import * as THREE from "three"; import { computeBoardLayout, type BoardLayoutParams, type BoardLayoutResult } from "./BoardLayoutMath"; /** * Three.js 3D 棋盘布局器 * 在 XZ 平面上布局棋盘,Y=0 为地面。 * * 坐标约定: * - X 向右(col 增大方向) * - Z 向下(row 增大方向)— 俯视时等价于屏幕"向下" * - Y 向上(物品高度) */ export interface BoardLayout3DResult { cellSize: number; // 格子世界单位大小 boardWidth: number; // 棋盘总宽度(世界单位) boardHeight: number; // 棋盘总高度/深度(世界单位) originX: number; // 棋盘左上角 X 世界坐标 originZ: number; // 棋盘左上角 Z 世界坐标 rows: number; cols: number; } export class BoardLayout3D { private layout!: BoardLayout3DResult; /** * 计算棋盘布局 * @param rows 行数 * @param cols 列数 * @param cellSize 格子大小(世界单位),默认 1.0 */ computeLayout(rows: number, cols: number, cellSize: number = 1.0): BoardLayout3DResult { const boardWidth = cols * cellSize; const boardHeight = rows * cellSize; // 以原点为棋盘中心 const originX = -boardWidth / 2; const originZ = -boardHeight / 2; this.layout = { cellSize, boardWidth, boardHeight, originX, originZ, rows, cols, }; return this.layout; } /** * 获取格子中心的世界坐标 * @param col 列号(0-indexed) * @param row 行号(0-indexed) * @returns 世界坐标 { x, y, z } */ getCellWorldPos(col: number, row: number): THREE.Vector3 { const { cellSize, originX, originZ } = this.layout; return new THREE.Vector3( originX + col * cellSize + cellSize / 2, 0, originZ + row * cellSize + cellSize / 2 ); } /** * 获取棋盘中心世界坐标 */ getBoardCenter(): THREE.Vector3 { return new THREE.Vector3(0, 0, 0); } /** * 世界坐标 → 格子坐标 * @returns { col, row } 或 null(如果超出棋盘范围) */ worldToCell(worldX: number, worldZ: number): { col: number; row: number } | null { const { cellSize, originX, originZ, rows, cols } = this.layout; const col = Math.floor((worldX - originX) / cellSize); const row = Math.floor((worldZ - originZ) / cellSize); if (col < 0 || col >= cols || row < 0 || row >= rows) { return null; } return { col, row }; } /** * 计算格子索引(row-major) */ cellToIndex(col: number, row: number): number { return row * this.layout.cols + col; } /** * 获取棋盘边界(用于确定哪些格子在边缘) */ isOnEdge(col: number, row: number): boolean { const { rows, cols } = this.layout; return col === 0 || col === cols - 1 || row === 0 || row === rows - 1; } /** * 计算从某格子到棋盘边缘的步数(沿指定方向) */ stepsToEdge(col: number, row: number, dx: number, dz: number): number { const { rows, cols } = this.layout; let steps = 0; let c = col + dx; let r = row + dz; while (c >= 0 && c < cols && r >= 0 && r < rows) { steps++; c += dx; r += dz; } return steps + 1; // +1 for exiting the board } /** 获取当前布局结果 */ getLayout(): BoardLayout3DResult { return this.layout; } }