Files
EVEngine/docs/usr/modules/map.md
T
西风逍遥游andCursor Agent c0d9fe4a7d test(hex): 程序化六边形关卡套件(FOV / 光照 / 寻路 / 拾取 / 粒子) (#50)
* test(hex): add procedural hex dungeon levels for engine QA

Cross-module simulation levels exercise hex tilemap procgen, FOV,
2D lighting, spatial pickup + inventory, and particles. Includes a
playable examples/hex-levels demo with level select and a pipeline crawl.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* test(hex): expand levels 06–15 and fog-raid pipeline

Add Flow Field swarm, cell-cost detours, multi-revealer perception,
FoW mask/algorithms, camera pick, dual-grid, procgen variants,
QuadTree cull, multi-light, particle/stash transfer, and a fog-raid
pipeline. Update the playable hex-levels demo for levels 6–9.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* test(hex): add fixture JSON data and data-driven hex tests

Expand catalog/items/loot/seeds/perception fixtures, handcrafted maps,
and particle configs. Wire the hex-levels demo to load items and particle
JSON plus fixtures.nut loot tables. Register hex_level_data.cpp coverage.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* test(hex): fix data fixtures assertions for zeroerr and sparse gens

Avoid CHECK_EQ on bag->addItem (double-eval), and only enforce minWalkable
on dungeon.bsp in the seeds matrix smoke.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* feat(hex): boot each level from distinct catalog configs

Enrich catalog/fixtures with per-level FOV, light, cell-cost, and enable
flags. Wire examples/hex-levels to apply those boot settings on level
switch. Add hex.data.catalog.bootEachLevelDistinctConfig to verify each
catalog entry starts with its own applied configuration.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* docs(hex): note per-level boot configs in data README

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* test(hex): add levels 16–20 and extra data-driven coverage

Expand simulation with facing-cone FOV, flow+cell-cost, seed
reproducibility, corner peek, equipment equip, and torchEscort /
catalogRaid pipelines. Add fixture tests for perception gates, all loot
tables, enable-flag consistency, seed path samples, map markers,
defaults, equipment slots, and mist particles on dungeon.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* docs(hex): clarify expanded test coverage in README

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* test(hex): add levels 21–25 and broader fixture validation

Cover hex world↔tile roundtrip, FOV memory clear, findGroupPath,
multi-algo FOV smoke, blocked-cell sync, and costlyFogPickup pipeline.
Add data tests for loot/item referential integrity, feature tags,
particle schema, algorithm registration, ring-door path, categories,
detection margin, and door walkability.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* feat(hex): expand catalog to 31 levels (0–30) and playable cycle

Add levels 16–30 with distinct boot configs (facing cone, flow+cost,
maze/WFC/drunkard, mist particles, raid combo). Regenerate fixtures.nut
with LEVEL_IDS; main.nut cycles all catalog levels via N/B. Add
simulation cases 26–30 and catalog presence tests.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* fix(hex): harden level 02/17 against non-portable procgen paths

macOS CI failed hex.level.02.dynamicFov (empty path) and
hex.level.17.flowPlusCellCost (path length == 2) because spawn↔exit
layouts from DTL/std distributions differ across libstdc++ vs libc++.
Use handcrafted hex maps so FOV memory and flow+cost assertions are
platform-stable.

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-13 11:54:41 +08:00

8.4 KiB
Raw Blame History

Tilemap模块

脚本入口: eve.Map()

创建或载入 TileLayer,设置瓦片、投影、图层并提交渲染;可用 Pathfinder 做格子寻路与群体 Flow Field,用 Fov 做动态视野与探索记忆。

基本用法

local map = eve.Map();
local layer = map.newLayerFromFile("maps/level.json");
layer.setTile(2, 3, 7);
map.update(dt);
map.render(gfx);

对象关系与调用时机

Map 聚合 TileLayer 并统一更新/渲染;TileLayer 保存网格、投影、origin、层级和图集资源。JSON loader 把 Tiled 数据映射到这些对象。寻路在格子索引空间进行,与投影解耦;需要世界坐标时对路径点调用 tileToWorld*。

目标导向指南

载入 Tiled 地图

把 JSON 和图集放在游戏目录,用 newLayerFromFile(path) 创建层;初始化后设置 origin、layer 和 visible。每帧 map.update(dt),渲染时 map.render(gfx)。

运行时修改瓦片

先用地图坐标换算接口把世界位置转成格子,再 setTile(x, y, gid);批量生成地图时先 resize,再填充,避免重复重建图层。0 通常表示空瓦片。改瓦片后若已创建 Pathfinder,调用 syncFromLayer()。

单体寻路(A*)

local pf = map.newPathfinder(layer);
pf.setTopology("auto");   // ortho4 / ortho8 / hex;auto 按 orientation
pf.blockGid(1);           // 墙 GID
local path = pf.findPath(sx, sy, gx, gy);
if (path.getLength() > 0) {
    local x = path.getX(0);
    local y = path.getY(0);
}

正交/等距默认四向;setDiagonal(true) 后 auto 升为八向。交错/六角地图 auto 为 hex。

群体寻路(同目标 Flow Field)

多单位前往同一格时,建一次势场再各自跟随,避免每人跑一遍 A*:

local field = pf.buildFlowField(gx, gy);
local p1 = pf.followFlow(field, ax, ay);
local p2 = pf.findGroupPath(bx, by, gx, gy); // 内部复用缓存场
local nx = field.nextX(ax, ay);
local ny = field.nextY(ax, ay);

自定义网格(不绑 TileLayer):map.newPathfinderSize(w, h),再用 setBlocked / setCellCost。

动态视野(FOV / 战争迷雾)

格子可见性与探索记忆;遮挡(opaque)与寻路可行走(walkable)分开配置。默认算法为 recursive shadowcasting;可选 raycast / permissive / rectangle。模式:grid2d(默认)、heightmap、volume。拓扑:ortho / hex。

local fov = map.newFov(layer);
fov.setBlockEmpty(false);
fov.blockOpaqueGid(1);
fov.setRadiusMetric("chebyshev");
fov.setTopology("auto"); // 或 "hex"
local id = fov.addRevealer(sx, sy, 8);
// 软 RPG 挂钩:游戏自行读取 actor 属性后写入
fov.setRevealerPerception(id, actor.getFinalAttribute("perception"));
fov.setPerceptionRadiusScale(0.25);
fov.setDetectionMargin(0.0);
fov.compute();
if (fov.canDetect(id, tx, ty, targetStealth)) { /* 可见且感知足够 */ }
local tex = fov.buildMaskTexture(gfx); // RGBA8 FoW 遮罩,调用方拥有

自定义网格:map.newFovSize(w, h) + setOpaque。移动观察者后再次 compute();无变更时 isDirty() 为 false,compute 会跳过。离开视野的格子保留 explored,可用 clearMemory() 清空。

高度场:

fov.setMode("heightmap");
fov.setElevation(4, 1, 2.0);
fov.setCliffBlock(1.0);

体素 3D:

local fov3 = map.newFovVolume(32, 32, 8);
fov3.setOpaque3(4, 4, 2, true);
fov3.addRevealer3(4, 4, 1, 10);
fov3.setVerticalRange(4);
fov3.compute();
fov3.isVisible3(8, 4, 1);

Dual Grid(双网格)

Tiled 没有原生 dual-grid;在编辑器里画逻辑填充层,运行时解算显示层。支持正交 / 等距 / 交错 / 六角:掩码按格子索引采样,显示层继承投影参数并施加对应半步 origin 偏移。

local map = eve.Map();
local logic = map.newLayer(16, 12, 32, 32);
local display = map.newLayer(1, 1, 32, 32);
// display.setTileset(tex, 1, 4);  // 4×4 的 15-tile 图集
logic.setTile(3, 4, 1);
map.resolveDualGrid(logic, display);  // 半步偏移 + 15 片选瓦
// map.dualGridOffsetX(logic) / dualGridOffsetY(logic) 可查偏移量

resolveDualGridFilled(logic, display, filledGid) 只把指定 GID 当作填充。逻辑层可继续用于碰撞 / 寻路;默认会 setVisible(false)。

常见问题

  • 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()
  • 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()、setTint()、setVisible()、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

使用要点

  • 模块对象和它创建的资源对象应保存在全局或实体状态中,不要在每帧重复创建。
  • 带 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/