Tilemap模块
脚本入口: eve.Map()
创建或载入 TileLayer,设置瓦片、投影、图层并提交渲染;可用 Pathfinder 做格子寻路与群体 Flow Field,用 Fov 做动态视野与探索记忆。
基本用法
对象关系与调用时机
Map 聚合 TileLayer 并统一更新/渲染;TileLayer 保存网格、投影、origin、层级和图集资源。JSON loader 把 Tiled 数据映射到这些对象。寻路在格子索引空间进行,与投影解耦;需要世界坐标时对路径点调用 tileToWorld*。
目标导向指南
载入 Tiled 地图
把 JSON 和图集放在游戏目录,用 newLayerFromFile(path) 创建层;初始化后设置 origin、layer 和 visible。每帧 map.update(dt),渲染时 map.render(gfx)。
产品内容应使用 loadFromFileWithObjectContract(path, contractJson)。它先在候选区解析地图,再按 eve.map.object-contract version 1 校验对象类型、唯一名称、自定义属性的必填性、类型、范围和枚举; 只有全部通过才替换当前图层与对象缓存。返回值是结构化 Result(ok/status/value),失败时当前可玩 场景保持不变。契约可以禁止未知对象类型和未知属性,从而在地图加载边界捕获拼写错误和不完整 portal:
契约属性规则支持 kind: string|int|number|bool、required、数值 min/max 与字符串 enum。 对象几何必须为有限数,宽高不得为负;默认要求对象名称非空且唯一。契约只负责通用结构准入,诸如 “朝向必须恰有一个非零分量”之类跨字段领域规则仍由项目在发布游戏状态前校验。
运行时修改瓦片
先用地图坐标换算接口把世界位置转成格子,再 setTile(x, y, gid);批量生成地图时先 resize,再填充,避免重复重建图层。0 通常表示空瓦片。
fillRect(x, y, width, height, gid) 会裁剪到地图边界,并把整次区域修改发布为一个 revision。绑定到图层的 Pathfinder 与 Fov 会在下一次查询或 compute() 时根据 revision 自动同步;通常不再需要手动调用 syncFromLayer()。
地图内部以 32×32 chunk 建立空间索引。带 Camera2D 的正常 map.render(gfx) 会先按视口剔除 chunk;可通过 map.getLastVisitedChunkCount()、map.getLastVisitedCellCount() 和现有的可见瓦片统计检查本帧工作量。
TileSet v2 数据、动画与 terrain
运行时可以逐帧建立动画,并为 GID 写入保留类型的自定义数据:
terrain rule 使用 8 位邻接掩码(从西北开始顺时针)。绘制一个 terrain 会重新解析目标及其一格邻域:
Tiled JSON 的 animation、typed properties、wangsets 与无限地图 chunks 可直接导入。地图可以引用多个外部 JSON .tsj 或 XML .tsx tileset;每个 atlas 按地图中的 firstgid 选择,图片路径相对 tileset 文件解析。外部 tileset 也会加入热重载依赖。无限地图当前会按已存在 chunk 的包围盒规范化为运行时图层,并把负 chunk 坐标折算进图层 origin。
Tile properties 中的 walkable、cost、enterMask、exitMask 会进入统一导航资料。方向位为 N=1, E=2, S=4, W=8;寻路同时检查源格的 exitMask 和目标格的反向 enterMask。没有声明时四向均允许。这样悬崖边、单向台阶和墙口不需要再维护一份独立的 Pathfinder 阻挡表。
组合项目自己的 2.5D 资产工作流
独立 PNG、特殊 pivot 或不规则 atlas 不要求采用引擎内置成品导入器。项目工作流只需生成 eve.tileset/1 manifest,运行时载入:
每个 GID 可声明 region、pivot、sortBias、footprint、walkable、cost 与项目自定义字段。规则 atlas GID 仍走原路径。参考阶段管线位于 tools/tile-pipeline/,可用项目 Python 插件替换任一步;详见 docs/dev/可组合2.5D-TileSet资产管线.md。
逻辑格尺寸和渲染间距相互独立:
间距同时用于正反坐标换算、拾取和深度排序,但不改变 GID、寻路邻接关系或移动成本。JSON 配置可使用 "renderSpacing":[1.12,1.12] 或 "cellGap":[8,4]。
需要互相产生 2.5D 遮挡的地面、角色和建筑应使用相同的 layer,使统一队列按脚点深度排序。layer 是 HUD、前景遮罩等用途的硬排序屏障;同格内的细微顺序使用 TileSet sortBias。
单体寻路(A*)
正交/等距默认四向;setDiagonal(true) 后 auto 升为八向。交错/六角地图 auto 为 hex。
群体寻路(同目标 Flow Field)
多单位前往同一格时,建一次势场再各自跟随,避免每人跑一遍 A*:
自定义网格(不绑 TileLayer):map.newPathfinderSize(w, h),再用 setBlocked / setCellCost。
动态视野(FOV / 战争迷雾)
格子可见性与探索记忆;遮挡(opaque)与寻路可行走(walkable)分开配置。默认算法为 recursive shadowcasting;可选 raycast / permissive / rectangle。模式:grid2d(默认)、heightmap、volume。拓扑:ortho / hex。
自定义网格:map.newFovSize(w, h) + setOpaque。移动观察者后再次 compute();无变更时 isDirty() 为 false,compute 会跳过。离开视野的格子保留 explored,可用 clearMemory() 清空。
高度场:
体素 3D:
Dual Grid(双网格)
Tiled **没有**原生 dual-grid;在编辑器里画逻辑填充层,运行时解算显示层。支持正交 / 等距 / 交错 / 六角:掩码按格子索引采样,显示层继承投影参数并施加对应半步 origin 偏移。
resolveDualGridFilled(logic, display, filledGid) 只把指定 GID 当作填充。逻辑层可继续用于碰撞 / 寻路;默认会 setVisible(false)。
碰撞几何
publishCollision(layer) 会把 setTileMetadata(..., walkable=false) 标记的正交瓦片贪心合并成世界坐标矩形,减少静态碰撞体数量;已注册的物理/项目适配器会通过 ITileCollisionSink 一次性收到替换后的几何。没有适配器时仍可读取矩形,自行创建物理夹具:
setTileNavigationProfile(gid, walkable, cost, enterMask, exitMask, opaque, semanticFlags) 是同行性、碰撞与视野遮挡的统一画像。Pathfinder/Flow Field 使用 walkable、cost 与四向 enter/exit mask,publishCollision 使用不可通行状态或 Tiled tile object collision,Fov 使用 opaque;三者随同一 tile revision 自动失效,避免分别维护“可走”和“墙体”两套事实。
生产级自动贴图
逻辑 terrain grid 是权威数据,GID 只是派生显示结果。先定义 family 与精确 8 邻域规则,再由 point/rectangle/fill/erase 操作只重算 dirty region 外扩一格:
同一 mask 可配置多个带权变体;选择由 family seed、terrain 与坐标确定,不依赖时间或容器遍历 顺序。wall 解析四个正交邻居,waterfall 解析上下连续性,因此可以稳定表达墙顶/墙身/墙脚 以及瀑布口/循环水体/水花脚;动画仍使用 addTileAnimationFrame。完整的无素材示例位于 examples/autotile-production。
Tiled 与 RPG Maker MV/MZ
Tiled JSON/TMJ 支持 embedded tileset、外部 TSJ/TSX、多 tileset、无限 chunk、嵌套 group、 typed properties、animation、Wang connectivity、水平/垂直/对角 transform flags,以及 tile objectgroup 的矩形/多边形包围盒碰撞。外部引用相对 map/tileset 文件解析并参与 hot reload。 导入失败会恢复 Config、Tiles、Tileset、Draw 与 Resource 的旧快照,不留下半更新状态。
C++ 可直接导入 RPG Maker 工程,无需启动 RPG Maker:
适配器读取 A1-A5/B-E sheet、四个 tile plane 与 shadow plane,按 MV/MZ 官方 quarter-tile table 解码 A1 水面/瀑布动画、A2 地面、A3 屋顶/墙、A4 墙顶/墙身。navigationLayer 把 passage、四方向 passage、star overlay、ladder、bush、counter、damage floor 与 terrain tag 合成为单一隐藏画像;源文件不会被修改,Resource.sourceEngine/sourceVersion 会记录来源。
当前自动合并只支持正交层;等距、交错和六角层返回 0,项目应使用多边形适配器,避免把菱形误近似成轴对齐矩形。
常见问题
- GID 与图集编号混淆:0 为空,其余值遵循 tileset 映射;默认空瓦片不可走(
setBlockEmpty)。 - 世界坐标直接作为 tile 索引:先做投影换算。
- 修改 JSON 后未启用 watch/autoReload。
- 期望 Tiled 直接导出 dual-grid 显示层:不支持;用逻辑层 +
resolveDualGrid。 - 寻路失败:
getLength()==0(越界、不可走或不可达),不是抛异常。
API 快查
下列方法名来自当前 Squirrel 绑定;同一模块创建的辅助对象(例如 World、Body、Source)的方法也列在这里。
applyConfig()、clear()、depthYAt()、fill()、getAutoReload()、getConfigPath()、getLayer()、getLayerCount()getMapHeight()、getMapWidth()、getName()、getObjectCount()、getObjectGid()、getObjectHeight()、getObjectName()、getObjectType()findObjectByName(name):返回第一个同名对象的临时索引;不存在返回-1。findObjectAt(x, y, type):返回包含该点的第一个对象;空type接受任意类型,点对象要求坐标精确匹配,不存在返回-1。getLastVisibleTileCount()、getLastCustomVisualCount()、getLastAtlasCount()publishCollision()、getCollisionRectCount()、getCollisionRectX()、getCollisionRectY()、getCollisionRectWidth()、getCollisionRectHeight()getObjectWidth()、getObjectX()、getObjectY()、getTile()、getTileHeight()、getTileWidth()、getTilesetColumns()、getTilesetFirstGid()getTilesetTexture()、getX()、getY()、isVisible()、loadConfig()、loadFromFile()、newLayer()、newLayerFromFile()newPathfinder()、newPathfinderSize()、newFov()、newFovSize()、newFovVolume()pollConfigs()、reloadConfig()、render()、resize()、resolveDualGrid()、resolveDualGridFilled()、setAutoReload()、setCamera()、setCanvas()、setLayer()setOrigin()、setTile()、setTileSize()、setTileset()、setTilesetTileSize()、setTileVisual()、setVisualScale()、getVisualScaleX()、getVisualScaleY()、setTileMetadata()、clearTileVisuals()、getTileVisualCount()、loadTilesetManifest()、setTint()、setVisible()、setReceiveLight()、getReceiveLight()、tileToWorldX()tileToWorldY()、update()、worldToTileX()、worldToTileY()、dualGridFrame()、dualGridMaskAt()、dualGridOffsetX()、dualGridOffsetY()、lastDualGridError()
Pathfinder:setTopology、getTopology、setDiagonal、blockGid、unblockGid、clearBlockedGids、setBlockEmpty、setBlocked、isWalkable、setCellCost、getCellCost、syncFromLayer、findPath、buildFlowField、followFlow、findGroupPath、invalidateCache
Path:getLength、getX、getY、getTotalCost
FlowField:getWidth、getHeight、getGoalX、getGoalY、costAt、nextX、nextY、isReachable
Fov:getWidth、getHeight、getDepth、setMode、getMode、setAlgorithm、getAlgorithm、setRadiusMetric、getRadiusMetric、setTopology、getTopology、setCornerPeek、blockOpaqueGid、unblockOpaqueGid、clearOpaqueGids、setBlockEmpty、setOpaque、isOpaque、setOpaque3、isOpaque3、syncFromLayer、setElevation、getElevation、setCliffBlock、setEyeOffset、setVerticalRange、addRevealer、addRevealer3、removeRevealer、clearRevealers、setRevealerPosition、setRevealerPosition3、setRevealerRadius、setRevealerFacing、clearRevealerFacing、setRevealerEnabled、getRevealerCount、setRevealerPerception、getRevealerPerception、setPerceptionRadiusScale、setDetectionMargin、getEffectiveRadius、canDetect、canDetect3、markDirty、isDirty、compute、isVisible、isExplored、isVisible3、isExplored3、getState、getState3、clearMemory、resetVisibleOnly、getMaskValue、getMaskByte、getMaskValue3、getMaskByte3、buildMaskTexture、buildMaskTextureSlice
使用要点
- 模块对象和它创建的资源对象应保存在全局或实体状态中,不要在每帧重复创建。
- 对象索引只在当前对象缓存内有效;地图加载、热重载或
setObjects后应按稳定名称重新查询,不能把索引写入存档。 - Tiled object 的
properties会按名称排序并投影为 owning UTF-8 文本,可用getObjectPropertyCount/getObjectPropertyName/hasObjectProperty/getObjectProperty(index, name, defaultValue)查询。数值和布尔值由玩法边界按自己的 schema 再解析与校验; 热重载后同样必须重新按对象名查询,不能保存属性索引。 newLayerFromFile/loadFromFile采用事务式场景替换:加载失败保留当前图层和对象缓存; 成功后清空并隐藏被替换图层,再发布新图层与对象缓存。这使传送门和场景切换不会因坏资源把当前场景清空。- 带
update(dt)的系统应在eve_update调用;绘制方法应在eve_render调用。 - 参数约束、默认值和返回类型以对应模块头文件及
addFunc绑定为准;本文 API 快查与当前源码同步生成。
源码: src/modules/map/ 设计: `docs/dev/寻路系统设计.md`、`docs/dev/动态视野系统设计.md` 相关测试: test/map.cpp、test/map_path.cpp、test/map_fov.cpp、test/hex_level_simulation.cpp、test/hex_level_data.cpp 示例: examples/hex-levels/
GID 与混合地形编辑
setTile、fillRect、fill 保留完整 32 位 GID。高位携带 Tiled 翻转标志时,C++ int 可能为负;使用 0 擦除,不要把负值当作空格。
paintTerrain / paintTerrainRect 解析邻域时保留没有逻辑地形归属的普通 tile。eraseTerrainRect 只清空指定矩形并重新解析附近地形,不清空矩形外的普通装饰。
编辑文档的格式支持与运行时 importer 不同,见 Tilemap 编辑文档与格式读写。