@esengine/pathfinding 12.1.2 → 13.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/dist/ecs.js CHANGED
@@ -1,11 +1,15 @@
1
1
  import {
2
2
  CatmullRomSmoother,
3
3
  CombinedSmoother,
4
+ DEFAULT_AGENT_PARAMS,
5
+ DEFAULT_ORCA_CONFIG,
4
6
  GridMap,
5
7
  IncrementalAStarPathfinder,
6
8
  LineOfSightSmoother,
7
- PathValidator
8
- } from "./chunk-TPT7Q3E3.js";
9
+ PathValidator,
10
+ createKDTree,
11
+ createORCASolver
12
+ } from "./chunk-OA7ZZQMH.js";
9
13
  import {
10
14
  PathfindingState,
11
15
  __name,
@@ -1025,7 +1029,688 @@ PathfindingSystem = _ts_decorate3([
1025
1029
  _ts_metadata3("design:type", Function),
1026
1030
  _ts_metadata3("design:paramtypes", [])
1027
1031
  ], PathfindingSystem);
1032
+
1033
+ // src/ecs/AvoidanceAgentComponent.ts
1034
+ import { Component as Component3, ECSComponent as ECSComponent3, Serializable as Serializable3, Serialize as Serialize3, Property as Property3 } from "@esengine/ecs-framework";
1035
+ function _ts_decorate4(decorators, target, key, desc) {
1036
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1037
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1038
+ 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;
1039
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1040
+ }
1041
+ __name(_ts_decorate4, "_ts_decorate");
1042
+ function _ts_metadata4(k, v) {
1043
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1044
+ }
1045
+ __name(_ts_metadata4, "_ts_metadata");
1046
+ var _AvoidanceAgentComponent = class _AvoidanceAgentComponent extends Component3 {
1047
+ constructor() {
1048
+ super(...arguments);
1049
+ // =========================================================================
1050
+ // 物理属性 | Physical Properties
1051
+ // =========================================================================
1052
+ /**
1053
+ * @zh 代理半径
1054
+ * @en Agent radius
1055
+ *
1056
+ * @zh 用于碰撞检测和避让计算
1057
+ * @en Used for collision detection and avoidance computation
1058
+ */
1059
+ __publicField(this, "radius", DEFAULT_AGENT_PARAMS.radius);
1060
+ /**
1061
+ * @zh 最大速度
1062
+ * @en Maximum speed
1063
+ */
1064
+ __publicField(this, "maxSpeed", DEFAULT_AGENT_PARAMS.maxSpeed);
1065
+ // =========================================================================
1066
+ // ORCA 参数 | ORCA Parameters
1067
+ // =========================================================================
1068
+ /**
1069
+ * @zh 邻居检测距离
1070
+ * @en Neighbor detection distance
1071
+ *
1072
+ * @zh 只考虑此范围内的其他代理
1073
+ * @en Only considers other agents within this range
1074
+ */
1075
+ __publicField(this, "neighborDist", DEFAULT_AGENT_PARAMS.neighborDist);
1076
+ /**
1077
+ * @zh 最大邻居数量
1078
+ * @en Maximum number of neighbors to consider
1079
+ *
1080
+ * @zh 限制计算量,优先考虑最近的邻居
1081
+ * @en Limits computation, prioritizes closest neighbors
1082
+ */
1083
+ __publicField(this, "maxNeighbors", DEFAULT_AGENT_PARAMS.maxNeighbors);
1084
+ /**
1085
+ * @zh 代理避让时间视野(秒)
1086
+ * @en Time horizon for agent avoidance (seconds)
1087
+ *
1088
+ * @zh 更大的值会让代理更早开始避让,但可能导致过于保守
1089
+ * @en Larger values make agents start avoiding earlier, but may be too conservative
1090
+ */
1091
+ __publicField(this, "timeHorizon", DEFAULT_AGENT_PARAMS.timeHorizon);
1092
+ /**
1093
+ * @zh 障碍物避让时间视野(秒)
1094
+ * @en Time horizon for obstacle avoidance (seconds)
1095
+ */
1096
+ __publicField(this, "timeHorizonObst", DEFAULT_AGENT_PARAMS.timeHorizonObst);
1097
+ // =========================================================================
1098
+ // 位置和速度(运行时状态)| Position & Velocity (Runtime State)
1099
+ // =========================================================================
1100
+ /**
1101
+ * @zh 当前位置 X
1102
+ * @en Current position X
1103
+ *
1104
+ * @zh 如果实体有 Transform 组件,系统会自动同步
1105
+ * @en If entity has Transform component, system will sync automatically
1106
+ */
1107
+ __publicField(this, "positionX", 0);
1108
+ /**
1109
+ * @zh 当前位置 Y
1110
+ * @en Current position Y
1111
+ */
1112
+ __publicField(this, "positionY", 0);
1113
+ /**
1114
+ * @zh 当前速度 X
1115
+ * @en Current velocity X
1116
+ */
1117
+ __publicField(this, "velocityX", 0);
1118
+ /**
1119
+ * @zh 当前速度 Y
1120
+ * @en Current velocity Y
1121
+ */
1122
+ __publicField(this, "velocityY", 0);
1123
+ /**
1124
+ * @zh 首选速度 X(通常指向目标方向)
1125
+ * @en Preferred velocity X (usually towards target)
1126
+ */
1127
+ __publicField(this, "preferredVelocityX", 0);
1128
+ /**
1129
+ * @zh 首选速度 Y
1130
+ * @en Preferred velocity Y
1131
+ */
1132
+ __publicField(this, "preferredVelocityY", 0);
1133
+ /**
1134
+ * @zh ORCA 计算的新速度 X
1135
+ * @en New velocity X computed by ORCA
1136
+ */
1137
+ __publicField(this, "newVelocityX", 0);
1138
+ /**
1139
+ * @zh ORCA 计算的新速度 Y
1140
+ * @en New velocity Y computed by ORCA
1141
+ */
1142
+ __publicField(this, "newVelocityY", 0);
1143
+ // =========================================================================
1144
+ // 配置选项 | Configuration Options
1145
+ // =========================================================================
1146
+ /**
1147
+ * @zh 是否启用避让
1148
+ * @en Whether avoidance is enabled
1149
+ */
1150
+ __publicField(this, "enabled", true);
1151
+ /**
1152
+ * @zh 是否自动应用新速度
1153
+ * @en Whether to automatically apply new velocity
1154
+ *
1155
+ * @zh 如果为 true,系统会在计算后自动将 newVelocity 赋值给 velocity
1156
+ * @en If true, system will automatically assign newVelocity to velocity after computation
1157
+ */
1158
+ __publicField(this, "autoApplyVelocity", true);
1159
+ }
1160
+ // =========================================================================
1161
+ // 公共方法 | Public Methods
1162
+ // =========================================================================
1163
+ /**
1164
+ * @zh 设置位置
1165
+ * @en Set position
1166
+ */
1167
+ setPosition(x, y) {
1168
+ this.positionX = x;
1169
+ this.positionY = y;
1170
+ }
1171
+ /**
1172
+ * @zh 设置当前速度
1173
+ * @en Set current velocity
1174
+ */
1175
+ setVelocity(x, y) {
1176
+ this.velocityX = x;
1177
+ this.velocityY = y;
1178
+ }
1179
+ /**
1180
+ * @zh 设置首选速度
1181
+ * @en Set preferred velocity
1182
+ */
1183
+ setPreferredVelocity(x, y) {
1184
+ this.preferredVelocityX = x;
1185
+ this.preferredVelocityY = y;
1186
+ }
1187
+ /**
1188
+ * @zh 设置首选速度朝向目标
1189
+ * @en Set preferred velocity towards target
1190
+ *
1191
+ * @param targetX - @zh 目标 X @en Target X
1192
+ * @param targetY - @zh 目标 Y @en Target Y
1193
+ * @param currentX - @zh 当前 X(可选,默认使用 positionX)@en Current X (optional, defaults to positionX)
1194
+ * @param currentY - @zh 当前 Y(可选,默认使用 positionY)@en Current Y (optional, defaults to positionY)
1195
+ */
1196
+ setPreferredVelocityTowards(targetX, targetY, currentX, currentY) {
1197
+ const x = currentX ?? this.positionX;
1198
+ const y = currentY ?? this.positionY;
1199
+ const dx = targetX - x;
1200
+ const dy = targetY - y;
1201
+ const dist = Math.sqrt(dx * dx + dy * dy);
1202
+ if (dist > 1e-4) {
1203
+ const speed = Math.min(this.maxSpeed, dist);
1204
+ this.preferredVelocityX = dx / dist * speed;
1205
+ this.preferredVelocityY = dy / dist * speed;
1206
+ } else {
1207
+ this.preferredVelocityX = 0;
1208
+ this.preferredVelocityY = 0;
1209
+ }
1210
+ }
1211
+ /**
1212
+ * @zh 应用 ORCA 计算的新速度
1213
+ * @en Apply new velocity computed by ORCA
1214
+ */
1215
+ applyNewVelocity() {
1216
+ this.velocityX = this.newVelocityX;
1217
+ this.velocityY = this.newVelocityY;
1218
+ }
1219
+ /**
1220
+ * @zh 获取新速度的长度
1221
+ * @en Get length of new velocity
1222
+ */
1223
+ getNewSpeed() {
1224
+ return Math.sqrt(this.newVelocityX * this.newVelocityX + this.newVelocityY * this.newVelocityY);
1225
+ }
1226
+ /**
1227
+ * @zh 获取当前速度的长度
1228
+ * @en Get length of current velocity
1229
+ */
1230
+ getCurrentSpeed() {
1231
+ return Math.sqrt(this.velocityX * this.velocityX + this.velocityY * this.velocityY);
1232
+ }
1233
+ /**
1234
+ * @zh 停止代理
1235
+ * @en Stop the agent
1236
+ */
1237
+ stop() {
1238
+ this.velocityX = 0;
1239
+ this.velocityY = 0;
1240
+ this.preferredVelocityX = 0;
1241
+ this.preferredVelocityY = 0;
1242
+ this.newVelocityX = 0;
1243
+ this.newVelocityY = 0;
1244
+ }
1245
+ /**
1246
+ * @zh 重置组件状态
1247
+ * @en Reset component state
1248
+ */
1249
+ reset() {
1250
+ this.positionX = 0;
1251
+ this.positionY = 0;
1252
+ this.velocityX = 0;
1253
+ this.velocityY = 0;
1254
+ this.preferredVelocityX = 0;
1255
+ this.preferredVelocityY = 0;
1256
+ this.newVelocityX = 0;
1257
+ this.newVelocityY = 0;
1258
+ }
1259
+ /**
1260
+ * @zh 组件从实体移除时调用
1261
+ * @en Called when component is removed from entity
1262
+ */
1263
+ onRemovedFromEntity() {
1264
+ this.reset();
1265
+ }
1266
+ };
1267
+ __name(_AvoidanceAgentComponent, "AvoidanceAgentComponent");
1268
+ var AvoidanceAgentComponent = _AvoidanceAgentComponent;
1269
+ _ts_decorate4([
1270
+ Serialize3(),
1271
+ Property3({
1272
+ type: "number",
1273
+ label: "Radius",
1274
+ min: 0.1,
1275
+ max: 10
1276
+ }),
1277
+ _ts_metadata4("design:type", Number)
1278
+ ], AvoidanceAgentComponent.prototype, "radius", void 0);
1279
+ _ts_decorate4([
1280
+ Serialize3(),
1281
+ Property3({
1282
+ type: "number",
1283
+ label: "Max Speed",
1284
+ min: 0.1,
1285
+ max: 100
1286
+ }),
1287
+ _ts_metadata4("design:type", Number)
1288
+ ], AvoidanceAgentComponent.prototype, "maxSpeed", void 0);
1289
+ _ts_decorate4([
1290
+ Serialize3(),
1291
+ Property3({
1292
+ type: "number",
1293
+ label: "Neighbor Dist",
1294
+ min: 1,
1295
+ max: 100
1296
+ }),
1297
+ _ts_metadata4("design:type", Number)
1298
+ ], AvoidanceAgentComponent.prototype, "neighborDist", void 0);
1299
+ _ts_decorate4([
1300
+ Serialize3(),
1301
+ Property3({
1302
+ type: "number",
1303
+ label: "Max Neighbors",
1304
+ min: 1,
1305
+ max: 50
1306
+ }),
1307
+ _ts_metadata4("design:type", Number)
1308
+ ], AvoidanceAgentComponent.prototype, "maxNeighbors", void 0);
1309
+ _ts_decorate4([
1310
+ Serialize3(),
1311
+ Property3({
1312
+ type: "number",
1313
+ label: "Time Horizon",
1314
+ min: 0.1,
1315
+ max: 10
1316
+ }),
1317
+ _ts_metadata4("design:type", Number)
1318
+ ], AvoidanceAgentComponent.prototype, "timeHorizon", void 0);
1319
+ _ts_decorate4([
1320
+ Serialize3(),
1321
+ Property3({
1322
+ type: "number",
1323
+ label: "Time Horizon Obst",
1324
+ min: 0.1,
1325
+ max: 10
1326
+ }),
1327
+ _ts_metadata4("design:type", Number)
1328
+ ], AvoidanceAgentComponent.prototype, "timeHorizonObst", void 0);
1329
+ _ts_decorate4([
1330
+ Serialize3(),
1331
+ Property3({
1332
+ type: "boolean",
1333
+ label: "Enabled"
1334
+ }),
1335
+ _ts_metadata4("design:type", Boolean)
1336
+ ], AvoidanceAgentComponent.prototype, "enabled", void 0);
1337
+ _ts_decorate4([
1338
+ Serialize3(),
1339
+ Property3({
1340
+ type: "boolean",
1341
+ label: "Auto Apply"
1342
+ }),
1343
+ _ts_metadata4("design:type", Boolean)
1344
+ ], AvoidanceAgentComponent.prototype, "autoApplyVelocity", void 0);
1345
+ AvoidanceAgentComponent = _ts_decorate4([
1346
+ ECSComponent3("AvoidanceAgent"),
1347
+ Serializable3({
1348
+ version: 1,
1349
+ typeId: "AvoidanceAgent"
1350
+ })
1351
+ ], AvoidanceAgentComponent);
1352
+
1353
+ // src/ecs/AvoidanceWorldComponent.ts
1354
+ import { Component as Component4, ECSComponent as ECSComponent4, Serializable as Serializable4, Serialize as Serialize4, Property as Property4 } from "@esengine/ecs-framework";
1355
+ function _ts_decorate5(decorators, target, key, desc) {
1356
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1357
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1358
+ 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;
1359
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1360
+ }
1361
+ __name(_ts_decorate5, "_ts_decorate");
1362
+ function _ts_metadata5(k, v) {
1363
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1364
+ }
1365
+ __name(_ts_metadata5, "_ts_metadata");
1366
+ var _AvoidanceWorldComponent = class _AvoidanceWorldComponent extends Component4 {
1367
+ constructor() {
1368
+ super(...arguments);
1369
+ // =========================================================================
1370
+ // ORCA 配置 | ORCA Configuration
1371
+ // =========================================================================
1372
+ /**
1373
+ * @zh 默认时间视野(代理)
1374
+ * @en Default time horizon for agents
1375
+ */
1376
+ __publicField(this, "defaultTimeHorizon", DEFAULT_ORCA_CONFIG.defaultTimeHorizon);
1377
+ /**
1378
+ * @zh 默认时间视野(障碍物)
1379
+ * @en Default time horizon for obstacles
1380
+ */
1381
+ __publicField(this, "defaultTimeHorizonObst", DEFAULT_ORCA_CONFIG.defaultTimeHorizonObst);
1382
+ /**
1383
+ * @zh 时间步长
1384
+ * @en Time step
1385
+ */
1386
+ __publicField(this, "timeStep", DEFAULT_ORCA_CONFIG.timeStep);
1387
+ // =========================================================================
1388
+ // 运行时实例(不序列化)| Runtime Instances (not serialized)
1389
+ // =========================================================================
1390
+ /**
1391
+ * @zh ORCA 求解器实例
1392
+ * @en ORCA solver instance
1393
+ */
1394
+ __publicField(this, "solver", null);
1395
+ /**
1396
+ * @zh KD-Tree 实例
1397
+ * @en KD-Tree instance
1398
+ */
1399
+ __publicField(this, "kdTree", null);
1400
+ /**
1401
+ * @zh 静态障碍物列表
1402
+ * @en List of static obstacles
1403
+ */
1404
+ __publicField(this, "obstacles", []);
1405
+ /**
1406
+ * @zh 是否已初始化
1407
+ * @en Whether initialized
1408
+ */
1409
+ __publicField(this, "initialized", false);
1410
+ // =========================================================================
1411
+ // 统计信息 | Statistics
1412
+ // =========================================================================
1413
+ /**
1414
+ * @zh 当前代理数量
1415
+ * @en Current agent count
1416
+ */
1417
+ __publicField(this, "agentCount", 0);
1418
+ /**
1419
+ * @zh 本帧处理的代理数
1420
+ * @en Agents processed this frame
1421
+ */
1422
+ __publicField(this, "agentsProcessedThisFrame", 0);
1423
+ /**
1424
+ * @zh 本帧 ORCA 计算耗时(毫秒)
1425
+ * @en ORCA computation time this frame (ms)
1426
+ */
1427
+ __publicField(this, "computeTimeMs", 0);
1428
+ }
1429
+ // =========================================================================
1430
+ // 公共方法 | Public Methods
1431
+ // =========================================================================
1432
+ /**
1433
+ * @zh 获取 ORCA 配置
1434
+ * @en Get ORCA configuration
1435
+ */
1436
+ getConfig() {
1437
+ return {
1438
+ defaultTimeHorizon: this.defaultTimeHorizon,
1439
+ defaultTimeHorizonObst: this.defaultTimeHorizonObst,
1440
+ timeStep: this.timeStep
1441
+ };
1442
+ }
1443
+ /**
1444
+ * @zh 添加静态障碍物
1445
+ * @en Add static obstacle
1446
+ *
1447
+ * @param obstacle - @zh 障碍物(顶点列表,逆时针顺序)@en Obstacle (vertex list, counter-clockwise)
1448
+ */
1449
+ addObstacle(obstacle) {
1450
+ this.obstacles.push(obstacle);
1451
+ }
1452
+ /**
1453
+ * @zh 添加矩形障碍物
1454
+ * @en Add rectangular obstacle
1455
+ *
1456
+ * @param x - @zh 左下角 X @en Bottom-left X
1457
+ * @param y - @zh 左下角 Y @en Bottom-left Y
1458
+ * @param width - @zh 宽度 @en Width
1459
+ * @param height - @zh 高度 @en Height
1460
+ */
1461
+ addRectObstacle(x, y, width, height) {
1462
+ this.obstacles.push({
1463
+ vertices: [
1464
+ {
1465
+ x,
1466
+ y
1467
+ },
1468
+ {
1469
+ x: x + width,
1470
+ y
1471
+ },
1472
+ {
1473
+ x: x + width,
1474
+ y: y + height
1475
+ },
1476
+ {
1477
+ x,
1478
+ y: y + height
1479
+ }
1480
+ ]
1481
+ });
1482
+ }
1483
+ /**
1484
+ * @zh 移除所有障碍物
1485
+ * @en Remove all obstacles
1486
+ */
1487
+ clearObstacles() {
1488
+ this.obstacles = [];
1489
+ }
1490
+ /**
1491
+ * @zh 重置统计信息
1492
+ * @en Reset statistics
1493
+ */
1494
+ resetStats() {
1495
+ this.agentsProcessedThisFrame = 0;
1496
+ this.computeTimeMs = 0;
1497
+ }
1498
+ /**
1499
+ * @zh 组件从实体移除时调用
1500
+ * @en Called when component is removed from entity
1501
+ */
1502
+ onRemovedFromEntity() {
1503
+ this.solver = null;
1504
+ this.kdTree = null;
1505
+ this.obstacles = [];
1506
+ this.initialized = false;
1507
+ }
1508
+ };
1509
+ __name(_AvoidanceWorldComponent, "AvoidanceWorldComponent");
1510
+ var AvoidanceWorldComponent = _AvoidanceWorldComponent;
1511
+ _ts_decorate5([
1512
+ Serialize4(),
1513
+ Property4({
1514
+ type: "number",
1515
+ label: "Time Horizon",
1516
+ min: 0.1,
1517
+ max: 10
1518
+ }),
1519
+ _ts_metadata5("design:type", Number)
1520
+ ], AvoidanceWorldComponent.prototype, "defaultTimeHorizon", void 0);
1521
+ _ts_decorate5([
1522
+ Serialize4(),
1523
+ Property4({
1524
+ type: "number",
1525
+ label: "Time Horizon Obst",
1526
+ min: 0.1,
1527
+ max: 10
1528
+ }),
1529
+ _ts_metadata5("design:type", Number)
1530
+ ], AvoidanceWorldComponent.prototype, "defaultTimeHorizonObst", void 0);
1531
+ _ts_decorate5([
1532
+ Serialize4(),
1533
+ Property4({
1534
+ type: "number",
1535
+ label: "Time Step",
1536
+ min: 1e-3,
1537
+ max: 0.1
1538
+ }),
1539
+ _ts_metadata5("design:type", Number)
1540
+ ], AvoidanceWorldComponent.prototype, "timeStep", void 0);
1541
+ AvoidanceWorldComponent = _ts_decorate5([
1542
+ ECSComponent4("AvoidanceWorld"),
1543
+ Serializable4({
1544
+ version: 1,
1545
+ typeId: "AvoidanceWorld"
1546
+ })
1547
+ ], AvoidanceWorldComponent);
1548
+
1549
+ // src/ecs/LocalAvoidanceSystem.ts
1550
+ import { EntitySystem as EntitySystem2, Matcher as Matcher2, ECSSystem as ECSSystem2 } from "@esengine/ecs-framework";
1551
+ function _ts_decorate6(decorators, target, key, desc) {
1552
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1553
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1554
+ 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;
1555
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1556
+ }
1557
+ __name(_ts_decorate6, "_ts_decorate");
1558
+ function _ts_metadata6(k, v) {
1559
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1560
+ }
1561
+ __name(_ts_metadata6, "_ts_metadata");
1562
+ var _LocalAvoidanceSystem = class _LocalAvoidanceSystem extends EntitySystem2 {
1563
+ constructor() {
1564
+ super(Matcher2.all(AvoidanceAgentComponent));
1565
+ __publicField(this, "worldEntity", null);
1566
+ __publicField(this, "worldComponent", null);
1567
+ __publicField(this, "solver", null);
1568
+ __publicField(this, "kdTree", null);
1569
+ }
1570
+ /**
1571
+ * @zh 系统初始化
1572
+ * @en System initialization
1573
+ */
1574
+ onInitialize() {
1575
+ this.findWorldEntity();
1576
+ this.initializeSolver();
1577
+ }
1578
+ /**
1579
+ * @zh 系统激活时调用
1580
+ * @en Called when system is enabled
1581
+ */
1582
+ onEnable() {
1583
+ this.findWorldEntity();
1584
+ }
1585
+ /**
1586
+ * @zh 处理实体
1587
+ * @en Process entities
1588
+ */
1589
+ process(entities) {
1590
+ if (entities.length === 0) return;
1591
+ if (!this.solver) {
1592
+ this.initializeSolver();
1593
+ }
1594
+ const startTime = performance.now();
1595
+ const agents = this.collectAgentData(entities);
1596
+ this.kdTree.build(agents);
1597
+ const obstacles = this.worldComponent?.obstacles ?? [];
1598
+ const deltaTime = this.worldComponent?.timeStep ?? 1 / 60;
1599
+ for (let i = 0; i < entities.length; i++) {
1600
+ const entity = entities[i];
1601
+ const component = entity.getComponent(AvoidanceAgentComponent);
1602
+ if (!component.enabled) continue;
1603
+ const agent = agents[i];
1604
+ const neighborResults = this.kdTree.queryNeighbors(agent.position, agent.neighborDist, agent.maxNeighbors, agent.id);
1605
+ const neighbors = neighborResults.map((r) => r.agent);
1606
+ const newVelocity = this.solver.computeNewVelocity(agent, neighbors, obstacles, deltaTime);
1607
+ component.newVelocityX = newVelocity.x;
1608
+ component.newVelocityY = newVelocity.y;
1609
+ if (component.autoApplyVelocity) {
1610
+ component.applyNewVelocity();
1611
+ }
1612
+ }
1613
+ const endTime = performance.now();
1614
+ if (this.worldComponent) {
1615
+ this.worldComponent.agentCount = entities.length;
1616
+ this.worldComponent.agentsProcessedThisFrame = entities.length;
1617
+ this.worldComponent.computeTimeMs = endTime - startTime;
1618
+ }
1619
+ }
1620
+ // =========================================================================
1621
+ // 私有方法 | Private Methods
1622
+ // =========================================================================
1623
+ /**
1624
+ * @zh 查找世界实体
1625
+ * @en Find world entity
1626
+ */
1627
+ findWorldEntity() {
1628
+ if (!this.scene) return;
1629
+ const entities = this.scene.entities.findEntitiesWithComponent(AvoidanceWorldComponent);
1630
+ if (entities.length > 0) {
1631
+ const entity = entities[0];
1632
+ const worldComp = entity.getComponent(AvoidanceWorldComponent);
1633
+ if (worldComp) {
1634
+ this.worldEntity = entity;
1635
+ this.worldComponent = worldComp;
1636
+ if (this.solver && !worldComp.solver) {
1637
+ worldComp.solver = this.solver;
1638
+ }
1639
+ if (this.kdTree && !worldComp.kdTree) {
1640
+ worldComp.kdTree = this.kdTree;
1641
+ }
1642
+ worldComp.initialized = true;
1643
+ }
1644
+ }
1645
+ }
1646
+ /**
1647
+ * @zh 初始化求解器
1648
+ * @en Initialize solver
1649
+ */
1650
+ initializeSolver() {
1651
+ const config = this.worldComponent?.getConfig();
1652
+ this.solver = createORCASolver(config);
1653
+ this.kdTree = createKDTree();
1654
+ if (this.worldComponent) {
1655
+ this.worldComponent.solver = this.solver;
1656
+ this.worldComponent.kdTree = this.kdTree;
1657
+ }
1658
+ }
1659
+ /**
1660
+ * @zh 收集代理数据
1661
+ * @en Collect agent data
1662
+ */
1663
+ collectAgentData(entities) {
1664
+ const agents = [];
1665
+ for (const entity of entities) {
1666
+ const avoidance = entity.getComponent(AvoidanceAgentComponent);
1667
+ const pathAgent = entity.getComponent(PathfindingAgentComponent);
1668
+ if (pathAgent) {
1669
+ avoidance.positionX = pathAgent.x;
1670
+ avoidance.positionY = pathAgent.y;
1671
+ const waypoint = pathAgent.getNextWaypoint();
1672
+ if (waypoint && avoidance.preferredVelocityX === 0 && avoidance.preferredVelocityY === 0) {
1673
+ avoidance.setPreferredVelocityTowards(waypoint.x, waypoint.y);
1674
+ }
1675
+ }
1676
+ agents.push({
1677
+ id: entity.id,
1678
+ position: {
1679
+ x: avoidance.positionX,
1680
+ y: avoidance.positionY
1681
+ },
1682
+ velocity: {
1683
+ x: avoidance.velocityX,
1684
+ y: avoidance.velocityY
1685
+ },
1686
+ preferredVelocity: {
1687
+ x: avoidance.preferredVelocityX,
1688
+ y: avoidance.preferredVelocityY
1689
+ },
1690
+ radius: avoidance.radius,
1691
+ maxSpeed: avoidance.maxSpeed,
1692
+ neighborDist: avoidance.neighborDist,
1693
+ maxNeighbors: avoidance.maxNeighbors,
1694
+ timeHorizon: avoidance.timeHorizon,
1695
+ timeHorizonObst: avoidance.timeHorizonObst
1696
+ });
1697
+ }
1698
+ return agents;
1699
+ }
1700
+ };
1701
+ __name(_LocalAvoidanceSystem, "LocalAvoidanceSystem");
1702
+ var LocalAvoidanceSystem = _LocalAvoidanceSystem;
1703
+ LocalAvoidanceSystem = _ts_decorate6([
1704
+ ECSSystem2("LocalAvoidance", {
1705
+ updateOrder: 50
1706
+ }),
1707
+ _ts_metadata6("design:type", Function),
1708
+ _ts_metadata6("design:paramtypes", [])
1709
+ ], LocalAvoidanceSystem);
1028
1710
  export {
1711
+ AvoidanceAgentComponent,
1712
+ AvoidanceWorldComponent,
1713
+ LocalAvoidanceSystem,
1029
1714
  PathfindingAgentComponent,
1030
1715
  PathfindingMapComponent,
1031
1716
  PathfindingSystem