@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/KDTree-2rs2EXvm.d.ts +407 -0
- package/dist/LinearProgram-DyD3pI6v.d.ts +56 -0
- package/dist/avoidance.d.ts +31 -0
- package/dist/avoidance.js +31 -0
- package/dist/avoidance.js.map +1 -0
- package/dist/chunk-JTZP55BJ.js +935 -0
- package/dist/chunk-JTZP55BJ.js.map +1 -0
- package/dist/chunk-KEYTX37K.js +1 -0
- package/dist/chunk-KEYTX37K.js.map +1 -0
- package/dist/chunk-T626JPC7.js +10 -0
- package/dist/chunk-T626JPC7.js.map +1 -0
- package/dist/{chunk-TPT7Q3E3.js → chunk-VNC2YAAL.js} +5 -3
- package/dist/{chunk-TPT7Q3E3.js.map → chunk-VNC2YAAL.js.map} +1 -1
- package/dist/{chunk-GTFFYRZM.js → chunk-YKA3PWU3.js} +1 -8
- package/dist/{chunk-GTFFYRZM.js.map → chunk-YKA3PWU3.js.map} +1 -1
- package/dist/ecs.d.ts +382 -1
- package/dist/ecs.js +692 -3
- package/dist/ecs.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +23 -4
- package/dist/index.js.map +1 -1
- package/dist/nodes.js +4 -2
- package/dist/nodes.js.map +1 -1
- package/package.json +8 -4
package/dist/ecs.js
CHANGED
|
@@ -5,12 +5,20 @@ import {
|
|
|
5
5
|
IncrementalAStarPathfinder,
|
|
6
6
|
LineOfSightSmoother,
|
|
7
7
|
PathValidator
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
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
|