import { Layers, Node, Sprite, UITransform, Vec3 } from 'cc'; import { cellToWorldCenter, parseCellKey, tileNodeName } from '../core/GridCoords'; import { LevelConfig } from './LevelTypes'; import { setupLayerContainer } from './TileLayout'; const UI_LAYER = Layers.Enum.UI_2D; function ensureLayer(root: Node, name: 'Ground' | 'Border'): Node { let layer = root.getChildByName(name); if (!layer) { layer = new Node(name); layer.parent = root; layer.layer = UI_LAYER; } setupLayerContainer(layer); return layer; } function ensureTile(layer: Node, layerKind: 'ground' | 'border', x: number, y: number): Node { const nodeName = tileNodeName(layerKind, x, y); let node = layer.getChildByName(nodeName); if (!node) { node = new Node(nodeName); node.parent = layer; node.layer = UI_LAYER; node.addComponent(UITransform); node.addComponent(Sprite); } node.active = true; return node; } /** 按 levels-database.json 补齐 / 隐藏砖块节点(与关卡编辑器数据一致) */ export function syncTileNodesFromConfig(levelRoot: Node, config: LevelConfig): number { const ground = ensureLayer(levelRoot, 'Ground'); const border = ensureLayer(levelRoot, 'Border'); const wantGround = new Set(Object.keys(config.ground ?? {})); const wantBorder = new Set(Object.keys(config.border ?? {})); let n = 0; for (const key of wantGround) { const p = parseCellKey(key); if (!p) continue; ensureTile(ground, 'ground', p.x, p.y); n++; } for (const key of wantBorder) { const p = parseCellKey(key); if (!p) continue; ensureTile(border, 'border', p.x, p.y); n++; } for (const ch of ground.children) { const m = /^g_(-?\d+)_(-?\d+)$/.exec(ch.name); if (!m) continue; const key = `${m[1]},${m[2]}`; ch.active = wantGround.has(key); } for (const ch of border.children) { const m = /^b_(-?\d+)_(-?\d+)$/.exec(ch.name); if (!m) continue; const key = `${m[1]},${m[2]}`; ch.active = wantBorder.has(key); } return n; } /** 关卡包围盒中心(格子 pivot 落点),用于居中显示 */ export function computeLevelCenterOffset(config: LevelConfig): Vec3 { const keys = [ ...Object.keys(config.ground ?? {}), ...Object.keys(config.border ?? {}), ]; if (!keys.length) return new Vec3(0, 0, 0); let minX = Infinity; let maxX = -Infinity; let minY = Infinity; let maxY = -Infinity; for (const key of keys) { const p = parseCellKey(key); if (!p) continue; const w = cellToWorldCenter(new Vec3(p.x, p.y, 0)); minX = Math.min(minX, w.x); maxX = Math.max(maxX, w.x); minY = Math.min(minY, w.y); maxY = Math.max(maxY, w.y); } return new Vec3(-(minX + maxX) * 0.5, -(minY + maxY) * 0.5, 0); } export function centerLevelRoot(levelRoot: Node, config: LevelConfig) { const off = computeLevelCenterOffset(config); levelRoot.setPosition(off.x, off.y, 0); }