feat(pathfinding): 支持从不可行走位置开始寻路
改进寻路系统,允许玩家从不可行走的当前位置开始寻路到可行走区域。 当玩家位于不可行走位置时,系统会自动寻找最近的可行走位置作为起点, 并临时将起点设置为可行走状态以启动A*算法。 主要变更: - AStarPathfinding: 临时修改起点可行走状态以支持算法启动 - PlayerController: 检测玩家当前位置并自动传送到最近可行走点 - TiledMapPathfinder: 在寻路前验证起点并寻找替代位置
This commit is contained in:
@@ -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 [];
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user