@esengine/pathfinding
Version:
寻路算法库,支持A*、广度优先等算法,适用于Cocos Creator、Laya等游戏引擎
110 lines (93 loc) • 3.15 kB
text/typescript
import { IVector2, Vector2Utils } from '../../../Types/IVector2';
import { IUnweightedGraph } from './IUnweightedGraph';
/**
* 广度优先搜索算法实现
* 适用于无权图,保证找到最短路径(步数最少)
*/
export class BreadthFirstPathfinder {
/**
* 使用广度优先搜索算法搜索路径
* @param graph 图对象
* @param start 起始节点
* @param goal 目标节点
* @param cameFrom 可选的路径记录Map
* @returns 是否找到路径
*/
static search<T extends IVector2>(
graph: IUnweightedGraph<T>,
start: T,
goal: T,
cameFrom?: Map<number, T>
): boolean {
const frontier: T[] = [];
const visited = new Set<number>();
const pathMap = cameFrom || new Map<number, T>();
const startHash = Vector2Utils.toHash(start);
const goalHash = Vector2Utils.toHash(goal);
if (startHash === goalHash) {
return true;
}
frontier.push(start);
visited.add(startHash);
while (frontier.length > 0) {
const current = frontier.shift()!;
const currentHash = Vector2Utils.toHash(current);
if (currentHash === goalHash) {
return true;
}
for (const neighbor of graph.getNeighbors(current)) {
const neighborHash = Vector2Utils.toHash(neighbor);
if (visited.has(neighborHash)) {
continue;
}
visited.add(neighborHash);
pathMap.set(neighborHash, current);
frontier.push(neighbor);
}
}
return false;
}
/**
* 搜索并返回完整路径
* @param graph 图对象
* @param start 起始节点
* @param goal 目标节点
* @returns 路径数组,如果没找到则返回空数组
*/
static searchPath<T extends IVector2>(
graph: IUnweightedGraph<T>,
start: T,
goal: T
): T[] {
const cameFrom = new Map<number, T>();
if (this.search(graph, start, goal, cameFrom)) {
return this.reconstructPath(cameFrom, start, goal);
}
return [];
}
/**
* 重构路径
* @param cameFrom 路径记录Map
* @param start 起始节点
* @param goal 目标节点
* @returns 完整路径
*/
static reconstructPath<T extends IVector2>(
cameFrom: Map<number, T>,
start: T,
goal: T
): T[] {
const path: T[] = [];
let current = goal;
const startHash = Vector2Utils.toHash(start);
while (Vector2Utils.toHash(current) !== startHash) {
path.unshift(current);
const currentHash = Vector2Utils.toHash(current);
const parent = cameFrom.get(currentHash);
if (!parent) break;
current = parent;
}
path.unshift(start);
return path;
}
}