feat(pathfinding): 支持从不可行走位置开始寻路
改进寻路系统,允许玩家从不可行走的当前位置开始寻路到可行走区域。 当玩家位于不可行走位置时,系统会自动寻找最近的可行走位置作为起点, 并临时将起点设置为可行走状态以启动A*算法。 主要变更: - AStarPathfinding: 临时修改起点可行走状态以支持算法启动 - PlayerController: 检测玩家当前位置并自动传送到最近可行走点 - TiledMapPathfinder: 在寻路前验证起点并寻找替代位置
This commit is contained in:
@@ -65,11 +65,15 @@ export class AStarPathfinding extends Component {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.grid[startX][startY].walkable || !this.grid[targetX][targetY].walkable) {
|
// 检查终点是否可行走
|
||||||
console.warn('起点或终点不可行走');
|
if (!this.grid[targetX][targetY].walkable) {
|
||||||
|
console.warn('终点不可行走');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 注意:起点可能不可行走,我们在TiledMapPathfinder中已经处理了这种情况
|
||||||
|
// 这里不再检查起点是否可行走,允许从不可行走的起点开始寻路
|
||||||
|
|
||||||
if (startX === targetX && startY === targetY) {
|
if (startX === targetX && startY === targetY) {
|
||||||
return [new Vec2(startX, startY)];
|
return [new Vec2(startX, startY)];
|
||||||
}
|
}
|
||||||
@@ -80,6 +84,10 @@ export class AStarPathfinding extends Component {
|
|||||||
const startNode = this.grid[startX][startY];
|
const startNode = this.grid[startX][startY];
|
||||||
const targetNode = this.grid[targetX][targetY];
|
const targetNode = this.grid[targetX][targetY];
|
||||||
|
|
||||||
|
// 临时将起点设置为可行走,以便算法能够开始
|
||||||
|
const originalStartWalkable = startNode.walkable;
|
||||||
|
startNode.walkable = true;
|
||||||
|
|
||||||
const openSet: PathNode[] = [];
|
const openSet: PathNode[] = [];
|
||||||
const closedSet: PathNode[] = [];
|
const closedSet: PathNode[] = [];
|
||||||
|
|
||||||
@@ -101,12 +109,16 @@ export class AStarPathfinding extends Component {
|
|||||||
|
|
||||||
// 如果到达目标节点,重建路径
|
// 如果到达目标节点,重建路径
|
||||||
if (currentNode === targetNode) {
|
if (currentNode === targetNode) {
|
||||||
|
// 恢复起点的原始可行走状态
|
||||||
|
startNode.walkable = originalStartWalkable;
|
||||||
return this.retracePath(startNode, targetNode);
|
return this.retracePath(startNode, targetNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查相邻节点
|
// 检查相邻节点
|
||||||
const neighbors = this.getNeighbors(currentNode);
|
const neighbors = this.getNeighbors(currentNode);
|
||||||
for (const neighbor of neighbors) {
|
for (const neighbor of neighbors) {
|
||||||
|
// 如果当前节点不可行走,我们仍然允许它连接到可行走的相邻节点
|
||||||
|
// 这样可以从不可行走的起点移动到可行走的区域
|
||||||
if (!neighbor.walkable || closedSet.indexOf(neighbor) !== -1) {
|
if (!neighbor.walkable || closedSet.indexOf(neighbor) !== -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -126,6 +138,9 @@ export class AStarPathfinding extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 恢复起点的原始可行走状态
|
||||||
|
startNode.walkable = originalStartWalkable;
|
||||||
|
|
||||||
// 没有找到路径
|
// 没有找到路径
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,8 +238,23 @@ export class PlayerController extends Component {
|
|||||||
clampedPos.set(closestWalkable);
|
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);
|
this.currentPath = this.pathfinder.findPath(startPos, clampedPos);
|
||||||
|
|
||||||
if (this.currentPath.length === 0) {
|
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);
|
const targetTilePos = this.worldToTileCoordinate(targetWorldPos);
|
||||||
|
|
||||||
console.log(`寻路: 起点瓦片坐标(${startTilePos.x}, ${startTilePos.y}) -> 终点瓦片坐标(${targetTilePos.x}, ${targetTilePos.y})`);
|
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*算法寻找路径
|
// 使用A*算法寻找路径
|
||||||
const tilePath = this.pathfinding.findPath(
|
const tilePath = this.pathfinding.findPath(
|
||||||
startTilePos.x, startTilePos.y,
|
startTilePos.x, startTilePos.y,
|
||||||
|
|||||||
Reference in New Issue
Block a user