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