@esengine/pathfinding 13.2.0 → 13.3.1
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 → CollisionResolver-CSgWsegP.d.ts} +122 -86
- package/dist/FlowController-BztOzQsW.d.ts +2781 -0
- package/dist/KDTree-BRpn7O8K.d.ts +216 -0
- package/dist/avoidance.d.ts +26 -4
- package/dist/avoidance.js +10 -2
- package/dist/{chunk-JTZP55BJ.js → chunk-3VEX32JO.js} +385 -9
- package/dist/chunk-3VEX32JO.js.map +1 -0
- package/dist/chunk-H5EFZBBT.js +1 -0
- package/dist/chunk-ZYGBA7VK.js +3831 -0
- package/dist/chunk-ZYGBA7VK.js.map +1 -0
- package/dist/ecs.d.ts +440 -647
- package/dist/ecs.js +1020 -1399
- package/dist/ecs.js.map +1 -1
- package/dist/index.d.ts +158 -711
- package/dist/index.js +1353 -1739
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/IIncrementalPathfinding-3qs7e_pO.d.ts +0 -450
- package/dist/LinearProgram-DyD3pI6v.d.ts +0 -56
- package/dist/chunk-JTZP55BJ.js.map +0 -1
- package/dist/chunk-KEYTX37K.js +0 -1
- package/dist/chunk-VNC2YAAL.js +0 -1650
- package/dist/chunk-VNC2YAAL.js.map +0 -1
- /package/dist/{chunk-KEYTX37K.js.map → chunk-H5EFZBBT.js.map} +0 -0
|
@@ -8,7 +8,8 @@ var DEFAULT_ORCA_CONFIG = {
|
|
|
8
8
|
defaultTimeHorizon: 2,
|
|
9
9
|
defaultTimeHorizonObst: 1,
|
|
10
10
|
timeStep: 1 / 60,
|
|
11
|
-
epsilon: 1e-5
|
|
11
|
+
epsilon: 1e-5,
|
|
12
|
+
yAxisDown: false
|
|
12
13
|
};
|
|
13
14
|
var DEFAULT_AGENT_PARAMS = {
|
|
14
15
|
radius: 0.5,
|
|
@@ -175,6 +176,9 @@ function linearProgram3(lines, numObstLines, beginLine, radius, result) {
|
|
|
175
176
|
if (linearProgram2(projLines, radius, optVelocity, true, result) < projLines.length) {
|
|
176
177
|
result.copy(tempResult);
|
|
177
178
|
}
|
|
179
|
+
if (!verifyObstacleConstraints(lines, numObstLines, result)) {
|
|
180
|
+
result.copy(tempResult);
|
|
181
|
+
}
|
|
178
182
|
distance = det(lines[i].direction, {
|
|
179
183
|
x: lines[i].point.x - result.x,
|
|
180
184
|
y: lines[i].point.y - result.y
|
|
@@ -183,13 +187,38 @@ function linearProgram3(lines, numObstLines, beginLine, radius, result) {
|
|
|
183
187
|
}
|
|
184
188
|
}
|
|
185
189
|
__name(linearProgram3, "linearProgram3");
|
|
190
|
+
function verifyObstacleConstraints(lines, numObstLines, velocity) {
|
|
191
|
+
for (let i = 0; i < numObstLines; i++) {
|
|
192
|
+
const line = lines[i];
|
|
193
|
+
const detVal = det(line.direction, {
|
|
194
|
+
x: line.point.x - velocity.x,
|
|
195
|
+
y: line.point.y - velocity.y
|
|
196
|
+
});
|
|
197
|
+
if (detVal > EPSILON) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
__name(verifyObstacleConstraints, "verifyObstacleConstraints");
|
|
186
204
|
function solveORCALinearProgram(lines, numObstLines, maxSpeed, preferredVelocity) {
|
|
187
205
|
const result = new Vector2();
|
|
188
206
|
const lineFail = linearProgram2(lines, maxSpeed, preferredVelocity, false, result);
|
|
189
|
-
|
|
207
|
+
let feasible = lineFail >= lines.length;
|
|
208
|
+
let violatedConstraints = 0;
|
|
209
|
+
if (!feasible) {
|
|
190
210
|
linearProgram3(lines, numObstLines, lineFail, maxSpeed, result);
|
|
211
|
+
violatedConstraints = lines.length - lineFail;
|
|
191
212
|
}
|
|
192
|
-
|
|
213
|
+
if (numObstLines > 0 && !verifyObstacleConstraints(lines, numObstLines, result)) {
|
|
214
|
+
feasible = false;
|
|
215
|
+
violatedConstraints = Math.max(violatedConstraints, 1);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
velocity: result,
|
|
219
|
+
feasible,
|
|
220
|
+
violatedConstraints
|
|
221
|
+
};
|
|
193
222
|
}
|
|
194
223
|
__name(solveORCALinearProgram, "solveORCALinearProgram");
|
|
195
224
|
|
|
@@ -251,11 +280,15 @@ function createObstacleVertices(vertices, startId = 0) {
|
|
|
251
280
|
return obstacleVertices;
|
|
252
281
|
}
|
|
253
282
|
__name(createObstacleVertices, "createObstacleVertices");
|
|
254
|
-
function buildObstacleVertices(obstacles) {
|
|
283
|
+
function buildObstacleVertices(obstacles, options = {}) {
|
|
284
|
+
const { yAxisDown = false } = options;
|
|
255
285
|
const allVertices = [];
|
|
256
286
|
let nextId = 0;
|
|
257
287
|
for (const obstacle of obstacles) {
|
|
258
|
-
const
|
|
288
|
+
const ccwVertices = ensureCCW([
|
|
289
|
+
...obstacle.vertices
|
|
290
|
+
], yAxisDown);
|
|
291
|
+
const vertices = createObstacleVertices(ccwVertices, nextId);
|
|
259
292
|
allVertices.push(...vertices);
|
|
260
293
|
nextId += vertices.length;
|
|
261
294
|
}
|
|
@@ -320,11 +353,31 @@ var _ORCASolver = class _ORCASolver {
|
|
|
320
353
|
* @returns @zh 计算得到的新速度 @en Computed new velocity
|
|
321
354
|
*/
|
|
322
355
|
computeNewVelocity(agent, neighbors, obstacles, deltaTime) {
|
|
356
|
+
const result = this.computeNewVelocityWithResult(agent, neighbors, obstacles, deltaTime);
|
|
357
|
+
return result.velocity;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* @zh 计算代理的新速度(带完整结果)
|
|
361
|
+
* @en Compute new velocity for agent (with full result)
|
|
362
|
+
*
|
|
363
|
+
* @param agent - @zh 当前代理 @en Current agent
|
|
364
|
+
* @param neighbors - @zh 邻近代理列表 @en List of neighboring agents
|
|
365
|
+
* @param obstacles - @zh 障碍物列表 @en List of obstacles
|
|
366
|
+
* @param deltaTime - @zh 时间步长 @en Time step
|
|
367
|
+
* @returns @zh 完整求解结果 @en Full solve result
|
|
368
|
+
*/
|
|
369
|
+
computeNewVelocityWithResult(agent, neighbors, obstacles, deltaTime) {
|
|
323
370
|
const orcaLines = [];
|
|
324
|
-
const obstacleVertices = buildObstacleVertices(obstacles
|
|
371
|
+
const obstacleVertices = buildObstacleVertices(obstacles, {
|
|
372
|
+
yAxisDown: this.config.yAxisDown
|
|
373
|
+
});
|
|
325
374
|
const numObstLines = this.createObstacleORCALines(agent, obstacleVertices, orcaLines);
|
|
326
375
|
this.createAgentORCALines(agent, neighbors, deltaTime, orcaLines);
|
|
327
|
-
|
|
376
|
+
const result = solveORCALinearProgram(orcaLines, numObstLines, agent.maxSpeed, agent.preferredVelocity);
|
|
377
|
+
return {
|
|
378
|
+
...result,
|
|
379
|
+
numLines: orcaLines.length
|
|
380
|
+
};
|
|
328
381
|
}
|
|
329
382
|
/**
|
|
330
383
|
* @zh 创建代理间的 ORCA 约束线
|
|
@@ -918,6 +971,325 @@ function createKDTree() {
|
|
|
918
971
|
}
|
|
919
972
|
__name(createKDTree, "createKDTree");
|
|
920
973
|
|
|
974
|
+
// src/avoidance/CollisionResolver.ts
|
|
975
|
+
var EPSILON4 = 1e-5;
|
|
976
|
+
var EMPTY_COLLISION = {
|
|
977
|
+
collided: false,
|
|
978
|
+
penetration: 0,
|
|
979
|
+
normal: {
|
|
980
|
+
x: 0,
|
|
981
|
+
y: 0
|
|
982
|
+
},
|
|
983
|
+
closestPoint: {
|
|
984
|
+
x: 0,
|
|
985
|
+
y: 0
|
|
986
|
+
}
|
|
987
|
+
};
|
|
988
|
+
function closestPointOnSegment(point, segStart, segEnd) {
|
|
989
|
+
const dx = segEnd.x - segStart.x;
|
|
990
|
+
const dy = segEnd.y - segStart.y;
|
|
991
|
+
const lengthSq3 = dx * dx + dy * dy;
|
|
992
|
+
if (lengthSq3 < EPSILON4) {
|
|
993
|
+
return {
|
|
994
|
+
x: segStart.x,
|
|
995
|
+
y: segStart.y
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
const t = Math.max(0, Math.min(1, ((point.x - segStart.x) * dx + (point.y - segStart.y) * dy) / lengthSq3));
|
|
999
|
+
return {
|
|
1000
|
+
x: segStart.x + t * dx,
|
|
1001
|
+
y: segStart.y + t * dy
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
__name(closestPointOnSegment, "closestPointOnSegment");
|
|
1005
|
+
function isPointInPolygon(point, vertices) {
|
|
1006
|
+
let inside = false;
|
|
1007
|
+
const n = vertices.length;
|
|
1008
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
1009
|
+
const xi = vertices[i].x;
|
|
1010
|
+
const yi = vertices[i].y;
|
|
1011
|
+
const xj = vertices[j].x;
|
|
1012
|
+
const yj = vertices[j].y;
|
|
1013
|
+
if (yi > point.y !== yj > point.y && point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi) {
|
|
1014
|
+
inside = !inside;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
return inside;
|
|
1018
|
+
}
|
|
1019
|
+
__name(isPointInPolygon, "isPointInPolygon");
|
|
1020
|
+
function closestPointOnPolygon(point, vertices) {
|
|
1021
|
+
let minDistSq = Infinity;
|
|
1022
|
+
let closestPt = {
|
|
1023
|
+
x: 0,
|
|
1024
|
+
y: 0
|
|
1025
|
+
};
|
|
1026
|
+
let closestEdge = 0;
|
|
1027
|
+
for (let i = 0; i < vertices.length; i++) {
|
|
1028
|
+
const j = (i + 1) % vertices.length;
|
|
1029
|
+
const closest = closestPointOnSegment(point, vertices[i], vertices[j]);
|
|
1030
|
+
const dx = point.x - closest.x;
|
|
1031
|
+
const dy = point.y - closest.y;
|
|
1032
|
+
const distSq = dx * dx + dy * dy;
|
|
1033
|
+
if (distSq < minDistSq) {
|
|
1034
|
+
minDistSq = distSq;
|
|
1035
|
+
closestPt = closest;
|
|
1036
|
+
closestEdge = i;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return {
|
|
1040
|
+
point: closestPt,
|
|
1041
|
+
distanceSq: minDistSq,
|
|
1042
|
+
edgeIndex: closestEdge
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
__name(closestPointOnPolygon, "closestPointOnPolygon");
|
|
1046
|
+
var DEFAULT_COLLISION_CONFIG = {
|
|
1047
|
+
responseFactor: 1,
|
|
1048
|
+
safetyMargin: 0.01
|
|
1049
|
+
};
|
|
1050
|
+
var _CollisionResolver = class _CollisionResolver {
|
|
1051
|
+
constructor(config = {}) {
|
|
1052
|
+
__publicField(this, "config");
|
|
1053
|
+
this.config = {
|
|
1054
|
+
...DEFAULT_COLLISION_CONFIG,
|
|
1055
|
+
...config
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* @zh 检测圆与单个障碍物的碰撞
|
|
1060
|
+
* @en Detect collision between circle and single obstacle
|
|
1061
|
+
*
|
|
1062
|
+
* @param position - @zh 圆心位置 @en Circle center position
|
|
1063
|
+
* @param radius - @zh 圆半径 @en Circle radius
|
|
1064
|
+
* @param obstacle - @zh 障碍物 @en Obstacle
|
|
1065
|
+
* @returns @zh 碰撞结果 @en Collision result
|
|
1066
|
+
*/
|
|
1067
|
+
detectCollision(position, radius, obstacle) {
|
|
1068
|
+
const vertices = obstacle.vertices;
|
|
1069
|
+
if (vertices.length < 3) {
|
|
1070
|
+
return EMPTY_COLLISION;
|
|
1071
|
+
}
|
|
1072
|
+
const isInside = isPointInPolygon(position, vertices);
|
|
1073
|
+
const closest = closestPointOnPolygon(position, vertices);
|
|
1074
|
+
const distance = Math.sqrt(closest.distanceSq);
|
|
1075
|
+
let penetration;
|
|
1076
|
+
let normalX;
|
|
1077
|
+
let normalY;
|
|
1078
|
+
if (isInside) {
|
|
1079
|
+
penetration = radius + distance;
|
|
1080
|
+
const dx = closest.point.x - position.x;
|
|
1081
|
+
const dy = closest.point.y - position.y;
|
|
1082
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
1083
|
+
if (len2 > EPSILON4) {
|
|
1084
|
+
normalX = dx / len2;
|
|
1085
|
+
normalY = dy / len2;
|
|
1086
|
+
} else {
|
|
1087
|
+
normalX = 1;
|
|
1088
|
+
normalY = 0;
|
|
1089
|
+
}
|
|
1090
|
+
} else if (distance < radius) {
|
|
1091
|
+
penetration = radius - distance;
|
|
1092
|
+
const dx = position.x - closest.point.x;
|
|
1093
|
+
const dy = position.y - closest.point.y;
|
|
1094
|
+
const len2 = Math.sqrt(dx * dx + dy * dy);
|
|
1095
|
+
if (len2 > EPSILON4) {
|
|
1096
|
+
normalX = dx / len2;
|
|
1097
|
+
normalY = dy / len2;
|
|
1098
|
+
} else {
|
|
1099
|
+
normalX = 1;
|
|
1100
|
+
normalY = 0;
|
|
1101
|
+
}
|
|
1102
|
+
} else {
|
|
1103
|
+
return EMPTY_COLLISION;
|
|
1104
|
+
}
|
|
1105
|
+
return {
|
|
1106
|
+
collided: true,
|
|
1107
|
+
penetration,
|
|
1108
|
+
normal: {
|
|
1109
|
+
x: normalX,
|
|
1110
|
+
y: normalY
|
|
1111
|
+
},
|
|
1112
|
+
closestPoint: closest.point
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* @zh 检测圆与所有障碍物的碰撞
|
|
1117
|
+
* @en Detect collision between circle and all obstacles
|
|
1118
|
+
*
|
|
1119
|
+
* @param position - @zh 圆心位置 @en Circle center position
|
|
1120
|
+
* @param radius - @zh 圆半径 @en Circle radius
|
|
1121
|
+
* @param obstacles - @zh 障碍物列表 @en List of obstacles
|
|
1122
|
+
* @returns @zh 最严重的碰撞结果 @en Most severe collision result
|
|
1123
|
+
*/
|
|
1124
|
+
detectCollisions(position, radius, obstacles) {
|
|
1125
|
+
let worstCollision = EMPTY_COLLISION;
|
|
1126
|
+
let maxPenetration = 0;
|
|
1127
|
+
for (const obstacle of obstacles) {
|
|
1128
|
+
const collision = this.detectCollision(position, radius, obstacle);
|
|
1129
|
+
if (collision.collided && collision.penetration > maxPenetration) {
|
|
1130
|
+
maxPenetration = collision.penetration;
|
|
1131
|
+
worstCollision = collision;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return worstCollision;
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* @zh 解决碰撞,返回修正后的位置
|
|
1138
|
+
* @en Resolve collision, return corrected position
|
|
1139
|
+
*
|
|
1140
|
+
* @param position - @zh 当前位置 @en Current position
|
|
1141
|
+
* @param radius - @zh 半径 @en Radius
|
|
1142
|
+
* @param obstacles - @zh 障碍物列表 @en List of obstacles
|
|
1143
|
+
* @returns @zh 修正后的位置 @en Corrected position
|
|
1144
|
+
*/
|
|
1145
|
+
resolveCollision(position, radius, obstacles) {
|
|
1146
|
+
const result = {
|
|
1147
|
+
x: position.x,
|
|
1148
|
+
y: position.y
|
|
1149
|
+
};
|
|
1150
|
+
const maxIterations = 4;
|
|
1151
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
1152
|
+
const collision = this.detectCollisions(result, radius, obstacles);
|
|
1153
|
+
if (!collision.collided) {
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
const pushDistance = (collision.penetration + this.config.safetyMargin) * this.config.responseFactor;
|
|
1157
|
+
result.x += collision.normal.x * pushDistance;
|
|
1158
|
+
result.y += collision.normal.y * pushDistance;
|
|
1159
|
+
}
|
|
1160
|
+
return result;
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* @zh 验证速度是否会导致碰撞,返回安全速度
|
|
1164
|
+
* @en Validate velocity won't cause collision, return safe velocity
|
|
1165
|
+
*
|
|
1166
|
+
* @param position - @zh 当前位置 @en Current position
|
|
1167
|
+
* @param velocity - @zh 目标速度 @en Target velocity
|
|
1168
|
+
* @param radius - @zh 半径 @en Radius
|
|
1169
|
+
* @param obstacles - @zh 障碍物列表 @en List of obstacles
|
|
1170
|
+
* @param deltaTime - @zh 时间步长 @en Time step
|
|
1171
|
+
* @returns @zh 安全速度 @en Safe velocity
|
|
1172
|
+
*/
|
|
1173
|
+
validateVelocity(position, velocity, radius, obstacles, deltaTime) {
|
|
1174
|
+
const speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y);
|
|
1175
|
+
if (speed < EPSILON4) {
|
|
1176
|
+
return velocity;
|
|
1177
|
+
}
|
|
1178
|
+
const newPos = {
|
|
1179
|
+
x: position.x + velocity.x * deltaTime,
|
|
1180
|
+
y: position.y + velocity.y * deltaTime
|
|
1181
|
+
};
|
|
1182
|
+
const collision = this.detectCollisions(newPos, radius, obstacles);
|
|
1183
|
+
if (!collision.collided) {
|
|
1184
|
+
return velocity;
|
|
1185
|
+
}
|
|
1186
|
+
const dotProduct = velocity.x * collision.normal.x + velocity.y * collision.normal.y;
|
|
1187
|
+
if (dotProduct >= 0) {
|
|
1188
|
+
return velocity;
|
|
1189
|
+
}
|
|
1190
|
+
const slideVelocity = {
|
|
1191
|
+
x: velocity.x - dotProduct * collision.normal.x,
|
|
1192
|
+
y: velocity.y - dotProduct * collision.normal.y
|
|
1193
|
+
};
|
|
1194
|
+
const slideSpeed = Math.sqrt(slideVelocity.x * slideVelocity.x + slideVelocity.y * slideVelocity.y);
|
|
1195
|
+
if (slideSpeed < speed * 0.1) {
|
|
1196
|
+
const perpDir1 = {
|
|
1197
|
+
x: -collision.normal.y,
|
|
1198
|
+
y: collision.normal.x
|
|
1199
|
+
};
|
|
1200
|
+
const perpDir2 = {
|
|
1201
|
+
x: collision.normal.y,
|
|
1202
|
+
y: -collision.normal.x
|
|
1203
|
+
};
|
|
1204
|
+
const dot1 = velocity.x * perpDir1.x + velocity.y * perpDir1.y;
|
|
1205
|
+
const dot22 = velocity.x * perpDir2.x + velocity.y * perpDir2.y;
|
|
1206
|
+
const chosenDir = dot1 >= dot22 ? perpDir1 : perpDir2;
|
|
1207
|
+
return {
|
|
1208
|
+
x: chosenDir.x * speed,
|
|
1209
|
+
y: chosenDir.y * speed
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
return slideVelocity;
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* @zh 检测两个代理之间的碰撞
|
|
1216
|
+
* @en Detect collision between two agents
|
|
1217
|
+
*
|
|
1218
|
+
* @param posA - @zh 代理 A 位置 @en Agent A position
|
|
1219
|
+
* @param radiusA - @zh 代理 A 半径 @en Agent A radius
|
|
1220
|
+
* @param posB - @zh 代理 B 位置 @en Agent B position
|
|
1221
|
+
* @param radiusB - @zh 代理 B 半径 @en Agent B radius
|
|
1222
|
+
* @returns @zh 碰撞结果 @en Collision result
|
|
1223
|
+
*/
|
|
1224
|
+
detectAgentCollision(posA, radiusA, posB, radiusB) {
|
|
1225
|
+
const dx = posB.x - posA.x;
|
|
1226
|
+
const dy = posB.y - posA.y;
|
|
1227
|
+
const distSq = dx * dx + dy * dy;
|
|
1228
|
+
const combinedRadius = radiusA + radiusB;
|
|
1229
|
+
if (distSq >= combinedRadius * combinedRadius) {
|
|
1230
|
+
return EMPTY_COLLISION;
|
|
1231
|
+
}
|
|
1232
|
+
const distance = Math.sqrt(distSq);
|
|
1233
|
+
const penetration = combinedRadius - distance;
|
|
1234
|
+
let normalX, normalY;
|
|
1235
|
+
if (distance > EPSILON4) {
|
|
1236
|
+
normalX = -dx / distance;
|
|
1237
|
+
normalY = -dy / distance;
|
|
1238
|
+
} else {
|
|
1239
|
+
normalX = 1;
|
|
1240
|
+
normalY = 0;
|
|
1241
|
+
}
|
|
1242
|
+
return {
|
|
1243
|
+
collided: true,
|
|
1244
|
+
penetration,
|
|
1245
|
+
normal: {
|
|
1246
|
+
x: normalX,
|
|
1247
|
+
y: normalY
|
|
1248
|
+
},
|
|
1249
|
+
closestPoint: {
|
|
1250
|
+
x: posA.x + normalX * radiusA,
|
|
1251
|
+
y: posA.y + normalY * radiusA
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* @zh 解决代理之间的碰撞
|
|
1257
|
+
* @en Resolve collision between agents
|
|
1258
|
+
*
|
|
1259
|
+
* @param posA - @zh 代理 A 位置 @en Agent A position
|
|
1260
|
+
* @param radiusA - @zh 代理 A 半径 @en Agent A radius
|
|
1261
|
+
* @param posB - @zh 代理 B 位置 @en Agent B position
|
|
1262
|
+
* @param radiusB - @zh 代理 B 半径 @en Agent B radius
|
|
1263
|
+
* @returns @zh 修正后的位置 [A, B] @en Corrected positions [A, B]
|
|
1264
|
+
*/
|
|
1265
|
+
resolveAgentCollision(posA, radiusA, posB, radiusB) {
|
|
1266
|
+
const collision = this.detectAgentCollision(posA, radiusA, posB, radiusB);
|
|
1267
|
+
if (!collision.collided) {
|
|
1268
|
+
return [
|
|
1269
|
+
posA,
|
|
1270
|
+
posB
|
|
1271
|
+
];
|
|
1272
|
+
}
|
|
1273
|
+
const halfPush = (collision.penetration + this.config.safetyMargin) * 0.5 * this.config.responseFactor;
|
|
1274
|
+
return [
|
|
1275
|
+
{
|
|
1276
|
+
x: posA.x + collision.normal.x * halfPush,
|
|
1277
|
+
y: posA.y + collision.normal.y * halfPush
|
|
1278
|
+
},
|
|
1279
|
+
{
|
|
1280
|
+
x: posB.x - collision.normal.x * halfPush,
|
|
1281
|
+
y: posB.y - collision.normal.y * halfPush
|
|
1282
|
+
}
|
|
1283
|
+
];
|
|
1284
|
+
}
|
|
1285
|
+
};
|
|
1286
|
+
__name(_CollisionResolver, "CollisionResolver");
|
|
1287
|
+
var CollisionResolver = _CollisionResolver;
|
|
1288
|
+
function createCollisionResolver(config) {
|
|
1289
|
+
return new CollisionResolver(config);
|
|
1290
|
+
}
|
|
1291
|
+
__name(createCollisionResolver, "createCollisionResolver");
|
|
1292
|
+
|
|
921
1293
|
export {
|
|
922
1294
|
DEFAULT_ORCA_CONFIG,
|
|
923
1295
|
DEFAULT_AGENT_PARAMS,
|
|
@@ -930,6 +1302,10 @@ export {
|
|
|
930
1302
|
ORCASolver,
|
|
931
1303
|
createORCASolver,
|
|
932
1304
|
KDTree,
|
|
933
|
-
createKDTree
|
|
1305
|
+
createKDTree,
|
|
1306
|
+
EMPTY_COLLISION,
|
|
1307
|
+
DEFAULT_COLLISION_CONFIG,
|
|
1308
|
+
CollisionResolver,
|
|
1309
|
+
createCollisionResolver
|
|
934
1310
|
};
|
|
935
|
-
//# sourceMappingURL=chunk-
|
|
1311
|
+
//# sourceMappingURL=chunk-3VEX32JO.js.map
|