@esengine/pathfinding 13.3.0 → 13.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ecs.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Component, EntitySystem, Entity } from '@esengine/ecs-framework';
2
- import { S as IVector2, V as IPathPlanner, a7 as IFlowController, a0 as ILocalAvoidance, a2 as ICollisionResolver, _ as IObstacleData } from './FlowController-Dc3nuLq5.js';
3
- export { ap as CollisionResolverAdapter, ab as DEFAULT_FLOW_CONTROLLER_CONFIG, ao as DEFAULT_ORCA_PARAMS, ar as FlowController, ag as GridPathfinderAdapter, a3 as ICongestionZone, a4 as IFlowAgentData, a5 as IFlowControlResult, a6 as IFlowControllerConfig, au as IGridPathfinderAdapterConfig, av as IIncrementalGridPathPlannerConfig, at as IORCAParams, ak as IncrementalGridPathPlannerAdapter, ae as NavMeshPathPlannerAdapter, am as ORCALocalAvoidanceAdapter, aa as PassPermission, ah as createAStarPlanner, aq as createDefaultCollisionResolver, as as createFlowController, aj as createHPAPlanner, al as createIncrementalAStarPlanner, ai as createJPSPlanner, af as createNavMeshPathPlanner, an as createORCAAvoidance } from './FlowController-Dc3nuLq5.js';
2
+ import { S as IVector2, V as IPathPlanner, a7 as IFlowController, a0 as ILocalAvoidance, a2 as ICollisionResolver, _ as IObstacleData } from './FlowController-BztOzQsW.js';
3
+ export { ap as CollisionResolverAdapter, ab as DEFAULT_FLOW_CONTROLLER_CONFIG, ao as DEFAULT_ORCA_PARAMS, ar as FlowController, ag as GridPathfinderAdapter, a3 as ICongestionZone, a4 as IFlowAgentData, a5 as IFlowControlResult, a6 as IFlowControllerConfig, au as IGridPathfinderAdapterConfig, av as IIncrementalGridPathPlannerConfig, at as IORCAParams, ak as IncrementalGridPathPlannerAdapter, ae as NavMeshPathPlannerAdapter, am as ORCALocalAvoidanceAdapter, aa as PassPermission, ah as createAStarPlanner, aq as createDefaultCollisionResolver, as as createFlowController, aj as createHPAPlanner, al as createIncrementalAStarPlanner, ai as createJPSPlanner, af as createNavMeshPathPlanner, an as createORCAAvoidance } from './FlowController-BztOzQsW.js';
4
4
  import './CollisionResolver-CSgWsegP.js';
5
5
  import '@esengine/ecs-framework-math';
6
6
 
@@ -609,6 +609,31 @@ declare class NavigationSystem extends EntitySystem {
609
609
  * @en Resolve agent-agent collisions
610
610
  */
611
611
  private resolveAgentCollisions;
612
+ /**
613
+ * @zh 查找有效的修正向量(不会进入障碍物)
614
+ * @en Find valid correction vector (won't enter obstacles)
615
+ */
616
+ private findValidCorrection;
617
+ /**
618
+ * @zh 查找滑动位置(当目标位置不可行走时)
619
+ * @en Find slide position (when target position is not walkable)
620
+ *
621
+ * @zh 尝试只沿 X 轴或 Y 轴移动,实现沿墙滑动效果
622
+ * @en Try moving only along X or Y axis, achieving wall sliding effect
623
+ */
624
+ private findSlidePosition;
625
+ /**
626
+ * @zh 检查位置是否可行走(考虑代理半径)
627
+ * @en Check if position is walkable (considering agent radius)
628
+ *
629
+ * @zh 检查代理边界框的4个角点和中心点,确保整个代理都在可行走区域
630
+ * @en Check 4 corners and center of agent bounding box, ensure entire agent is in walkable area
631
+ *
632
+ * @param position - @zh 位置 @en Position
633
+ * @param radius - @zh 代理半径 @en Agent radius
634
+ * @param tolerance - @zh 容差比例 (0-1),用于允许轻微重叠 @en Tolerance ratio (0-1), allows slight overlap
635
+ */
636
+ private isPositionWalkable;
612
637
  }
613
638
 
614
639
  /**
package/dist/ecs.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  createNavMeshPathPlanner,
19
19
  createORCAAvoidance,
20
20
  isIncrementalPlanner
21
- } from "./chunk-NIKT3PQC.js";
21
+ } from "./chunk-ZYGBA7VK.js";
22
22
  import "./chunk-YKA3PWU3.js";
23
23
  import "./chunk-3VEX32JO.js";
24
24
  import {
@@ -1020,6 +1020,18 @@ var _NavigationSystem = class _NavigationSystem extends EntitySystem {
1020
1020
  y: 0
1021
1021
  };
1022
1022
  }
1023
+ if (agent.state === NavigationState.Unreachable || agent.state === NavigationState.Arrived) {
1024
+ return {
1025
+ x: 0,
1026
+ y: 0
1027
+ };
1028
+ }
1029
+ if (agent.path.length === 0 && !agent.isComputingPath) {
1030
+ return {
1031
+ x: 0,
1032
+ y: 0
1033
+ };
1034
+ }
1023
1035
  let targetX, targetY;
1024
1036
  let isLastWaypoint = false;
1025
1037
  if (agent.currentWaypointIndex < agent.path.length) {
@@ -1027,10 +1039,15 @@ var _NavigationSystem = class _NavigationSystem extends EntitySystem {
1027
1039
  targetX = waypoint.x;
1028
1040
  targetY = waypoint.y;
1029
1041
  isLastWaypoint = agent.currentWaypointIndex === agent.path.length - 1;
1030
- } else {
1042
+ } else if (agent.path.length > 0) {
1031
1043
  targetX = agent.destination.x;
1032
1044
  targetY = agent.destination.y;
1033
1045
  isLastWaypoint = true;
1046
+ } else {
1047
+ return {
1048
+ x: 0,
1049
+ y: 0
1050
+ };
1034
1051
  }
1035
1052
  const dx = targetX - agent.position.x;
1036
1053
  const dy = targetY - agent.position.y;
@@ -1090,6 +1107,22 @@ var _NavigationSystem = class _NavigationSystem extends EntitySystem {
1090
1107
  if (this.config.enableCollisionResolution && this.collisionResolver && allObstacles.length > 0) {
1091
1108
  newPosition = this.collisionResolver.resolveCollision(newPosition, agent.radius, allObstacles);
1092
1109
  }
1110
+ if (!this.isPositionWalkable(newPosition, agent.radius)) {
1111
+ const slidPosition = this.findSlidePosition(agent.position, newPosition, agent.radius);
1112
+ if (slidPosition) {
1113
+ newPosition = slidPosition;
1114
+ agent.velocity = {
1115
+ x: (newPosition.x - agent.position.x) / deltaTime,
1116
+ y: (newPosition.y - agent.position.y) / deltaTime
1117
+ };
1118
+ } else {
1119
+ agent.velocity = {
1120
+ x: 0,
1121
+ y: 0
1122
+ };
1123
+ return;
1124
+ }
1125
+ }
1093
1126
  agent.position = newPosition;
1094
1127
  this.checkArrival(agent);
1095
1128
  }
@@ -1182,12 +1215,130 @@ var _NavigationSystem = class _NavigationSystem extends EntitySystem {
1182
1215
  x: agent.position.x + correction.x,
1183
1216
  y: agent.position.y + correction.y
1184
1217
  };
1218
+ if (!this.isPositionWalkable(newPosition, agent.radius, 1)) {
1219
+ const partialCorrection = this.findValidCorrection(agent.position, correction, agent.radius);
1220
+ if (partialCorrection) {
1221
+ newPosition = {
1222
+ x: agent.position.x + partialCorrection.x,
1223
+ y: agent.position.y + partialCorrection.y
1224
+ };
1225
+ } else {
1226
+ continue;
1227
+ }
1228
+ }
1185
1229
  if (allObstacles.length > 0) {
1186
1230
  newPosition = this.collisionResolver.resolveCollision(newPosition, agent.radius, allObstacles);
1187
1231
  }
1232
+ if (!this.isPositionWalkable(newPosition, agent.radius, 1)) {
1233
+ continue;
1234
+ }
1188
1235
  agent.position = newPosition;
1189
1236
  }
1190
1237
  }
1238
+ /**
1239
+ * @zh 查找有效的修正向量(不会进入障碍物)
1240
+ * @en Find valid correction vector (won't enter obstacles)
1241
+ */
1242
+ findValidCorrection(currentPos, correction, radius = 0) {
1243
+ if (!this.pathPlanner) return correction;
1244
+ const steps = [
1245
+ 0.75,
1246
+ 0.5,
1247
+ 0.25,
1248
+ 0.1
1249
+ ];
1250
+ for (const scale of steps) {
1251
+ const testPos = {
1252
+ x: currentPos.x + correction.x * scale,
1253
+ y: currentPos.y + correction.y * scale
1254
+ };
1255
+ if (this.isPositionWalkable(testPos, radius, 1)) {
1256
+ return {
1257
+ x: correction.x * scale,
1258
+ y: correction.y * scale
1259
+ };
1260
+ }
1261
+ }
1262
+ return null;
1263
+ }
1264
+ /**
1265
+ * @zh 查找滑动位置(当目标位置不可行走时)
1266
+ * @en Find slide position (when target position is not walkable)
1267
+ *
1268
+ * @zh 尝试只沿 X 轴或 Y 轴移动,实现沿墙滑动效果
1269
+ * @en Try moving only along X or Y axis, achieving wall sliding effect
1270
+ */
1271
+ findSlidePosition(currentPos, targetPos, radius) {
1272
+ const dx = targetPos.x - currentPos.x;
1273
+ const dy = targetPos.y - currentPos.y;
1274
+ const xOnlyPos = {
1275
+ x: targetPos.x,
1276
+ y: currentPos.y
1277
+ };
1278
+ if (Math.abs(dx) > 1e-3 && this.isPositionWalkable(xOnlyPos, radius)) {
1279
+ return xOnlyPos;
1280
+ }
1281
+ const yOnlyPos = {
1282
+ x: currentPos.x,
1283
+ y: targetPos.y
1284
+ };
1285
+ if (Math.abs(dy) > 1e-3 && this.isPositionWalkable(yOnlyPos, radius)) {
1286
+ return yOnlyPos;
1287
+ }
1288
+ const halfPos = {
1289
+ x: currentPos.x + dx * 0.5,
1290
+ y: currentPos.y + dy * 0.5
1291
+ };
1292
+ if (this.isPositionWalkable(halfPos, radius)) {
1293
+ return halfPos;
1294
+ }
1295
+ return null;
1296
+ }
1297
+ /**
1298
+ * @zh 检查位置是否可行走(考虑代理半径)
1299
+ * @en Check if position is walkable (considering agent radius)
1300
+ *
1301
+ * @zh 检查代理边界框的4个角点和中心点,确保整个代理都在可行走区域
1302
+ * @en Check 4 corners and center of agent bounding box, ensure entire agent is in walkable area
1303
+ *
1304
+ * @param position - @zh 位置 @en Position
1305
+ * @param radius - @zh 代理半径 @en Agent radius
1306
+ * @param tolerance - @zh 容差比例 (0-1),用于允许轻微重叠 @en Tolerance ratio (0-1), allows slight overlap
1307
+ */
1308
+ isPositionWalkable(position, radius = 0, tolerance = 0.8) {
1309
+ if (!this.pathPlanner) return true;
1310
+ if (!this.pathPlanner.isWalkable(position)) {
1311
+ return false;
1312
+ }
1313
+ if (radius <= 0) {
1314
+ return true;
1315
+ }
1316
+ const checkRadius = radius * tolerance;
1317
+ const corners = [
1318
+ {
1319
+ x: position.x - checkRadius,
1320
+ y: position.y - checkRadius
1321
+ },
1322
+ {
1323
+ x: position.x + checkRadius,
1324
+ y: position.y - checkRadius
1325
+ },
1326
+ {
1327
+ x: position.x - checkRadius,
1328
+ y: position.y + checkRadius
1329
+ },
1330
+ {
1331
+ x: position.x + checkRadius,
1332
+ y: position.y + checkRadius
1333
+ }
1334
+ ];
1335
+ for (const corner of corners) {
1336
+ if (!this.pathPlanner.isWalkable(corner)) {
1337
+ return false;
1338
+ }
1339
+ }
1340
+ return true;
1341
+ }
1191
1342
  };
1192
1343
  __name(_NavigationSystem, "NavigationSystem");
1193
1344
  var NavigationSystem = _NavigationSystem;