import * as Phaser from "phaser"; /** * 开发调试覆盖层 * 在游戏场景上叠加可视化调试信息 */ export class DebugOverlay { private scene: any; private graphics!: Phaser.GameObjects.Graphics; private texts: Phaser.GameObjects.Text[] = []; private fpsText!: Phaser.GameObjects.Text; private visible = true; constructor(scene: any) { this.scene = scene; this.create(); } private create(): void { const scene = this.scene; // FPS 文本 this.fpsText = scene.add .text(10, 10, "FPS: 0", { fontSize: "14px", color: "#00ff00", backgroundColor: "#00000088", padding: { x: 4, y: 2 }, }) .setScrollFactor(0) .setDepth(9000); // 调试图形层 this.graphics = scene.add.graphics(); this.graphics.setDepth(8999); scene.boardContainer.add(this.graphics); // 绘制初始调试信息 this.drawDebugInfo(); // 每帧更新 FPS scene.events.on("update", () => { this.fpsText.setText(`FPS: ${scene.game.loop.actualFps.toFixed(0)}`); }); // 按 D 键切换显示/隐藏 scene.input.keyboard?.on("keydown-D", () => { this.visible = !this.visible; this.graphics.setVisible(this.visible); this.texts.forEach(t => t.setVisible(this.visible)); this.fpsText.setVisible(this.visible); }); } private drawDebugInfo(): void { const scene = this.scene; const level = scene.level; if (!level) return; const g = this.graphics; g.clear(); // 1. 格子网格线 g.lineStyle(1, 0x444444, 0.3); for (let row = 0; row <= level.rows; row++) { const y = row * scene.cellHeight; g.lineBetween(0, y, level.cols * scene.cellWidth, y); } for (let col = 0; col <= level.cols; col++) { const x = col * scene.cellWidth; g.lineBetween(x, 0, x, level.rows * scene.cellHeight); } // 2. 格子坐标文字 + 碰撞区域 for (let row = 0; row < level.rows; row++) { for (let col = 0; col < level.cols; col++) { const cx = col * scene.cellWidth + scene.cellWidth / 2; const cy = row * scene.cellHeight + scene.cellHeight / 2; // 坐标文字 const coordText = scene.add .text(cx, cy, `${col},${row}`, { fontSize: "10px", color: "#888888", }) .setOrigin(0.5) .setDepth(8998); scene.boardContainer.add(coordText); this.texts.push(coordText); // 碰撞区域高亮 const idx = row * level.cols + col; const occupied = level.paths.some((p: any, i: number) => { if (scene.removedPaths.has(i)) return false; return p.indices.includes(idx); }); if (occupied) { g.fillStyle(0xff0000, 0.1); g.fillRect( col * scene.cellWidth + 2, row * scene.cellHeight + 2, scene.cellWidth - 4, scene.cellHeight - 4, ); } } } // 3. 路径索引 + 命中范围 + 方向向量 for (let i = 0; i < level.paths.length; i++) { if (scene.removedPaths.has(i)) continue; const path = level.paths[i]; const hx = path.head.x * scene.cellWidth + scene.cellWidth / 2; const hy = path.head.y * scene.cellHeight + scene.cellHeight / 2; // 路径编号 const idxText = scene.add .text(hx, hy - scene.cellHeight * 0.4, `#${i}`, { fontSize: "12px", color: "#ffff00", fontStyle: "bold", backgroundColor: "#00000088", padding: { x: 2, y: 1 }, }) .setOrigin(0.5) .setDepth(9001); scene.boardContainer.add(idxText); this.texts.push(idxText); // 命中判定圆 const hitRadius = scene.cellSize * 0.6; g.lineStyle(1, 0x00ff00, 0.5); g.strokeCircle(hx, hy, hitRadius); // 方向辅助线 const dx = path.direction === "right" ? 1 : path.direction === "left" ? -1 : 0; const dy = path.direction === "down" ? 1 : path.direction === "up" ? -1 : 0; const lineLen = Math.max(level.cols, level.rows) * scene.cellSize; g.lineStyle(1, 0x00ffff, 0.4); g.lineBetween(hx, hy, hx + dx * lineLen, hy + dy * lineLen); } } }