Complete Cocos Creator port with level bundles, themes, and tooling.
Adds level prefabs, theme assets, audio, extensions, and deployment scripts for the Unity WebGL migration. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
88
assets/scripts/core/GridCoords.ts
Normal file
88
assets/scripts/core/GridCoords.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { Vec3 } from 'cc';
|
||||
import { CELL_PIXEL } from './GridConstants';
|
||||
|
||||
/**
|
||||
* 与 Unity Grid 一致:CellLayout Isometric Z-as-Y,CellSize (1, 0.5, 1)。
|
||||
* 缩放后 halfW=CELL/2, halfH=CELL/4。
|
||||
*/
|
||||
const HALF_W = CELL_PIXEL * 0.5;
|
||||
const HALF_H = CELL_PIXEL * 0.25;
|
||||
|
||||
if (!Number.isFinite(HALF_W) || HALF_W <= 0) {
|
||||
console.error('[GridCoords] CELL_PIXEL 无效,请检查 GridConstants 模块加载');
|
||||
}
|
||||
|
||||
export function cellToWorld(cell: Vec3): Vec3 {
|
||||
const x = cell.x;
|
||||
const y = cell.y;
|
||||
return new Vec3((x - y) * HALF_W, (x + y) * HALF_H, 0);
|
||||
}
|
||||
|
||||
/** Unity Tilemap tileAnchor (0.5,0.5):精灵 pivot 对齐格子中心 */
|
||||
export function cellToWorldCenter(cell: Vec3): Vec3 {
|
||||
const w = cellToWorld(cell);
|
||||
return new Vec3(w.x, w.y + HALF_H, 0);
|
||||
}
|
||||
|
||||
export function worldToCell(world: Vec3): Vec3 {
|
||||
const cx = (world.y / HALF_H + world.x / HALF_W) * 0.5;
|
||||
const cy = (world.y / HALF_H - world.x / HALF_W) * 0.5;
|
||||
return new Vec3(Math.round(cx), Math.round(cy), 0);
|
||||
}
|
||||
|
||||
/** 输入为世界坐标下的格子中心(与 Tilemap tileAnchor 一致) */
|
||||
export function worldCenterToCell(world: Vec3): Vec3 {
|
||||
return worldToCell(new Vec3(world.x, world.y - HALF_H, world.z));
|
||||
}
|
||||
|
||||
/** 世界坐标吸附到最近格子中心 */
|
||||
export function snapWorldToCellCenter(world: Vec3, out?: Vec3): Vec3 {
|
||||
const cell = worldToCell(world);
|
||||
const snapped = cellToWorld(cell);
|
||||
if (out) {
|
||||
out.set(snapped);
|
||||
return out;
|
||||
}
|
||||
return snapped;
|
||||
}
|
||||
|
||||
export function formatCellKey(x: number, y: number): string {
|
||||
return `${x},${y}`;
|
||||
}
|
||||
|
||||
export function parseCellKey(key: string): { x: number; y: number } | null {
|
||||
const parts = key.split(',');
|
||||
if (parts.length !== 2) return null;
|
||||
const x = parseInt(parts[0], 10);
|
||||
const y = parseInt(parts[1], 10);
|
||||
if (Number.isNaN(x) || Number.isNaN(y)) return null;
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
/** 烘焙瓦片节点名 g_1_0 / b_-2_1 → 格子坐标 */
|
||||
export function parseTileNodeName(name: string | undefined | null): { layer: 'ground' | 'border'; x: number; y: number } | null {
|
||||
if (!name) return null;
|
||||
const m = name.match(/^([gb])_(-?\d+)_(-?\d+)$/);
|
||||
if (!m) return null;
|
||||
return {
|
||||
layer: m[1] === 'g' ? 'ground' : 'border',
|
||||
x: parseInt(m[2], 10),
|
||||
y: parseInt(m[3], 10),
|
||||
};
|
||||
}
|
||||
|
||||
export function tileNodeName(layer: 'ground' | 'border', x: number, y: number): string {
|
||||
const p = layer === 'ground' ? 'g' : 'b';
|
||||
return `${p}_${x}_${y}`;
|
||||
}
|
||||
|
||||
export function getHalfCellSize(): { halfW: number; halfH: number } {
|
||||
return { halfW: HALF_W, halfH: HALF_H };
|
||||
}
|
||||
|
||||
/** 等距绘制深度(连续值,移动插值用;与 compareIsoDrawOrder 配套) */
|
||||
export function isoDrawDepthFromWorld(world: Vec3): { x: number; y: number } {
|
||||
const cx = (world.y / HALF_H + world.x / HALF_W) * 0.5;
|
||||
const cy = (world.y / HALF_H - world.x / HALF_W) * 0.5;
|
||||
return { x: cx, y: cy };
|
||||
}
|
||||
Reference in New Issue
Block a user