From 972334f786868c72d4a91b7a32993a65943c6ef5 Mon Sep 17 00:00:00 2001 From: richarjiang Date: Mon, 20 Oct 2025 09:23:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(pathfinding):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BB=8E=E4=B8=8D=E5=8F=AF=E8=A1=8C=E8=B5=B0=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E5=BC=80=E5=A7=8B=E5=AF=BB=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进寻路系统,允许玩家从不可行走的当前位置开始寻路到可行走区域。 当玩家位于不可行走位置时,系统会自动寻找最近的可行走位置作为起点, 并临时将起点设置为可行走状态以启动A*算法。 主要变更: - AStarPathfinding: 临时修改起点可行走状态以支持算法启动 - PlayerController: 检测玩家当前位置并自动传送到最近可行走点 - TiledMapPathfinder: 在寻路前验证起点并寻找替代位置 --- assets/scripts/AStarPathfinding.ts | 19 +++++++++++++++++-- assets/scripts/PlayerController.ts | 17 ++++++++++++++++- assets/scripts/TiledMapPathfinder.ts | 14 +++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/assets/scripts/AStarPathfinding.ts b/assets/scripts/AStarPathfinding.ts index fd79a05..d6ca292 100644 --- a/assets/scripts/AStarPathfinding.ts +++ b/assets/scripts/AStarPathfinding.ts @@ -65,11 +65,15 @@ export class AStarPathfinding extends Component { return []; } - if (!this.grid[startX][startY].walkable || !this.grid[targetX][targetY].walkable) { - console.warn('起点或终点不可行走'); + // 检查终点是否可行走 + if (!this.grid[targetX][targetY].walkable) { + console.warn('终点不可行走'); return []; } + // 注意:起点可能不可行走,我们在TiledMapPathfinder中已经处理了这种情况 + // 这里不再检查起点是否可行走,允许从不可行走的起点开始寻路 + if (startX === targetX && startY === targetY) { return [new Vec2(startX, startY)]; } @@ -80,6 +84,10 @@ export class AStarPathfinding extends Component { const startNode = this.grid[startX][startY]; const targetNode = this.grid[targetX][targetY]; + // 临时将起点设置为可行走,以便算法能够开始 + const originalStartWalkable = startNode.walkable; + startNode.walkable = true; + const openSet: PathNode[] = []; const closedSet: PathNode[] = []; @@ -101,12 +109,16 @@ export class AStarPathfinding extends Component { // 如果到达目标节点,重建路径 if (currentNode === targetNode) { + // 恢复起点的原始可行走状态 + startNode.walkable = originalStartWalkable; return this.retracePath(startNode, targetNode); } // 检查相邻节点 const neighbors = this.getNeighbors(currentNode); for (const neighbor of neighbors) { + // 如果当前节点不可行走,我们仍然允许它连接到可行走的相邻节点 + // 这样可以从不可行走的起点移动到可行走的区域 if (!neighbor.walkable || closedSet.indexOf(neighbor) !== -1) { continue; } @@ -126,6 +138,9 @@ export class AStarPathfinding extends Component { } } + // 恢复起点的原始可行走状态 + startNode.walkable = originalStartWalkable; + // 没有找到路径 return []; } diff --git a/assets/scripts/PlayerController.ts b/assets/scripts/PlayerController.ts index e536d6b..9da1542 100644 --- a/assets/scripts/PlayerController.ts +++ b/assets/scripts/PlayerController.ts @@ -238,8 +238,23 @@ export class PlayerController extends Component { clampedPos.set(closestWalkable); } + // 检查玩家当前位置是否可行走 + let startPos = this.player.position; + if (!this.pathfinder.isWorldPositionWalkable(startPos)) { + console.log('玩家当前位置不可行走,寻找最近的可行走位置作为起点'); + const closestPlayerWalkable = this.pathfinder.getClosestWalkablePosition(startPos); + if (!closestPlayerWalkable) { + console.warn('找不到玩家附近的可行走位置'); + return; + } + startPos = closestPlayerWalkable; + console.log(`将玩家移动到最近的可行走位置: (${startPos.x.toFixed(2)}, ${startPos.y.toFixed(2)})`); + + // 直接将玩家传送到最近的可行走位置 + this.player.setPosition(startPos); + } + // 使用寻路算法计算路径 - const startPos = this.player.position; this.currentPath = this.pathfinder.findPath(startPos, clampedPos); if (this.currentPath.length === 0) { diff --git a/assets/scripts/TiledMapPathfinder.ts b/assets/scripts/TiledMapPathfinder.ts index 86894cd..8f6cfd6 100644 --- a/assets/scripts/TiledMapPathfinder.ts +++ b/assets/scripts/TiledMapPathfinder.ts @@ -111,11 +111,23 @@ export class TiledMapPathfinder extends Component { } // 将世界坐标转换为瓦片坐标 - const startTilePos = this.worldToTileCoordinate(startWorldPos); + let startTilePos = this.worldToTileCoordinate(startWorldPos); const targetTilePos = this.worldToTileCoordinate(targetWorldPos); console.log(`寻路: 起点瓦片坐标(${startTilePos.x}, ${startTilePos.y}) -> 终点瓦片坐标(${targetTilePos.x}, ${targetTilePos.y})`); + // 检查起点是否可行走,如果不可行走则寻找最近的可行走位置 + if (!this.pathfinding.isWalkable(startTilePos.x, startTilePos.y)) { + console.log('起点不可行走,寻找最近的可行走位置'); + const closestWalkableWorldPos = this.getClosestWalkablePosition(startWorldPos); + if (!closestWalkableWorldPos) { + console.warn('找不到起点附近的可行走位置'); + return []; + } + startTilePos = this.worldToTileCoordinate(closestWalkableWorldPos); + console.log(`使用新的起点瓦片坐标(${startTilePos.x}, ${startTilePos.y})`); + } + // 使用A*算法寻找路径 const tilePath = this.pathfinding.findPath( startTilePos.x, startTilePos.y,