@esengine/pathfinding 1.0.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +740 -0
- package/dist/index.js +1826 -0
- package/dist/index.js.map +1 -0
- package/module.json +24 -0
- package/package.json +61 -70
- package/README.md +0 -358
- package/dist/pathfinding.cjs +0 -566
- package/dist/pathfinding.cjs.map +0 -1
- package/dist/pathfinding.d.ts +0 -152
- package/dist/pathfinding.js +0 -572
- package/dist/pathfinding.js.map +0 -1
- package/dist/pathfinding.mjs +0 -558
- package/dist/pathfinding.mjs.map +0 -1
package/README.md
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
# 寻路算法库
|
|
2
|
-
|
|
3
|
-
[](https://github.com/esengine/ecs-astar/actions)
|
|
4
|
-
[](https://www.npmjs.com/package/@esengine/pathfinding)
|
|
5
|
-
[](https://github.com/esengine/ecs-astar)
|
|
6
|
-
[](https://github.com/esengine/ecs-astar/blob/main/LICENSE)
|
|
7
|
-
|
|
8
|
-
适用于Cocos Creator和Laya引擎的寻路算法库,支持A*和广度优先搜索算法。
|
|
9
|
-
|
|
10
|
-
## ✨ 特性
|
|
11
|
-
|
|
12
|
-
- **多算法支持**:A*、广度优先搜索
|
|
13
|
-
- **引擎兼容**:支持Cocos Creator和Laya引擎
|
|
14
|
-
- **TypeScript**:完整的类型定义
|
|
15
|
-
- **高性能**:对象池优化,减少GC压力
|
|
16
|
-
- **稳定可靠**:87.39%测试覆盖率,14个测试用例验证
|
|
17
|
-
- **类型安全**:严格的TypeScript类型检查
|
|
18
|
-
|
|
19
|
-
## 安装
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install @esengine/pathfinding
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## 算法选择
|
|
26
|
-
|
|
27
|
-
### A*算法
|
|
28
|
-
- **适用场景**:大部分游戏寻路需求
|
|
29
|
-
- **特点**:支持权重地形,路径质量好
|
|
30
|
-
- **推荐用于**:RPG、策略游戏、塔防游戏
|
|
31
|
-
|
|
32
|
-
### 广度优先搜索
|
|
33
|
-
- **适用场景**:简单网格寻路
|
|
34
|
-
- **特点**:保证最短路径(步数最少)
|
|
35
|
-
- **推荐用于**:迷宫游戏、推箱子游戏
|
|
36
|
-
|
|
37
|
-
## 快速开始
|
|
38
|
-
|
|
39
|
-
### 基本使用
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
import { AStarPathfinder, AstarGridGraph, Vector2Utils } from '@esengine/pathfinding';
|
|
43
|
-
|
|
44
|
-
// 创建20x20的网格
|
|
45
|
-
const graph = new AstarGridGraph(20, 20);
|
|
46
|
-
|
|
47
|
-
// 添加障碍物
|
|
48
|
-
graph.addWall(Vector2Utils.create(10, 10));
|
|
49
|
-
graph.addWall(Vector2Utils.create(10, 11));
|
|
50
|
-
|
|
51
|
-
// 添加难走地形(权重节点)
|
|
52
|
-
graph.addWeightedNode(Vector2Utils.create(5, 5));
|
|
53
|
-
|
|
54
|
-
// 搜索路径
|
|
55
|
-
const start = Vector2Utils.create(0, 0);
|
|
56
|
-
const goal = Vector2Utils.create(19, 19);
|
|
57
|
-
|
|
58
|
-
// 方法1:使用图对象的便捷方法
|
|
59
|
-
const path = graph.searchPath(start, goal);
|
|
60
|
-
|
|
61
|
-
// 方法2:使用静态方法(更灵活)
|
|
62
|
-
const path2 = AStarPathfinder.searchPath(graph, start, goal);
|
|
63
|
-
|
|
64
|
-
// 检查路径是否存在(不返回具体路径)
|
|
65
|
-
const hasPath = AStarPathfinder.hasPath(graph, start, goal);
|
|
66
|
-
|
|
67
|
-
console.log('路径:', path);
|
|
68
|
-
console.log('路径存在:', hasPath);
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### 广度优先搜索
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
import { UnweightedGridGraph } from '@esengine/pathfinding';
|
|
75
|
-
|
|
76
|
-
// 创建网格,支持对角线移动
|
|
77
|
-
const graph = new UnweightedGridGraph(10, 10, true);
|
|
78
|
-
|
|
79
|
-
// 添加障碍物
|
|
80
|
-
graph.walls.push({ x: 5, y: 5 });
|
|
81
|
-
|
|
82
|
-
// 搜索路径
|
|
83
|
-
const path = graph.searchPath({ x: 0, y: 0 }, { x: 9, y: 9 });
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### 按需加载
|
|
87
|
-
|
|
88
|
-
```typescript
|
|
89
|
-
// 只使用A*算法
|
|
90
|
-
import { AstarGridGraph } from '@esengine/pathfinding/modules/astar';
|
|
91
|
-
|
|
92
|
-
// 只使用广度优先算法
|
|
93
|
-
import { UnweightedGridGraph } from '@esengine/pathfinding/modules/breadth-first';
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## 在游戏引擎中使用
|
|
97
|
-
|
|
98
|
-
### Cocos Creator
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import { AstarGridGraph } from '@esengine/pathfinding';
|
|
102
|
-
|
|
103
|
-
export default class PathfindingComponent extends cc.Component {
|
|
104
|
-
private graph: AstarGridGraph;
|
|
105
|
-
|
|
106
|
-
onLoad() {
|
|
107
|
-
this.graph = new AstarGridGraph(50, 50);
|
|
108
|
-
this.setupObstacles();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
findPath(start: cc.Vec2, goal: cc.Vec2): cc.Vec2[] {
|
|
112
|
-
return this.graph.searchPath(start, goal) as cc.Vec2[];
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private setupObstacles() {
|
|
116
|
-
// 添加地图障碍物
|
|
117
|
-
for (let x = 10; x < 15; x++) {
|
|
118
|
-
this.graph.addWall(cc.v2(x, 10));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Laya引擎
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
import { AstarGridGraph } from '@esengine/pathfinding';
|
|
128
|
-
|
|
129
|
-
export class PathfindingManager {
|
|
130
|
-
private graph: AstarGridGraph;
|
|
131
|
-
|
|
132
|
-
constructor(mapWidth: number, mapHeight: number) {
|
|
133
|
-
this.graph = new AstarGridGraph(mapWidth, mapHeight);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
findPath(start: Laya.Vector2, goal: Laya.Vector2): Laya.Vector2[] {
|
|
137
|
-
return this.graph.searchPath(start, goal) as Laya.Vector2[];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
addObstacle(pos: Laya.Vector2) {
|
|
141
|
-
this.graph.addWall(pos);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## API文档
|
|
147
|
-
|
|
148
|
-
### AStarPathfinder
|
|
149
|
-
|
|
150
|
-
A*算法核心实现(静态方法)。
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
// 搜索完整路径
|
|
154
|
-
AStarPathfinder.searchPath<T>(graph: IAstarGraph<T>, start: T, goal: T): T[]
|
|
155
|
-
|
|
156
|
-
// 检查路径是否存在
|
|
157
|
-
AStarPathfinder.hasPath<T>(graph: IAstarGraph<T>, start: T, goal: T): boolean
|
|
158
|
-
|
|
159
|
-
// 底层搜索方法(返回节点对象)
|
|
160
|
-
AStarPathfinder.search<T>(graph: IAstarGraph<T>, start: T, goal: T): {
|
|
161
|
-
found: boolean;
|
|
162
|
-
goalNode?: AStarNode;
|
|
163
|
-
openSetNodes?: AStarNode[];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// 对象池管理
|
|
167
|
-
AStarPathfinder.clearPool(): void // 清理对象池
|
|
168
|
-
AStarPathfinder.getPoolStats(): { // 获取池统计信息
|
|
169
|
-
poolSize: number;
|
|
170
|
-
maxPoolSize: number;
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### AstarGridGraph
|
|
175
|
-
|
|
176
|
-
A*算法网格图实现。
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
const graph = new AstarGridGraph(width: number, height: number);
|
|
180
|
-
|
|
181
|
-
// 属性
|
|
182
|
-
graph.walls: IVector2[] // 障碍物数组
|
|
183
|
-
graph.weightedNodes: IVector2[] // 加权节点数组
|
|
184
|
-
graph.defaultWeight: number // 默认移动成本(默认1)
|
|
185
|
-
graph.weightedNodeWeight: number // 加权节点成本(默认5)
|
|
186
|
-
|
|
187
|
-
// 方法
|
|
188
|
-
graph.searchPath(start, goal): IVector2[] // 搜索完整路径(便捷方法)
|
|
189
|
-
graph.isNodePassable(node): boolean // 检查节点是否可通行
|
|
190
|
-
graph.isNodeInBounds(node): boolean // 检查节点是否在边界内
|
|
191
|
-
graph.addWall(wall): void // 添加单个障碍物
|
|
192
|
-
graph.addWalls(walls): void // 批量添加障碍物
|
|
193
|
-
graph.clearWalls(): void // 清空障碍物
|
|
194
|
-
graph.addWeightedNode(node): void // 添加加权节点
|
|
195
|
-
graph.clearWeightedNodes(): void // 清空加权节点
|
|
196
|
-
|
|
197
|
-
// IAstarGraph接口方法
|
|
198
|
-
graph.getNeighbors(node): IVector2[] // 获取邻居节点
|
|
199
|
-
graph.cost(from, to): number // 计算移动成本
|
|
200
|
-
graph.heuristic(node, goal): number // 计算启发式距离
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
### UnweightedGridGraph
|
|
204
|
-
|
|
205
|
-
广度优先搜索网格图实现。
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
const graph = new UnweightedGridGraph(
|
|
209
|
-
width: number,
|
|
210
|
-
height: number,
|
|
211
|
-
allowDiagonal?: boolean // 是否允许对角线移动
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
// 属性
|
|
215
|
-
graph.walls: IVector2[] // 障碍物数组
|
|
216
|
-
|
|
217
|
-
// 方法
|
|
218
|
-
graph.searchPath(start, goal): IVector2[] // 搜索完整路径
|
|
219
|
-
graph.hasPath(start, goal): boolean // 检查是否存在路径
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Vector2Utils
|
|
223
|
-
|
|
224
|
-
向量操作工具类。
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
Vector2Utils.create(x, y) // 创建向量
|
|
228
|
-
Vector2Utils.equals(a, b) // 判断相等
|
|
229
|
-
Vector2Utils.add(a, b) // 向量加法
|
|
230
|
-
Vector2Utils.manhattanDistance(a, b) // 曼哈顿距离
|
|
231
|
-
Vector2Utils.distance(a, b) // 欧几里得距离
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## 游戏场景示例
|
|
235
|
-
|
|
236
|
-
### 塔防游戏
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
import { AStarPathfinder, AstarGridGraph } from '@esengine/pathfinding';
|
|
240
|
-
|
|
241
|
-
// 敌人寻路到基地
|
|
242
|
-
const graph = new AstarGridGraph(mapWidth, mapHeight);
|
|
243
|
-
towers.forEach(tower => graph.addWall(tower.position));
|
|
244
|
-
|
|
245
|
-
// 检查是否有路径(性能更好)
|
|
246
|
-
if (AStarPathfinder.hasPath(graph, spawnPoint, basePosition)) {
|
|
247
|
-
const path = AStarPathfinder.searchPath(graph, spawnPoint, basePosition);
|
|
248
|
-
enemy.followPath(path);
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### RPG游戏
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
import { AStarPathfinder, AstarGridGraph } from '@esengine/pathfinding';
|
|
256
|
-
|
|
257
|
-
// 角色移动寻路,设置不同地形权重
|
|
258
|
-
const graph = new AstarGridGraph(mapWidth, mapHeight);
|
|
259
|
-
swampTiles.forEach(tile => graph.addWeightedNode(tile));
|
|
260
|
-
graph.weightedNodeWeight = 3; // 沼泽地移动慢
|
|
261
|
-
|
|
262
|
-
const path = AStarPathfinder.searchPath(graph, playerPos, targetPos);
|
|
263
|
-
if (path.length > 0) {
|
|
264
|
-
player.moveTo(path);
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### 迷宫游戏
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
import { UnweightedGridGraph } from '@esengine/pathfinding';
|
|
272
|
-
|
|
273
|
-
// 简单迷宫寻路
|
|
274
|
-
const graph = new UnweightedGridGraph(mazeWidth, mazeHeight);
|
|
275
|
-
walls.forEach(wall => graph.walls.push(wall));
|
|
276
|
-
const path = graph.searchPath(startPos, exitPos);
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
### 性能优化示例
|
|
280
|
-
|
|
281
|
-
```typescript
|
|
282
|
-
import { AStarPathfinder } from '@esengine/pathfinding';
|
|
283
|
-
|
|
284
|
-
// 在游戏结束时清理对象池
|
|
285
|
-
function onGameEnd() {
|
|
286
|
-
AStarPathfinder.clearPool();
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// 监控内存使用
|
|
290
|
-
function checkMemoryUsage() {
|
|
291
|
-
const stats = AStarPathfinder.getPoolStats();
|
|
292
|
-
console.log(`对象池使用: ${stats.poolSize}/${stats.maxPoolSize}`);
|
|
293
|
-
|
|
294
|
-
if (stats.poolSize > stats.maxPoolSize * 0.8) {
|
|
295
|
-
console.warn('对象池使用率较高,考虑优化');
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
## 文件结构
|
|
301
|
-
|
|
302
|
-
```
|
|
303
|
-
bin/
|
|
304
|
-
├── pathfinding.js # 完整版本
|
|
305
|
-
├── pathfinding.min.js # 完整版本(压缩)
|
|
306
|
-
├── pathfinding.d.ts # TypeScript类型定义
|
|
307
|
-
└── modules/ # 分模块版本
|
|
308
|
-
├── astar.js # A*算法模块
|
|
309
|
-
├── astar.min.js # A*算法模块(压缩)
|
|
310
|
-
├── breadth-first.js # 广度优先模块
|
|
311
|
-
└── breadth-first.min.js # 广度优先模块(压缩)
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
## 开发
|
|
315
|
-
|
|
316
|
-
```bash
|
|
317
|
-
# 安装依赖
|
|
318
|
-
npm install
|
|
319
|
-
|
|
320
|
-
# 运行测试
|
|
321
|
-
npm test
|
|
322
|
-
|
|
323
|
-
# 测试覆盖率
|
|
324
|
-
npm run test:coverage
|
|
325
|
-
|
|
326
|
-
# 类型检查
|
|
327
|
-
npm run type-check
|
|
328
|
-
|
|
329
|
-
# 代码检查
|
|
330
|
-
npm run lint
|
|
331
|
-
|
|
332
|
-
# 构建
|
|
333
|
-
npm run build
|
|
334
|
-
|
|
335
|
-
# 完整CI检查
|
|
336
|
-
npm run ci
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
## 质量保证
|
|
340
|
-
|
|
341
|
-
- ✅ **14个测试用例**覆盖主要功能
|
|
342
|
-
- ✅ **87.39%代码覆盖率**
|
|
343
|
-
- ✅ **TypeScript严格模式**
|
|
344
|
-
- ✅ **ESLint代码规范**
|
|
345
|
-
- ✅ **CI自动化测试**
|
|
346
|
-
|
|
347
|
-
### 测试覆盖范围
|
|
348
|
-
|
|
349
|
-
- 基础路径查找功能
|
|
350
|
-
- 边界情况处理(起点=终点、超出边界、障碍物上)
|
|
351
|
-
- 错误情况处理(无路径、不可达)
|
|
352
|
-
- 性能和稳定性(大网格、多次搜索)
|
|
353
|
-
- 对象池内存管理
|
|
354
|
-
- 路径质量验证
|
|
355
|
-
|
|
356
|
-
## 许可证
|
|
357
|
-
|
|
358
|
-
MIT License
|