import { _decorator, Component, Node, TiledMap, TiledLayer, Vec2, Vec3, Size } from 'cc'; import { AStarPathfinding } from './AStarPathfinding'; const { ccclass, property } = _decorator; @ccclass('TiledMapPathfinder') export class TiledMapPathfinder extends Component { @property(TiledMap) tiledMap: TiledMap | null = null; @property({ displayName: '可行走图层名称' }) walkableLayerName: string = 'WalkableLayer'; @property({ displayName: '瓦片尺寸' }) tileSize: number = 32; private pathfinding: AStarPathfinding | null = null; private mapSize: Size = new Size(0, 0); private walkableData: number[][] = []; onLoad() { // 获取或创建寻路组件 this.pathfinding = this.getComponent(AStarPathfinding); if (!this.pathfinding) { this.pathfinding = this.addComponent(AStarPathfinding); } } start() { if (this.tiledMap) { this.initializePathfinding(); } else { console.error('TiledMapPathfinder: TiledMap组件未设置'); } } /** * 初始化寻路系统 */ private initializePathfinding() { if (!this.tiledMap) { console.error('TiledMap未设置'); return; } // 获取地图尺寸 this.mapSize = this.tiledMap.getMapSize(); console.log(`地图尺寸: ${this.mapSize.width}x${this.mapSize.height}`); // 获取可行走图层 const walkableLayer = this.tiledMap.getLayer(this.walkableLayerName); if (!walkableLayer) { console.error(`找不到图层: ${this.walkableLayerName}`); return; } // 读取可行走数据 this.extractWalkableData(walkableLayer); // 初始化A*寻路算法 if (this.pathfinding) { this.pathfinding.initializeGrid(this.mapSize.width, this.mapSize.height, this.walkableData); console.log('寻路系统初始化完成'); } } /** * 从TiledLayer提取可行走数据 */ private extractWalkableData(layer: TiledLayer) { this.walkableData = []; for (let y = 0; y < this.mapSize.height; y++) { this.walkableData[y] = []; for (let x = 0; x < this.mapSize.width; x++) { // 获取指定位置的瓦片GID const gid = layer.getTileGIDAt(x, y); // GID > 0 表示有瓦片,表示可行走 // GID = 0 表示没有瓦片,表示不可行走 this.walkableData[y][x] = gid > 0 ? 1 : 0; } } console.log('可行走数据提取完成'); this.debugPrintWalkableData(); } /** * 调试打印可行走数据(仅打印部分数据以避免日志过长) */ private debugPrintWalkableData() { console.log('可行走数据示例(前10行):'); for (let y = 0; y < Math.min(10, this.walkableData.length); y++) { const row = this.walkableData[y].slice(0, Math.min(10, this.walkableData[y].length)); console.log(`第${y}行: [${row.join(', ')}]`); } } /** * 寻找路径 * @param startWorldPos 起点世界坐标 * @param targetWorldPos 终点世界坐标 * @returns 路径的世界坐标数组 */ findPath(startWorldPos: Vec3, targetWorldPos: Vec3): Vec3[] { if (!this.pathfinding || !this.tiledMap) { console.warn('寻路系统未初始化'); return []; } // 将世界坐标转换为瓦片坐标 const startTilePos = this.worldToTileCoordinate(startWorldPos); const targetTilePos = this.worldToTileCoordinate(targetWorldPos); console.log(`寻路: 起点瓦片坐标(${startTilePos.x}, ${startTilePos.y}) -> 终点瓦片坐标(${targetTilePos.x}, ${targetTilePos.y})`); // 使用A*算法寻找路径 const tilePath = this.pathfinding.findPath( startTilePos.x, startTilePos.y, targetTilePos.x, targetTilePos.y ); if (tilePath.length === 0) { console.warn('未找到路径'); return []; } // 将瓦片坐标路径转换为世界坐标路径 const worldPath: Vec3[] = []; for (const tilePos of tilePath) { const worldPos = this.tileToWorldCoordinate(tilePos); worldPath.push(worldPos); } console.log(`找到路径,包含${worldPath.length}个点`); return worldPath; } /** * 世界坐标转换为瓦片坐标 */ private worldToTileCoordinate(worldPos: Vec3): Vec2 { if (!this.tiledMap) { return new Vec2(0, 0); } // 获取地图节点的位置偏移 const mapNode = this.tiledMap.node; const mapPosition = mapNode.position; // 计算相对于地图的坐标 const relativeX = worldPos.x - mapPosition.x; const relativeY = worldPos.y - mapPosition.y; // 获取地图尺寸信息 const mapSize = this.tiledMap.getMapSize(); const tileSize = this.tiledMap.getTileSize(); // 计算瓦片坐标 // 注意:Cocos Creator的Y轴向上为正,但瓦片地图的Y轴向下为正 const tileX = Math.floor((relativeX + mapSize.width * tileSize.width * 0.5) / tileSize.width); const tileY = Math.floor((mapSize.height * tileSize.height * 0.5 - relativeY) / tileSize.height); // 确保坐标在地图范围内 const clampedX = Math.max(0, Math.min(mapSize.width - 1, tileX)); const clampedY = Math.max(0, Math.min(mapSize.height - 1, tileY)); return new Vec2(clampedX, clampedY); } /** * 瓦片坐标转换为世界坐标 */ private tileToWorldCoordinate(tilePos: Vec2): Vec3 { if (!this.tiledMap) { return new Vec3(0, 0, 0); } // 获取地图节点的位置偏移 const mapNode = this.tiledMap.node; const mapPosition = mapNode.position; // 获取地图尺寸信息 const mapSize = this.tiledMap.getMapSize(); const tileSize = this.tiledMap.getTileSize(); // 计算世界坐标(瓦片中心点) const worldX = (tilePos.x + 0.5) * tileSize.width - mapSize.width * tileSize.width * 0.5 + mapPosition.x; const worldY = mapSize.height * tileSize.height * 0.5 - (tilePos.y + 0.5) * tileSize.height + mapPosition.y; return new Vec3(worldX, worldY, 0); } /** * 检查指定世界坐标是否可行走 */ isWorldPositionWalkable(worldPos: Vec3): boolean { if (!this.pathfinding) { return false; } const tilePos = this.worldToTileCoordinate(worldPos); return this.pathfinding.isWalkable(tilePos.x, tilePos.y); } /** * 获取最近的可行走位置 */ getClosestWalkablePosition(worldPos: Vec3, maxSearchRadius: number = 5): Vec3 | null { const centerTilePos = this.worldToTileCoordinate(worldPos); // 螺旋搜索最近的可行走位置 for (let radius = 0; radius <= maxSearchRadius; radius++) { for (let x = -radius; x <= radius; x++) { for (let y = -radius; y <= radius; y++) { // 只检查当前半径边界上的点 if (Math.abs(x) !== radius && Math.abs(y) !== radius && radius > 0) { continue; } const checkX = centerTilePos.x + x; const checkY = centerTilePos.y + y; if (this.pathfinding && this.pathfinding.isWalkable(checkX, checkY)) { return this.tileToWorldCoordinate(new Vec2(checkX, checkY)); } } } } return null; } /** * 获取地图信息 */ getMapInfo() { if (!this.tiledMap) { return null; } return { mapSize: this.tiledMap.getMapSize(), tileSize: this.tiledMap.getTileSize(), orientation: this.tiledMap.getMapOrientation() }; } }