@esengine/pathfinding 12.0.0 → 12.1.2

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/dist/ecs.js ADDED
@@ -0,0 +1,1033 @@
1
+ import {
2
+ CatmullRomSmoother,
3
+ CombinedSmoother,
4
+ GridMap,
5
+ IncrementalAStarPathfinder,
6
+ LineOfSightSmoother,
7
+ PathValidator
8
+ } from "./chunk-TPT7Q3E3.js";
9
+ import {
10
+ PathfindingState,
11
+ __name,
12
+ __publicField
13
+ } from "./chunk-GTFFYRZM.js";
14
+
15
+ // src/ecs/PathfindingAgentComponent.ts
16
+ import { Component, ECSComponent, Serializable, Serialize, Property } from "@esengine/ecs-framework";
17
+ function _ts_decorate(decorators, target, key, desc) {
18
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
22
+ }
23
+ __name(_ts_decorate, "_ts_decorate");
24
+ function _ts_metadata(k, v) {
25
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
26
+ }
27
+ __name(_ts_metadata, "_ts_metadata");
28
+ var _PathfindingAgentComponent = class _PathfindingAgentComponent extends Component {
29
+ constructor() {
30
+ super(...arguments);
31
+ // =========================================================================
32
+ // 位置属性 | Position Properties
33
+ // =========================================================================
34
+ /**
35
+ * @zh 当前位置 X 坐标
36
+ * @en Current position X coordinate
37
+ */
38
+ __publicField(this, "x", 0);
39
+ /**
40
+ * @zh 当前位置 Y 坐标
41
+ * @en Current position Y coordinate
42
+ */
43
+ __publicField(this, "y", 0);
44
+ // =========================================================================
45
+ // 目标属性 | Target Properties
46
+ // =========================================================================
47
+ /**
48
+ * @zh 目标位置 X 坐标
49
+ * @en Target position X coordinate
50
+ */
51
+ __publicField(this, "targetX", 0);
52
+ /**
53
+ * @zh 目标位置 Y 坐标
54
+ * @en Target position Y coordinate
55
+ */
56
+ __publicField(this, "targetY", 0);
57
+ /**
58
+ * @zh 是否有新的寻路请求待处理
59
+ * @en Whether there is a new path request pending
60
+ */
61
+ __publicField(this, "hasRequest", false);
62
+ // =========================================================================
63
+ // 配置属性 | Configuration Properties
64
+ // =========================================================================
65
+ /**
66
+ * @zh 寻路优先级(数值越小优先级越高)
67
+ * @en Pathfinding priority (lower number = higher priority)
68
+ */
69
+ __publicField(this, "priority", 50);
70
+ /**
71
+ * @zh 每帧最大迭代次数
72
+ * @en Maximum iterations per frame
73
+ */
74
+ __publicField(this, "maxIterationsPerFrame", 100);
75
+ /**
76
+ * @zh 是否启用动态重规划
77
+ * @en Whether dynamic replanning is enabled
78
+ */
79
+ __publicField(this, "enableDynamicReplan", true);
80
+ /**
81
+ * @zh 向前探测距离(用于障碍物检测)
82
+ * @en Lookahead distance for obstacle detection
83
+ */
84
+ __publicField(this, "lookaheadDistance", 5);
85
+ /**
86
+ * @zh 路径验证间隔(帧数)
87
+ * @en Path validation interval (in frames)
88
+ */
89
+ __publicField(this, "validationInterval", 10);
90
+ // =========================================================================
91
+ // 运行时状态(不序列化)| Runtime State (not serialized)
92
+ // =========================================================================
93
+ /**
94
+ * @zh 当前寻路状态
95
+ * @en Current pathfinding state
96
+ */
97
+ __publicField(this, "state", PathfindingState.Idle);
98
+ /**
99
+ * @zh 当前请求 ID
100
+ * @en Current request ID
101
+ */
102
+ __publicField(this, "currentRequestId", -1);
103
+ /**
104
+ * @zh 当前路径点列表
105
+ * @en Current path waypoints
106
+ */
107
+ __publicField(this, "path", []);
108
+ /**
109
+ * @zh 当前路径索引
110
+ * @en Current path index
111
+ */
112
+ __publicField(this, "pathIndex", 0);
113
+ /**
114
+ * @zh 路径总代价
115
+ * @en Total path cost
116
+ */
117
+ __publicField(this, "pathCost", 0);
118
+ /**
119
+ * @zh 寻路进度 (0-1)
120
+ * @en Pathfinding progress (0-1)
121
+ */
122
+ __publicField(this, "progress", 0);
123
+ /**
124
+ * @zh 上次验证的帧号
125
+ * @en Last validation frame number
126
+ */
127
+ __publicField(this, "lastValidationFrame", 0);
128
+ /**
129
+ * @zh 寻路完成回调
130
+ * @en Pathfinding complete callback
131
+ */
132
+ __publicField(this, "onPathComplete");
133
+ /**
134
+ * @zh 寻路进度回调
135
+ * @en Pathfinding progress callback
136
+ */
137
+ __publicField(this, "onPathProgress");
138
+ }
139
+ // =========================================================================
140
+ // 公共方法 | Public Methods
141
+ // =========================================================================
142
+ /**
143
+ * @zh 请求寻路到目标位置
144
+ * @en Request path to target position
145
+ *
146
+ * @param targetX - @zh 目标 X 坐标 @en Target X coordinate
147
+ * @param targetY - @zh 目标 Y 坐标 @en Target Y coordinate
148
+ */
149
+ requestPathTo(targetX, targetY) {
150
+ this.targetX = targetX;
151
+ this.targetY = targetY;
152
+ this.hasRequest = true;
153
+ this.state = PathfindingState.Idle;
154
+ this.progress = 0;
155
+ }
156
+ /**
157
+ * @zh 取消当前寻路
158
+ * @en Cancel current pathfinding
159
+ */
160
+ cancelPath() {
161
+ this.hasRequest = false;
162
+ this.state = PathfindingState.Cancelled;
163
+ this.path = [];
164
+ this.pathIndex = 0;
165
+ this.progress = 0;
166
+ this.currentRequestId = -1;
167
+ }
168
+ /**
169
+ * @zh 获取下一个路径点
170
+ * @en Get next waypoint
171
+ *
172
+ * @returns @zh 下一个路径点或 null @en Next waypoint or null
173
+ */
174
+ getNextWaypoint() {
175
+ if (this.pathIndex < this.path.length) {
176
+ return this.path[this.pathIndex];
177
+ }
178
+ return null;
179
+ }
180
+ /**
181
+ * @zh 前进到下一个路径点
182
+ * @en Advance to next waypoint
183
+ */
184
+ advanceWaypoint() {
185
+ if (this.pathIndex < this.path.length) {
186
+ this.pathIndex++;
187
+ }
188
+ }
189
+ /**
190
+ * @zh 检查是否到达路径终点
191
+ * @en Check if reached path end
192
+ *
193
+ * @returns @zh 是否到达终点 @en Whether reached end
194
+ */
195
+ isPathComplete() {
196
+ return this.pathIndex >= this.path.length;
197
+ }
198
+ /**
199
+ * @zh 检查是否正在寻路
200
+ * @en Check if pathfinding is in progress
201
+ *
202
+ * @returns @zh 是否正在寻路 @en Whether pathfinding is in progress
203
+ */
204
+ isSearching() {
205
+ return this.state === PathfindingState.InProgress;
206
+ }
207
+ /**
208
+ * @zh 检查是否有有效路径
209
+ * @en Check if has valid path
210
+ *
211
+ * @returns @zh 是否有有效路径 @en Whether has valid path
212
+ */
213
+ hasValidPath() {
214
+ return this.state === PathfindingState.Completed && this.path.length > 0;
215
+ }
216
+ /**
217
+ * @zh 获取剩余路径点数量
218
+ * @en Get remaining waypoint count
219
+ *
220
+ * @returns @zh 剩余路径点数量 @en Remaining waypoint count
221
+ */
222
+ getRemainingWaypointCount() {
223
+ return Math.max(0, this.path.length - this.pathIndex);
224
+ }
225
+ /**
226
+ * @zh 获取当前路径的总长度
227
+ * @en Get total path length
228
+ *
229
+ * @returns @zh 路径总长度 @en Total path length
230
+ */
231
+ getPathLength() {
232
+ return this.path.length;
233
+ }
234
+ /**
235
+ * @zh 重置组件状态
236
+ * @en Reset component state
237
+ */
238
+ reset() {
239
+ this.state = PathfindingState.Idle;
240
+ this.currentRequestId = -1;
241
+ this.path = [];
242
+ this.pathIndex = 0;
243
+ this.pathCost = 0;
244
+ this.progress = 0;
245
+ this.hasRequest = false;
246
+ this.lastValidationFrame = 0;
247
+ }
248
+ /**
249
+ * @zh 组件从实体移除时调用
250
+ * @en Called when component is removed from entity
251
+ */
252
+ onRemovedFromEntity() {
253
+ this.reset();
254
+ this.onPathComplete = void 0;
255
+ this.onPathProgress = void 0;
256
+ }
257
+ };
258
+ __name(_PathfindingAgentComponent, "PathfindingAgentComponent");
259
+ var PathfindingAgentComponent = _PathfindingAgentComponent;
260
+ _ts_decorate([
261
+ Serialize(),
262
+ Property({
263
+ type: "number",
264
+ label: "Position X"
265
+ }),
266
+ _ts_metadata("design:type", Number)
267
+ ], PathfindingAgentComponent.prototype, "x", void 0);
268
+ _ts_decorate([
269
+ Serialize(),
270
+ Property({
271
+ type: "number",
272
+ label: "Position Y"
273
+ }),
274
+ _ts_metadata("design:type", Number)
275
+ ], PathfindingAgentComponent.prototype, "y", void 0);
276
+ _ts_decorate([
277
+ Serialize(),
278
+ Property({
279
+ type: "number",
280
+ label: "Target X"
281
+ }),
282
+ _ts_metadata("design:type", Number)
283
+ ], PathfindingAgentComponent.prototype, "targetX", void 0);
284
+ _ts_decorate([
285
+ Serialize(),
286
+ Property({
287
+ type: "number",
288
+ label: "Target Y"
289
+ }),
290
+ _ts_metadata("design:type", Number)
291
+ ], PathfindingAgentComponent.prototype, "targetY", void 0);
292
+ _ts_decorate([
293
+ Serialize(),
294
+ Property({
295
+ type: "number",
296
+ label: "Priority",
297
+ min: 0,
298
+ max: 100
299
+ }),
300
+ _ts_metadata("design:type", Number)
301
+ ], PathfindingAgentComponent.prototype, "priority", void 0);
302
+ _ts_decorate([
303
+ Serialize(),
304
+ Property({
305
+ type: "number",
306
+ label: "Max Iterations/Frame",
307
+ min: 10,
308
+ max: 1e3
309
+ }),
310
+ _ts_metadata("design:type", Number)
311
+ ], PathfindingAgentComponent.prototype, "maxIterationsPerFrame", void 0);
312
+ _ts_decorate([
313
+ Serialize(),
314
+ Property({
315
+ type: "boolean",
316
+ label: "Dynamic Replan"
317
+ }),
318
+ _ts_metadata("design:type", Boolean)
319
+ ], PathfindingAgentComponent.prototype, "enableDynamicReplan", void 0);
320
+ _ts_decorate([
321
+ Serialize(),
322
+ Property({
323
+ type: "number",
324
+ label: "Lookahead Distance",
325
+ min: 1,
326
+ max: 20
327
+ }),
328
+ _ts_metadata("design:type", Number)
329
+ ], PathfindingAgentComponent.prototype, "lookaheadDistance", void 0);
330
+ _ts_decorate([
331
+ Serialize(),
332
+ Property({
333
+ type: "number",
334
+ label: "Validation Interval",
335
+ min: 1,
336
+ max: 60
337
+ }),
338
+ _ts_metadata("design:type", Number)
339
+ ], PathfindingAgentComponent.prototype, "validationInterval", void 0);
340
+ PathfindingAgentComponent = _ts_decorate([
341
+ ECSComponent("PathfindingAgent"),
342
+ Serializable({
343
+ version: 1,
344
+ typeId: "PathfindingAgent"
345
+ })
346
+ ], PathfindingAgentComponent);
347
+
348
+ // src/ecs/PathfindingMapComponent.ts
349
+ import { Component as Component2, ECSComponent as ECSComponent2, Serializable as Serializable2, Serialize as Serialize2, Property as Property2 } from "@esengine/ecs-framework";
350
+ function _ts_decorate2(decorators, target, key, desc) {
351
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
352
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
353
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
354
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
355
+ }
356
+ __name(_ts_decorate2, "_ts_decorate");
357
+ function _ts_metadata2(k, v) {
358
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
359
+ }
360
+ __name(_ts_metadata2, "_ts_metadata");
361
+ var _PathfindingMapComponent = class _PathfindingMapComponent extends Component2 {
362
+ constructor() {
363
+ super(...arguments);
364
+ // =========================================================================
365
+ // 地图配置 | Map Configuration
366
+ // =========================================================================
367
+ /**
368
+ * @zh 地图类型
369
+ * @en Map type
370
+ */
371
+ __publicField(this, "mapType", "grid");
372
+ /**
373
+ * @zh 网格宽度(仅 grid 类型)
374
+ * @en Grid width (grid type only)
375
+ */
376
+ __publicField(this, "width", 100);
377
+ /**
378
+ * @zh 网格高度(仅 grid 类型)
379
+ * @en Grid height (grid type only)
380
+ */
381
+ __publicField(this, "height", 100);
382
+ /**
383
+ * @zh 是否允许对角移动
384
+ * @en Whether diagonal movement is allowed
385
+ */
386
+ __publicField(this, "allowDiagonal", true);
387
+ /**
388
+ * @zh 是否避免穿角
389
+ * @en Whether to avoid corner cutting
390
+ */
391
+ __publicField(this, "avoidCorners", true);
392
+ // =========================================================================
393
+ // 系统配置 | System Configuration
394
+ // =========================================================================
395
+ /**
396
+ * @zh 每帧处理的最大代理数
397
+ * @en Maximum agents processed per frame
398
+ */
399
+ __publicField(this, "maxAgentsPerFrame", 10);
400
+ /**
401
+ * @zh 每帧总迭代次数预算
402
+ * @en Total iterations budget per frame
403
+ */
404
+ __publicField(this, "iterationsBudget", 1e3);
405
+ /**
406
+ * @zh 是否启用路径平滑
407
+ * @en Whether path smoothing is enabled
408
+ */
409
+ __publicField(this, "enableSmoothing", true);
410
+ /**
411
+ * @zh 路径平滑类型
412
+ * @en Path smoothing type
413
+ */
414
+ __publicField(this, "smoothingType", "los");
415
+ // =========================================================================
416
+ // 缓存配置 | Cache Configuration
417
+ // =========================================================================
418
+ /**
419
+ * @zh 是否启用路径缓存
420
+ * @en Whether path caching is enabled
421
+ */
422
+ __publicField(this, "enableCache", true);
423
+ /**
424
+ * @zh 缓存最大条目数
425
+ * @en Maximum cache entries
426
+ */
427
+ __publicField(this, "cacheMaxEntries", 1e3);
428
+ /**
429
+ * @zh 缓存过期时间(毫秒),0 表示不过期
430
+ * @en Cache TTL in milliseconds, 0 means no expiration
431
+ */
432
+ __publicField(this, "cacheTtlMs", 5e3);
433
+ // =========================================================================
434
+ // 调试配置 | Debug Configuration
435
+ // =========================================================================
436
+ /**
437
+ * @zh 是否显示调试信息
438
+ * @en Whether to show debug info
439
+ */
440
+ __publicField(this, "debugMode", false);
441
+ /**
442
+ * @zh 是否显示网格
443
+ * @en Whether to show grid
444
+ */
445
+ __publicField(this, "showGrid", false);
446
+ /**
447
+ * @zh 是否显示路径
448
+ * @en Whether to show paths
449
+ */
450
+ __publicField(this, "showPaths", false);
451
+ // =========================================================================
452
+ // 运行时实例(不序列化)| Runtime Instances (not serialized)
453
+ // =========================================================================
454
+ /**
455
+ * @zh 地图实例
456
+ * @en Map instance
457
+ */
458
+ __publicField(this, "map", null);
459
+ /**
460
+ * @zh 增量寻路器实例
461
+ * @en Incremental pathfinder instance
462
+ */
463
+ __publicField(this, "pathfinder", null);
464
+ /**
465
+ * @zh 路径平滑器实例
466
+ * @en Path smoother instance
467
+ */
468
+ __publicField(this, "smoother", null);
469
+ /**
470
+ * @zh 是否已初始化
471
+ * @en Whether initialized
472
+ */
473
+ __publicField(this, "initialized", false);
474
+ // =========================================================================
475
+ // 统计信息 | Statistics
476
+ // =========================================================================
477
+ /**
478
+ * @zh 当前活跃请求数
479
+ * @en Current active request count
480
+ */
481
+ __publicField(this, "activeRequests", 0);
482
+ /**
483
+ * @zh 本帧使用的迭代次数
484
+ * @en Iterations used this frame
485
+ */
486
+ __publicField(this, "iterationsUsedThisFrame", 0);
487
+ /**
488
+ * @zh 本帧处理的代理数
489
+ * @en Agents processed this frame
490
+ */
491
+ __publicField(this, "agentsProcessedThisFrame", 0);
492
+ /**
493
+ * @zh 缓存命中次数
494
+ * @en Cache hit count
495
+ */
496
+ __publicField(this, "cacheHits", 0);
497
+ /**
498
+ * @zh 缓存未命中次数
499
+ * @en Cache miss count
500
+ */
501
+ __publicField(this, "cacheMisses", 0);
502
+ }
503
+ // =========================================================================
504
+ // 公共方法 | Public Methods
505
+ // =========================================================================
506
+ /**
507
+ * @zh 设置网格单元格是否可通行
508
+ * @en Set grid cell walkability
509
+ *
510
+ * @param x - @zh X 坐标 @en X coordinate
511
+ * @param y - @zh Y 坐标 @en Y coordinate
512
+ * @param walkable - @zh 是否可通行 @en Is walkable
513
+ */
514
+ setWalkable(x, y, walkable) {
515
+ if (this.map && "setWalkable" in this.map) {
516
+ this.map.setWalkable(x, y, walkable);
517
+ if (this.pathfinder) {
518
+ this.pathfinder.notifyObstacleChange(x - 1, y - 1, x + 1, y + 1);
519
+ }
520
+ }
521
+ }
522
+ /**
523
+ * @zh 设置矩形区域是否可通行
524
+ * @en Set rectangular area walkability
525
+ *
526
+ * @param x - @zh 起始 X @en Start X
527
+ * @param y - @zh 起始 Y @en Start Y
528
+ * @param width - @zh 宽度 @en Width
529
+ * @param height - @zh 高度 @en Height
530
+ * @param walkable - @zh 是否可通行 @en Is walkable
531
+ */
532
+ setRectWalkable(x, y, rectWidth, rectHeight, walkable) {
533
+ if (this.map && "setRectWalkable" in this.map) {
534
+ this.map.setRectWalkable(x, y, rectWidth, rectHeight, walkable);
535
+ if (this.pathfinder) {
536
+ this.pathfinder.notifyObstacleChange(x - 1, y - 1, x + rectWidth + 1, y + rectHeight + 1);
537
+ }
538
+ }
539
+ }
540
+ /**
541
+ * @zh 检查位置是否可通行
542
+ * @en Check if position is walkable
543
+ *
544
+ * @param x - @zh X 坐标 @en X coordinate
545
+ * @param y - @zh Y 坐标 @en Y coordinate
546
+ * @returns @zh 是否可通行 @en Is walkable
547
+ */
548
+ isWalkable(x, y) {
549
+ return this.map?.isWalkable(x, y) ?? false;
550
+ }
551
+ /**
552
+ * @zh 重置统计信息
553
+ * @en Reset statistics
554
+ */
555
+ resetStats() {
556
+ this.iterationsUsedThisFrame = 0;
557
+ this.agentsProcessedThisFrame = 0;
558
+ }
559
+ /**
560
+ * @zh 获取剩余迭代预算
561
+ * @en Get remaining iteration budget
562
+ *
563
+ * @returns @zh 剩余预算 @en Remaining budget
564
+ */
565
+ getRemainingBudget() {
566
+ return Math.max(0, this.iterationsBudget - this.iterationsUsedThisFrame);
567
+ }
568
+ /**
569
+ * @zh 获取缓存统计信息
570
+ * @en Get cache statistics
571
+ *
572
+ * @returns @zh 缓存统计 @en Cache statistics
573
+ */
574
+ getCacheStats() {
575
+ const pathfinderWithCache = this.pathfinder;
576
+ if (pathfinderWithCache?.getCacheStats) {
577
+ const stats = pathfinderWithCache.getCacheStats();
578
+ this.cacheHits = stats.hits;
579
+ this.cacheMisses = stats.misses;
580
+ return {
581
+ enabled: this.enableCache,
582
+ hits: stats.hits,
583
+ misses: stats.misses,
584
+ hitRate: stats.hitRate
585
+ };
586
+ }
587
+ return {
588
+ enabled: this.enableCache,
589
+ hits: this.cacheHits,
590
+ misses: this.cacheMisses,
591
+ hitRate: this.cacheHits + this.cacheMisses > 0 ? this.cacheHits / (this.cacheHits + this.cacheMisses) : 0
592
+ };
593
+ }
594
+ /**
595
+ * @zh 组件从实体移除时调用
596
+ * @en Called when component is removed from entity
597
+ */
598
+ onRemovedFromEntity() {
599
+ if (this.pathfinder) {
600
+ this.pathfinder.clear();
601
+ }
602
+ this.map = null;
603
+ this.pathfinder = null;
604
+ this.smoother = null;
605
+ this.initialized = false;
606
+ }
607
+ };
608
+ __name(_PathfindingMapComponent, "PathfindingMapComponent");
609
+ var PathfindingMapComponent = _PathfindingMapComponent;
610
+ _ts_decorate2([
611
+ Serialize2(),
612
+ Property2({
613
+ type: "enum",
614
+ label: "Map Type",
615
+ options: [
616
+ {
617
+ value: "grid",
618
+ label: "Grid"
619
+ },
620
+ {
621
+ value: "navmesh",
622
+ label: "NavMesh"
623
+ }
624
+ ]
625
+ }),
626
+ _ts_metadata2("design:type", typeof PathfindingMapType === "undefined" ? Object : PathfindingMapType)
627
+ ], PathfindingMapComponent.prototype, "mapType", void 0);
628
+ _ts_decorate2([
629
+ Serialize2(),
630
+ Property2({
631
+ type: "number",
632
+ label: "Map Width",
633
+ min: 1,
634
+ max: 1e4
635
+ }),
636
+ _ts_metadata2("design:type", Number)
637
+ ], PathfindingMapComponent.prototype, "width", void 0);
638
+ _ts_decorate2([
639
+ Serialize2(),
640
+ Property2({
641
+ type: "number",
642
+ label: "Map Height",
643
+ min: 1,
644
+ max: 1e4
645
+ }),
646
+ _ts_metadata2("design:type", Number)
647
+ ], PathfindingMapComponent.prototype, "height", void 0);
648
+ _ts_decorate2([
649
+ Serialize2(),
650
+ Property2({
651
+ type: "boolean",
652
+ label: "Allow Diagonal"
653
+ }),
654
+ _ts_metadata2("design:type", Boolean)
655
+ ], PathfindingMapComponent.prototype, "allowDiagonal", void 0);
656
+ _ts_decorate2([
657
+ Serialize2(),
658
+ Property2({
659
+ type: "boolean",
660
+ label: "Avoid Corners"
661
+ }),
662
+ _ts_metadata2("design:type", Boolean)
663
+ ], PathfindingMapComponent.prototype, "avoidCorners", void 0);
664
+ _ts_decorate2([
665
+ Serialize2(),
666
+ Property2({
667
+ type: "number",
668
+ label: "Max Agents/Frame",
669
+ min: 1,
670
+ max: 100
671
+ }),
672
+ _ts_metadata2("design:type", Number)
673
+ ], PathfindingMapComponent.prototype, "maxAgentsPerFrame", void 0);
674
+ _ts_decorate2([
675
+ Serialize2(),
676
+ Property2({
677
+ type: "number",
678
+ label: "Iterations Budget",
679
+ min: 100,
680
+ max: 1e4
681
+ }),
682
+ _ts_metadata2("design:type", Number)
683
+ ], PathfindingMapComponent.prototype, "iterationsBudget", void 0);
684
+ _ts_decorate2([
685
+ Serialize2(),
686
+ Property2({
687
+ type: "boolean",
688
+ label: "Enable Smoothing"
689
+ }),
690
+ _ts_metadata2("design:type", Boolean)
691
+ ], PathfindingMapComponent.prototype, "enableSmoothing", void 0);
692
+ _ts_decorate2([
693
+ Serialize2(),
694
+ Property2({
695
+ type: "enum",
696
+ label: "Smoothing Type",
697
+ options: [
698
+ {
699
+ value: "los",
700
+ label: "Line of Sight"
701
+ },
702
+ {
703
+ value: "catmullrom",
704
+ label: "Catmull-Rom"
705
+ },
706
+ {
707
+ value: "combined",
708
+ label: "Combined"
709
+ }
710
+ ]
711
+ }),
712
+ _ts_metadata2("design:type", String)
713
+ ], PathfindingMapComponent.prototype, "smoothingType", void 0);
714
+ _ts_decorate2([
715
+ Serialize2(),
716
+ Property2({
717
+ type: "boolean",
718
+ label: "Enable Cache"
719
+ }),
720
+ _ts_metadata2("design:type", Boolean)
721
+ ], PathfindingMapComponent.prototype, "enableCache", void 0);
722
+ _ts_decorate2([
723
+ Serialize2(),
724
+ Property2({
725
+ type: "number",
726
+ label: "Cache Size",
727
+ min: 100,
728
+ max: 1e4
729
+ }),
730
+ _ts_metadata2("design:type", Number)
731
+ ], PathfindingMapComponent.prototype, "cacheMaxEntries", void 0);
732
+ _ts_decorate2([
733
+ Serialize2(),
734
+ Property2({
735
+ type: "number",
736
+ label: "Cache TTL (ms)",
737
+ min: 0,
738
+ max: 6e4
739
+ }),
740
+ _ts_metadata2("design:type", Number)
741
+ ], PathfindingMapComponent.prototype, "cacheTtlMs", void 0);
742
+ _ts_decorate2([
743
+ Serialize2(),
744
+ Property2({
745
+ type: "boolean",
746
+ label: "Debug Mode"
747
+ }),
748
+ _ts_metadata2("design:type", Boolean)
749
+ ], PathfindingMapComponent.prototype, "debugMode", void 0);
750
+ _ts_decorate2([
751
+ Serialize2(),
752
+ Property2({
753
+ type: "boolean",
754
+ label: "Show Grid"
755
+ }),
756
+ _ts_metadata2("design:type", Boolean)
757
+ ], PathfindingMapComponent.prototype, "showGrid", void 0);
758
+ _ts_decorate2([
759
+ Serialize2(),
760
+ Property2({
761
+ type: "boolean",
762
+ label: "Show Paths"
763
+ }),
764
+ _ts_metadata2("design:type", Boolean)
765
+ ], PathfindingMapComponent.prototype, "showPaths", void 0);
766
+ PathfindingMapComponent = _ts_decorate2([
767
+ ECSComponent2("PathfindingMap"),
768
+ Serializable2({
769
+ version: 1,
770
+ typeId: "PathfindingMap"
771
+ })
772
+ ], PathfindingMapComponent);
773
+
774
+ // src/ecs/PathfindingSystem.ts
775
+ import { EntitySystem, Matcher, ECSSystem } from "@esengine/ecs-framework";
776
+ function _ts_decorate3(decorators, target, key, desc) {
777
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
778
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
779
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
780
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
781
+ }
782
+ __name(_ts_decorate3, "_ts_decorate");
783
+ function _ts_metadata3(k, v) {
784
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
785
+ }
786
+ __name(_ts_metadata3, "_ts_metadata");
787
+ var _PathfindingSystem = class _PathfindingSystem extends EntitySystem {
788
+ constructor() {
789
+ super(Matcher.all(PathfindingAgentComponent));
790
+ __publicField(this, "mapEntity", null);
791
+ __publicField(this, "mapComponent", null);
792
+ __publicField(this, "pathValidator");
793
+ __publicField(this, "agentQueue", []);
794
+ __publicField(this, "frameCounter", 0);
795
+ this.pathValidator = new PathValidator();
796
+ }
797
+ /**
798
+ * @zh 系统初始化
799
+ * @en System initialization
800
+ */
801
+ onInitialize() {
802
+ this.findMapEntity();
803
+ this.initializeMap();
804
+ }
805
+ /**
806
+ * @zh 系统激活时调用
807
+ * @en Called when system is enabled
808
+ */
809
+ onEnable() {
810
+ this.findMapEntity();
811
+ }
812
+ /**
813
+ * @zh 处理实体
814
+ * @en Process entities
815
+ */
816
+ process(entities) {
817
+ if (!this.mapComponent?.pathfinder) {
818
+ this.findMapEntity();
819
+ if (!this.mapComponent?.pathfinder) {
820
+ return;
821
+ }
822
+ }
823
+ this.frameCounter++;
824
+ this.mapComponent.resetStats();
825
+ this.buildAgentQueue(entities);
826
+ this.processAgentsWithBudget();
827
+ this.validatePaths(entities);
828
+ }
829
+ // =========================================================================
830
+ // 私有方法 | Private Methods
831
+ // =========================================================================
832
+ /**
833
+ * @zh 查找地图实体
834
+ * @en Find map entity
835
+ */
836
+ findMapEntity() {
837
+ if (!this.scene) return;
838
+ const entities = this.scene.entities.findEntitiesWithComponent(PathfindingMapComponent);
839
+ if (entities.length > 0) {
840
+ const entity = entities[0];
841
+ const mapComp = entity.getComponent(PathfindingMapComponent);
842
+ if (mapComp) {
843
+ this.mapEntity = entity;
844
+ this.mapComponent = mapComp;
845
+ if (!mapComp.initialized) {
846
+ this.initializeMap();
847
+ }
848
+ }
849
+ }
850
+ }
851
+ /**
852
+ * @zh 初始化地图
853
+ * @en Initialize map
854
+ */
855
+ initializeMap() {
856
+ if (!this.mapComponent) return;
857
+ if (this.mapComponent.initialized) return;
858
+ if (!this.mapComponent.map) {
859
+ if (this.mapComponent.mapType === "grid") {
860
+ this.mapComponent.map = new GridMap(this.mapComponent.width, this.mapComponent.height, {
861
+ allowDiagonal: this.mapComponent.allowDiagonal,
862
+ avoidCorners: this.mapComponent.avoidCorners
863
+ });
864
+ }
865
+ }
866
+ if (!this.mapComponent.pathfinder && this.mapComponent.map) {
867
+ this.mapComponent.pathfinder = new IncrementalAStarPathfinder(this.mapComponent.map, {
868
+ enableCache: this.mapComponent.enableCache,
869
+ cacheConfig: {
870
+ maxEntries: this.mapComponent.cacheMaxEntries,
871
+ ttlMs: this.mapComponent.cacheTtlMs
872
+ }
873
+ });
874
+ }
875
+ if (!this.mapComponent.smoother && this.mapComponent.enableSmoothing) {
876
+ switch (this.mapComponent.smoothingType) {
877
+ case "catmullrom":
878
+ this.mapComponent.smoother = new CatmullRomSmoother();
879
+ break;
880
+ case "combined":
881
+ this.mapComponent.smoother = new CombinedSmoother();
882
+ break;
883
+ case "los":
884
+ default:
885
+ this.mapComponent.smoother = new LineOfSightSmoother();
886
+ break;
887
+ }
888
+ }
889
+ this.mapComponent.initialized = true;
890
+ }
891
+ /**
892
+ * @zh 构建代理优先级队列
893
+ * @en Build agent priority queue
894
+ */
895
+ buildAgentQueue(entities) {
896
+ this.agentQueue.length = 0;
897
+ for (const entity of entities) {
898
+ const agent = entity.getComponent(PathfindingAgentComponent);
899
+ if (!agent) continue;
900
+ if (!agent.hasRequest && (agent.state === PathfindingState.Idle || agent.state === PathfindingState.Completed || agent.state === PathfindingState.Cancelled)) {
901
+ continue;
902
+ }
903
+ this.agentQueue.push({
904
+ entity,
905
+ component: agent
906
+ });
907
+ }
908
+ this.agentQueue.sort((a, b) => a.component.priority - b.component.priority);
909
+ }
910
+ /**
911
+ * @zh 使用预算处理代理
912
+ * @en Process agents with budget
913
+ */
914
+ processAgentsWithBudget() {
915
+ const pathfinder = this.mapComponent.pathfinder;
916
+ const maxAgents = this.mapComponent.maxAgentsPerFrame;
917
+ let remainingBudget = this.mapComponent.iterationsBudget;
918
+ let agentsProcessed = 0;
919
+ for (const { component: agent } of this.agentQueue) {
920
+ if (agentsProcessed >= maxAgents || remainingBudget <= 0) {
921
+ break;
922
+ }
923
+ if (agent.hasRequest && agent.state === PathfindingState.Idle) {
924
+ this.startNewRequest(agent, pathfinder);
925
+ }
926
+ if (agent.state === PathfindingState.InProgress) {
927
+ const iterations = Math.min(agent.maxIterationsPerFrame, remainingBudget);
928
+ const progress = pathfinder.step(agent.currentRequestId, iterations);
929
+ this.updateAgentFromProgress(agent, progress, pathfinder);
930
+ remainingBudget -= progress.nodesSearched;
931
+ this.mapComponent.iterationsUsedThisFrame += progress.nodesSearched;
932
+ }
933
+ agentsProcessed++;
934
+ }
935
+ this.mapComponent.agentsProcessedThisFrame = agentsProcessed;
936
+ }
937
+ /**
938
+ * @zh 启动新的寻路请求
939
+ * @en Start new pathfinding request
940
+ */
941
+ startNewRequest(agent, pathfinder) {
942
+ if (agent.currentRequestId >= 0) {
943
+ pathfinder.cancel(agent.currentRequestId);
944
+ pathfinder.cleanup(agent.currentRequestId);
945
+ }
946
+ const request = pathfinder.requestPath(agent.x, agent.y, agent.targetX, agent.targetY, {
947
+ priority: agent.priority
948
+ });
949
+ agent.currentRequestId = request.id;
950
+ agent.state = PathfindingState.InProgress;
951
+ agent.hasRequest = false;
952
+ agent.progress = 0;
953
+ agent.path = [];
954
+ agent.pathIndex = 0;
955
+ this.mapComponent.activeRequests++;
956
+ }
957
+ /**
958
+ * @zh 从进度更新代理状态
959
+ * @en Update agent state from progress
960
+ */
961
+ updateAgentFromProgress(agent, progress, pathfinder) {
962
+ agent.state = progress.state;
963
+ agent.progress = progress.estimatedProgress;
964
+ agent.onPathProgress?.(progress.estimatedProgress);
965
+ if (progress.state === PathfindingState.Completed) {
966
+ const result = pathfinder.getResult(agent.currentRequestId);
967
+ if (result && result.found) {
968
+ const smoother = this.mapComponent?.smoother;
969
+ const map = this.mapComponent?.map;
970
+ if (smoother && map && this.mapComponent?.enableSmoothing) {
971
+ agent.path = smoother.smooth(result.path, map);
972
+ } else {
973
+ agent.path = [
974
+ ...result.path
975
+ ];
976
+ }
977
+ agent.pathIndex = 0;
978
+ agent.pathCost = result.cost;
979
+ agent.onPathComplete?.(true, agent.path);
980
+ } else {
981
+ agent.path = [];
982
+ agent.state = PathfindingState.Failed;
983
+ agent.onPathComplete?.(false, []);
984
+ }
985
+ pathfinder.cleanup(agent.currentRequestId);
986
+ this.mapComponent.activeRequests--;
987
+ } else if (progress.state === PathfindingState.Failed) {
988
+ agent.path = [];
989
+ agent.onPathComplete?.(false, []);
990
+ pathfinder.cleanup(agent.currentRequestId);
991
+ this.mapComponent.activeRequests--;
992
+ }
993
+ }
994
+ /**
995
+ * @zh 周期性验证路径有效性
996
+ * @en Periodically validate path validity
997
+ */
998
+ validatePaths(entities) {
999
+ const map = this.mapComponent?.map;
1000
+ if (!map) return;
1001
+ for (const entity of entities) {
1002
+ const agent = entity.getComponent(PathfindingAgentComponent);
1003
+ if (!agent || !agent.enableDynamicReplan) continue;
1004
+ if (agent.path.length === 0 || agent.isPathComplete()) continue;
1005
+ if (this.frameCounter - agent.lastValidationFrame < agent.validationInterval) {
1006
+ continue;
1007
+ }
1008
+ agent.lastValidationFrame = this.frameCounter;
1009
+ const checkEnd = Math.min(agent.pathIndex + agent.lookaheadDistance, agent.path.length);
1010
+ const result = this.pathValidator.validatePath(agent.path, agent.pathIndex, checkEnd, map);
1011
+ if (!result.valid) {
1012
+ agent.x = agent.path[agent.pathIndex]?.x ?? agent.x;
1013
+ agent.y = agent.path[agent.pathIndex]?.y ?? agent.y;
1014
+ agent.requestPathTo(agent.targetX, agent.targetY);
1015
+ }
1016
+ }
1017
+ }
1018
+ };
1019
+ __name(_PathfindingSystem, "PathfindingSystem");
1020
+ var PathfindingSystem = _PathfindingSystem;
1021
+ PathfindingSystem = _ts_decorate3([
1022
+ ECSSystem("Pathfinding", {
1023
+ updateOrder: 0
1024
+ }),
1025
+ _ts_metadata3("design:type", Function),
1026
+ _ts_metadata3("design:paramtypes", [])
1027
+ ], PathfindingSystem);
1028
+ export {
1029
+ PathfindingAgentComponent,
1030
+ PathfindingMapComponent,
1031
+ PathfindingSystem
1032
+ };
1033
+ //# sourceMappingURL=ecs.js.map