@ccgf/tilemap
v0.1.0
Published
网格 / 等距 / 六边形地图拓扑:坐标、邻居、距离、直线、圆环、投影(纯计算,不依赖引擎与框架)
Maintainers
Readme
@ccgf/tilemap
状态(2026-10-23):基础算法已完成;地图数据格式、关卡包、渲染、编辑器整体暂缓。 恢复前先读
docs/map-todo.md,不要在这里继续加产品级功能。
地图网格的纯算法库:方格 / 真等距(菱形)/ 六边形。
- 零
cc、零framework依赖 —— Node 里能直接单测,也能给工具/服务端复用 - 只算拓扑、坐标、邻居、距离、直线、圆环、投影;不碰渲染、节点、资源、可走性
- 坐标用普通数字 /
{x,y}/{q,r},不持有全局状态
import { SquareGrid, IsoProjection, HexGrid } from '@ccgf/tilemap';方格
const grid = new SquareGrid(20, 20);
const i = grid.index(5, 5); // y * width + x
const nb4 = grid.neighbors(i); // 4 邻居
const nb8 = grid.neighbors(i, [], true); // 8 邻居
const area = grid.range(i, 2); // 曼哈顿范围
const line = grid.line(i, grid.index(10, 10));约定:(0,0) 在左下角,x 向右、y 向上(第一象限);索引仍是 index = y*width + x,只是第 0 行在最下面。本类不判断可走性。
真等距(菱形)
菱形地图的逻辑拓扑就是方格,只是投影不同 —— 所以寻路/范围直接复用 SquareGrid。
const iso = new IsoProjection({ tileWidth: 64, tileHeight: 32 });
const p = iso.toWorld(3, 5); // 格子中心(Cocos Y 向上)
const cell = iso.pick(p.x, p.y); // 点选,返回整数格
const idx = iso.pickIndex(grid, p.x, p.y); // 图内返回索引,图外 null
const depth = iso.sortKey(3, 5); // -(x+y),升序 = 先画后排、再画前排公式(origin 是 (0,0) 格心的世界坐标):
worldX = originX + (x - y) * tileWidth / 2
worldY = originY + (x + y) * tileHeight / 2(0,0) 在左下角;x 向右上、y 向左上;Y 向上为正。pick 不是对连续坐标 floor:每格是菱形,边界附近必须用菱形判定,库已经处理。
六边形
const hex = new HexGrid({
cols: 20,
rows: 20,
size: 32, // 外接圆半径(中心到顶点)
orientation: 'flat', // 平顶
offset: 'odd-q', // 平顶标准:按列错半格
});
const i = hex.index(5, 5);
const nb = hex.neighbors(i); // 6 个
const ring = hex.ring(i, 2);
const range = hex.range(i, 2);
const line = hex.line(i, hex.index(10, 8));
const world = hex.toWorld(i);
const picked = hex.fromWorld(world.x, world.y); // 图外 null
const corners = hex.corners(i); // 6 个顶点,画高亮用坐标同样是左下原点:index = row * cols + col,row 向上增大(第 0 行在最下面)。
平顶 vs 尖顶,以及“行错行”
flat(平顶):左右是尖角,上下是平边;标准错位是按列(odd-q/even-q)。pointy(尖顶):上下是尖角;标准错位是按行(odd-r/even-r)。
四种 offset 都已实现、可以互转,但要注意:
- “每行水平排列、奇数行错半格”的视觉,标准做法是 pointy + odd-r;
- 平顶六边形的邻居方向是 N / S + 四个斜向,没有正 E / W 邻居,所以它天然是“按列错位”。
如果你把平顶地图按
row索引(odd-r),数学上仍然正确(row只是存储坐标), 但那一行并不对应屏幕上的水平行。
内部一律用 axial (q, r) 做邻居/距离/直线/圆环;col/row 只用于矩形存储。
三种坐标都支持:
const a = hex.toAxial(col, row); // offset -> axial
const o = hex.toOffset(q, r); // axial -> offset
const cube = hex.cubeOf(index); // (x, y, z), x + y + z = 0边界
不做可走性/权重:可走性数据由使用方存(
Uint8Array就行)。寻路用
@ccgf/pathfinding的findPathOnGraph;HexGrid自带neighbors+heuristic, 结构上就是一张图:import { findPathOnGraph } from '@ccgf/pathfinding'; findPathOnGraph(hex, start, goal); // 无阻挡 // 有阻挡:包一层 isBlocked findPathOnGraph({ neighbors: (i, out) => hex.neighbors(i, out), contains: (i) => hex.contains(i), heuristic: (a, b) => hex.distance(a, b), isBlocked: (i) => blocked[i] === 1, }, start, goal);不做地图数据格式、渲染、相机、节点坐标转换。
不持有任何全局状态。
