UNPKG

@esengine/pathfinding

Version:

寻路系统 | Pathfinding System - A*, Grid, NavMesh

1,176 lines (1,174 loc) 25.1 kB
import { PathfindingState } from "./chunk-YKA3PWU3.js"; import { __name } from "./chunk-T626JPC7.js"; // src/nodes/PathfindingNodes.ts var FindPathTemplate = { type: "FindPath", title: "Find Path", category: "custom", description: "Find path from start to end / \u4ECE\u8D77\u70B9\u5230\u7EC8\u70B9\u5BFB\u8DEF", keywords: [ "path", "pathfinding", "astar", "navigate", "route" ], menuPath: [ "Pathfinding", "Find Path" ], inputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "startX", displayName: "Start X", type: "float" }, { name: "startY", displayName: "Start Y", type: "float" }, { name: "endX", displayName: "End X", type: "float" }, { name: "endY", displayName: "End Y", type: "float" } ], outputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "found", displayName: "Found", type: "bool" }, { name: "path", displayName: "Path", type: "array" }, { name: "cost", displayName: "Cost", type: "float" } ], color: "#4caf50" }; var _FindPathExecutor = class _FindPathExecutor { execute(node, context) { const ctx = context; const startX = ctx.evaluateInput(node.id, "startX", 0); const startY = ctx.evaluateInput(node.id, "startY", 0); const endX = ctx.evaluateInput(node.id, "endX", 0); const endY = ctx.evaluateInput(node.id, "endY", 0); const result = ctx.findPath(startX, startY, endX, endY); return { outputs: { found: result.found, path: result.path, cost: result.cost }, nextExec: "exec" }; } }; __name(_FindPathExecutor, "FindPathExecutor"); var FindPathExecutor = _FindPathExecutor; var FindPathSmoothTemplate = { type: "FindPathSmooth", title: "Find Path (Smooth)", category: "custom", description: "Find path with smoothing / \u5BFB\u8DEF\u5E76\u5E73\u6ED1\u8DEF\u5F84", keywords: [ "path", "pathfinding", "smooth", "navigate" ], menuPath: [ "Pathfinding", "Find Path (Smooth)" ], inputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "startX", displayName: "Start X", type: "float" }, { name: "startY", displayName: "Start Y", type: "float" }, { name: "endX", displayName: "End X", type: "float" }, { name: "endY", displayName: "End Y", type: "float" } ], outputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "found", displayName: "Found", type: "bool" }, { name: "path", displayName: "Path", type: "array" }, { name: "cost", displayName: "Cost", type: "float" } ], color: "#4caf50" }; var _FindPathSmoothExecutor = class _FindPathSmoothExecutor { execute(node, context) { const ctx = context; const startX = ctx.evaluateInput(node.id, "startX", 0); const startY = ctx.evaluateInput(node.id, "startY", 0); const endX = ctx.evaluateInput(node.id, "endX", 0); const endY = ctx.evaluateInput(node.id, "endY", 0); const result = ctx.findPathSmooth(startX, startY, endX, endY); return { outputs: { found: result.found, path: result.path, cost: result.cost }, nextExec: "exec" }; } }; __name(_FindPathSmoothExecutor, "FindPathSmoothExecutor"); var FindPathSmoothExecutor = _FindPathSmoothExecutor; var IsWalkableTemplate = { type: "IsWalkable", title: "Is Walkable", category: "custom", description: "Check if position is walkable / \u68C0\u67E5\u4F4D\u7F6E\u662F\u5426\u53EF\u901A\u884C", keywords: [ "walkable", "obstacle", "blocked", "terrain" ], menuPath: [ "Pathfinding", "Is Walkable" ], isPure: true, inputs: [ { name: "x", displayName: "X", type: "float" }, { name: "y", displayName: "Y", type: "float" } ], outputs: [ { name: "walkable", displayName: "Walkable", type: "bool" } ], color: "#4caf50" }; var _IsWalkableExecutor = class _IsWalkableExecutor { execute(node, context) { const ctx = context; const x = ctx.evaluateInput(node.id, "x", 0); const y = ctx.evaluateInput(node.id, "y", 0); const walkable = ctx.isWalkable(x, y); return { outputs: { walkable } }; } }; __name(_IsWalkableExecutor, "IsWalkableExecutor"); var IsWalkableExecutor = _IsWalkableExecutor; var GetPathLengthTemplate = { type: "GetPathLength", title: "Get Path Length", category: "custom", description: "Get the number of points in path / \u83B7\u53D6\u8DEF\u5F84\u70B9\u6570\u91CF", keywords: [ "path", "length", "count", "waypoints" ], menuPath: [ "Pathfinding", "Get Path Length" ], isPure: true, inputs: [ { name: "path", displayName: "Path", type: "array" } ], outputs: [ { name: "length", displayName: "Length", type: "int" } ], color: "#4caf50" }; var _GetPathLengthExecutor = class _GetPathLengthExecutor { execute(node, context) { const ctx = context; const path = ctx.evaluateInput(node.id, "path", []); return { outputs: { length: path.length } }; } }; __name(_GetPathLengthExecutor, "GetPathLengthExecutor"); var GetPathLengthExecutor = _GetPathLengthExecutor; var GetPathDistanceTemplate = { type: "GetPathDistance", title: "Get Path Distance", category: "custom", description: "Get total path distance / \u83B7\u53D6\u8DEF\u5F84\u603B\u8DDD\u79BB", keywords: [ "path", "distance", "length", "travel" ], menuPath: [ "Pathfinding", "Get Path Distance" ], isPure: true, inputs: [ { name: "path", displayName: "Path", type: "array" } ], outputs: [ { name: "distance", displayName: "Distance", type: "float" } ], color: "#4caf50" }; var _GetPathDistanceExecutor = class _GetPathDistanceExecutor { execute(node, context) { const ctx = context; const path = ctx.evaluateInput(node.id, "path", []); const distance = ctx.getPathDistance(path); return { outputs: { distance } }; } }; __name(_GetPathDistanceExecutor, "GetPathDistanceExecutor"); var GetPathDistanceExecutor = _GetPathDistanceExecutor; var GetPathPointTemplate = { type: "GetPathPoint", title: "Get Path Point", category: "custom", description: "Get point at index in path / \u83B7\u53D6\u8DEF\u5F84\u4E2D\u6307\u5B9A\u7D22\u5F15\u7684\u70B9", keywords: [ "path", "point", "waypoint", "index" ], menuPath: [ "Pathfinding", "Get Path Point" ], isPure: true, inputs: [ { name: "path", displayName: "Path", type: "array" }, { name: "index", displayName: "Index", type: "int" } ], outputs: [ { name: "x", displayName: "X", type: "float" }, { name: "y", displayName: "Y", type: "float" }, { name: "valid", displayName: "Valid", type: "bool" } ], color: "#4caf50" }; var _GetPathPointExecutor = class _GetPathPointExecutor { execute(node, context) { const ctx = context; const path = ctx.evaluateInput(node.id, "path", []); const index = ctx.evaluateInput(node.id, "index", 0); if (index >= 0 && index < path.length) { return { outputs: { x: path[index].x, y: path[index].y, valid: true } }; } return { outputs: { x: 0, y: 0, valid: false } }; } }; __name(_GetPathPointExecutor, "GetPathPointExecutor"); var GetPathPointExecutor = _GetPathPointExecutor; var MoveAlongPathTemplate = { type: "MoveAlongPath", title: "Move Along Path", category: "custom", description: "Get position along path at progress / \u83B7\u53D6\u8DEF\u5F84\u4E0A\u6307\u5B9A\u8FDB\u5EA6\u7684\u4F4D\u7F6E", keywords: [ "path", "move", "lerp", "progress", "interpolate" ], menuPath: [ "Pathfinding", "Move Along Path" ], isPure: true, inputs: [ { name: "path", displayName: "Path", type: "array" }, { name: "progress", displayName: "Progress (0-1)", type: "float" } ], outputs: [ { name: "x", displayName: "X", type: "float" }, { name: "y", displayName: "Y", type: "float" } ], color: "#4caf50" }; var _MoveAlongPathExecutor = class _MoveAlongPathExecutor { execute(node, context) { const ctx = context; const path = ctx.evaluateInput(node.id, "path", []); let progress = ctx.evaluateInput(node.id, "progress", 0); if (path.length === 0) { return { outputs: { x: 0, y: 0 } }; } if (path.length === 1) { return { outputs: { x: path[0].x, y: path[0].y } }; } progress = Math.max(0, Math.min(1, progress)); let totalDistance = 0; const segmentDistances = []; for (let i = 1; i < path.length; i++) { const dx = path[i].x - path[i - 1].x; const dy = path[i].y - path[i - 1].y; const dist = Math.sqrt(dx * dx + dy * dy); segmentDistances.push(dist); totalDistance += dist; } if (totalDistance === 0) { return { outputs: { x: path[0].x, y: path[0].y } }; } const targetDistance = progress * totalDistance; let accumulatedDistance = 0; for (let i = 0; i < segmentDistances.length; i++) { const segmentDist = segmentDistances[i]; if (accumulatedDistance + segmentDist >= targetDistance) { const segmentProgress = (targetDistance - accumulatedDistance) / segmentDist; const x = path[i].x + (path[i + 1].x - path[i].x) * segmentProgress; const y = path[i].y + (path[i + 1].y - path[i].y) * segmentProgress; return { outputs: { x, y } }; } accumulatedDistance += segmentDist; } const last = path[path.length - 1]; return { outputs: { x: last.x, y: last.y } }; } }; __name(_MoveAlongPathExecutor, "MoveAlongPathExecutor"); var MoveAlongPathExecutor = _MoveAlongPathExecutor; var HasLineOfSightTemplate = { type: "HasLineOfSight", title: "Has Line of Sight", category: "custom", description: "Check if there is a clear line between two points / \u68C0\u67E5\u4E24\u70B9\u4E4B\u95F4\u662F\u5426\u6709\u6E05\u6670\u7684\u89C6\u7EBF", keywords: [ "line", "sight", "los", "visibility", "raycast" ], menuPath: [ "Pathfinding", "Has Line of Sight" ], isPure: true, inputs: [ { name: "startX", displayName: "Start X", type: "float" }, { name: "startY", displayName: "Start Y", type: "float" }, { name: "endX", displayName: "End X", type: "float" }, { name: "endY", displayName: "End Y", type: "float" } ], outputs: [ { name: "hasLOS", displayName: "Has LOS", type: "bool" } ], color: "#4caf50" }; var _HasLineOfSightExecutor = class _HasLineOfSightExecutor { execute(node, context) { const ctx = context; const startX = ctx.evaluateInput(node.id, "startX", 0); const startY = ctx.evaluateInput(node.id, "startY", 0); const endX = ctx.evaluateInput(node.id, "endX", 0); const endY = ctx.evaluateInput(node.id, "endY", 0); const hasLOS = ctx.hasLineOfSight?.(startX, startY, endX, endY) ?? true; return { outputs: { hasLOS } }; } }; __name(_HasLineOfSightExecutor, "HasLineOfSightExecutor"); var HasLineOfSightExecutor = _HasLineOfSightExecutor; var PathfindingNodeDefinitions = { templates: [ FindPathTemplate, FindPathSmoothTemplate, IsWalkableTemplate, GetPathLengthTemplate, GetPathDistanceTemplate, GetPathPointTemplate, MoveAlongPathTemplate, HasLineOfSightTemplate ], executors: /* @__PURE__ */ new Map([ [ "FindPath", new FindPathExecutor() ], [ "FindPathSmooth", new FindPathSmoothExecutor() ], [ "IsWalkable", new IsWalkableExecutor() ], [ "GetPathLength", new GetPathLengthExecutor() ], [ "GetPathDistance", new GetPathDistanceExecutor() ], [ "GetPathPoint", new GetPathPointExecutor() ], [ "MoveAlongPath", new MoveAlongPathExecutor() ], [ "HasLineOfSight", new HasLineOfSightExecutor() ] ]) }; // src/nodes/IncrementalPathfindingNodes.ts var RequestPathAsyncTemplate = { type: "RequestPathAsync", title: "Request Path (Async)", category: "custom", description: "Request incremental pathfinding / \u8BF7\u6C42\u589E\u91CF\u5BFB\u8DEF", keywords: [ "path", "pathfinding", "async", "incremental", "request" ], menuPath: [ "Pathfinding", "Incremental", "Request Path (Async)" ], inputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "startX", displayName: "Start X", type: "float" }, { name: "startY", displayName: "Start Y", type: "float" }, { name: "endX", displayName: "End X", type: "float" }, { name: "endY", displayName: "End Y", type: "float" }, { name: "priority", displayName: "Priority", type: "int" } ], outputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "requestId", displayName: "Request ID", type: "int" } ], color: "#4caf50" }; var _RequestPathAsyncExecutor = class _RequestPathAsyncExecutor { execute(node, context) { const ctx = context; const startX = ctx.evaluateInput(node.id, "startX", 0); const startY = ctx.evaluateInput(node.id, "startY", 0); const endX = ctx.evaluateInput(node.id, "endX", 0); const endY = ctx.evaluateInput(node.id, "endY", 0); const priority = ctx.evaluateInput(node.id, "priority", 50); const requestId = ctx.requestPath(startX, startY, endX, endY, priority); return { outputs: { requestId }, nextExec: "exec" }; } }; __name(_RequestPathAsyncExecutor, "RequestPathAsyncExecutor"); var RequestPathAsyncExecutor = _RequestPathAsyncExecutor; var StepPathTemplate = { type: "StepPath", title: "Step Path", category: "custom", description: "Execute one step of pathfinding / \u6267\u884C\u4E00\u6B65\u5BFB\u8DEF", keywords: [ "path", "pathfinding", "step", "iterate", "incremental" ], menuPath: [ "Pathfinding", "Incremental", "Step Path" ], inputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "requestId", displayName: "Request ID", type: "int" }, { name: "maxIterations", displayName: "Max Iterations", type: "int" } ], outputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "state", displayName: "State", type: "string" }, { name: "progress", displayName: "Progress", type: "float" }, { name: "nodesSearched", displayName: "Nodes Searched", type: "int" } ], color: "#4caf50" }; var _StepPathExecutor = class _StepPathExecutor { execute(node, context) { const ctx = context; const requestId = ctx.evaluateInput(node.id, "requestId", -1); const maxIterations = ctx.evaluateInput(node.id, "maxIterations", 100); const progress = ctx.stepPath(requestId, maxIterations); return { outputs: { state: progress.state, progress: progress.estimatedProgress, nodesSearched: progress.nodesSearched }, nextExec: "exec" }; } }; __name(_StepPathExecutor, "StepPathExecutor"); var StepPathExecutor = _StepPathExecutor; var GetPathProgressTemplate = { type: "GetPathProgress", title: "Get Path Progress", category: "custom", description: "Get incremental pathfinding progress / \u83B7\u53D6\u589E\u91CF\u5BFB\u8DEF\u8FDB\u5EA6", keywords: [ "path", "progress", "status", "state" ], menuPath: [ "Pathfinding", "Incremental", "Get Path Progress" ], isPure: true, inputs: [ { name: "requestId", displayName: "Request ID", type: "int" } ], outputs: [ { name: "state", displayName: "State", type: "string" }, { name: "progress", displayName: "Progress (0-1)", type: "float" }, { name: "nodesSearched", displayName: "Nodes Searched", type: "int" }, { name: "isComplete", displayName: "Is Complete", type: "bool" }, { name: "isInProgress", displayName: "Is In Progress", type: "bool" } ], color: "#4caf50" }; var _GetPathProgressExecutor = class _GetPathProgressExecutor { execute(node, context) { const ctx = context; const requestId = ctx.evaluateInput(node.id, "requestId", -1); const progress = ctx.getPathProgress(requestId); if (!progress) { return { outputs: { state: PathfindingState.Idle, progress: 0, nodesSearched: 0, isComplete: false, isInProgress: false } }; } return { outputs: { state: progress.state, progress: progress.estimatedProgress, nodesSearched: progress.nodesSearched, isComplete: progress.state === PathfindingState.Completed, isInProgress: progress.state === PathfindingState.InProgress } }; } }; __name(_GetPathProgressExecutor, "GetPathProgressExecutor"); var GetPathProgressExecutor = _GetPathProgressExecutor; var GetPathResultTemplate = { type: "GetPathResult", title: "Get Path Result", category: "custom", description: "Get completed path result / \u83B7\u53D6\u5DF2\u5B8C\u6210\u7684\u5BFB\u8DEF\u7ED3\u679C", keywords: [ "path", "result", "get", "output" ], menuPath: [ "Pathfinding", "Incremental", "Get Path Result" ], isPure: true, inputs: [ { name: "requestId", displayName: "Request ID", type: "int" } ], outputs: [ { name: "found", displayName: "Found", type: "bool" }, { name: "path", displayName: "Path", type: "array" }, { name: "cost", displayName: "Cost", type: "float" }, { name: "framesUsed", displayName: "Frames Used", type: "int" } ], color: "#4caf50" }; var _GetPathResultExecutor = class _GetPathResultExecutor { execute(node, context) { const ctx = context; const requestId = ctx.evaluateInput(node.id, "requestId", -1); const result = ctx.getPathResult(requestId); if (!result) { return { outputs: { found: false, path: [], cost: 0, framesUsed: 0 } }; } return { outputs: { found: result.found, path: result.path, cost: result.cost, framesUsed: result.framesUsed } }; } }; __name(_GetPathResultExecutor, "GetPathResultExecutor"); var GetPathResultExecutor = _GetPathResultExecutor; var CancelPathTemplate = { type: "CancelPath", title: "Cancel Path", category: "custom", description: "Cancel ongoing pathfinding / \u53D6\u6D88\u6B63\u5728\u8FDB\u884C\u7684\u5BFB\u8DEF", keywords: [ "path", "cancel", "stop", "abort" ], menuPath: [ "Pathfinding", "Incremental", "Cancel Path" ], inputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "requestId", displayName: "Request ID", type: "int" } ], outputs: [ { name: "exec", displayName: "", type: "exec" } ], color: "#f44336" }; var _CancelPathExecutor = class _CancelPathExecutor { execute(node, context) { const ctx = context; const requestId = ctx.evaluateInput(node.id, "requestId", -1); ctx.cancelPath(requestId); return { nextExec: "exec" }; } }; __name(_CancelPathExecutor, "CancelPathExecutor"); var CancelPathExecutor = _CancelPathExecutor; var SetObstacleTemplate = { type: "SetObstacle", title: "Set Obstacle", category: "custom", description: "Set or remove obstacle / \u8BBE\u7F6E\u6216\u79FB\u9664\u969C\u788D\u7269", keywords: [ "obstacle", "block", "walkable", "terrain" ], menuPath: [ "Pathfinding", "Incremental", "Set Obstacle" ], inputs: [ { name: "exec", displayName: "", type: "exec" }, { name: "x", displayName: "X", type: "int" }, { name: "y", displayName: "Y", type: "int" }, { name: "blocked", displayName: "Blocked", type: "bool" } ], outputs: [ { name: "exec", displayName: "", type: "exec" } ], color: "#ff9800" }; var _SetObstacleExecutor = class _SetObstacleExecutor { execute(node, context) { const ctx = context; const x = ctx.evaluateInput(node.id, "x", 0); const y = ctx.evaluateInput(node.id, "y", 0); const blocked = ctx.evaluateInput(node.id, "blocked", true); ctx.setObstacle(x, y, blocked); return { nextExec: "exec" }; } }; __name(_SetObstacleExecutor, "SetObstacleExecutor"); var SetObstacleExecutor = _SetObstacleExecutor; var IsPathCompleteTemplate = { type: "IsPathComplete", title: "Is Path Complete", category: "custom", description: "Check if pathfinding is complete / \u68C0\u67E5\u5BFB\u8DEF\u662F\u5426\u5B8C\u6210", keywords: [ "path", "complete", "done", "finished" ], menuPath: [ "Pathfinding", "Incremental", "Is Path Complete" ], isPure: true, inputs: [ { name: "requestId", displayName: "Request ID", type: "int" } ], outputs: [ { name: "isComplete", displayName: "Is Complete", type: "bool" }, { name: "found", displayName: "Found", type: "bool" } ], color: "#4caf50" }; var _IsPathCompleteExecutor = class _IsPathCompleteExecutor { execute(node, context) { const ctx = context; const requestId = ctx.evaluateInput(node.id, "requestId", -1); const progress = ctx.getPathProgress(requestId); const isComplete = progress?.state === PathfindingState.Completed || progress?.state === PathfindingState.Failed; const result = ctx.getPathResult(requestId); const found = result?.found ?? false; return { outputs: { isComplete, found } }; } }; __name(_IsPathCompleteExecutor, "IsPathCompleteExecutor"); var IsPathCompleteExecutor = _IsPathCompleteExecutor; var IncrementalPathfindingNodeDefinitions = { templates: [ RequestPathAsyncTemplate, StepPathTemplate, GetPathProgressTemplate, GetPathResultTemplate, CancelPathTemplate, SetObstacleTemplate, IsPathCompleteTemplate ], executors: /* @__PURE__ */ new Map([ [ "RequestPathAsync", new RequestPathAsyncExecutor() ], [ "StepPath", new StepPathExecutor() ], [ "GetPathProgress", new GetPathProgressExecutor() ], [ "GetPathResult", new GetPathResultExecutor() ], [ "CancelPath", new CancelPathExecutor() ], [ "SetObstacle", new SetObstacleExecutor() ], [ "IsPathComplete", new IsPathCompleteExecutor() ] ]) }; export { CancelPathExecutor, CancelPathTemplate, FindPathExecutor, FindPathSmoothExecutor, FindPathSmoothTemplate, FindPathTemplate, GetPathDistanceExecutor, GetPathDistanceTemplate, GetPathLengthExecutor, GetPathLengthTemplate, GetPathPointExecutor, GetPathPointTemplate, GetPathProgressExecutor, GetPathProgressTemplate, GetPathResultExecutor, GetPathResultTemplate, HasLineOfSightExecutor, HasLineOfSightTemplate, IncrementalPathfindingNodeDefinitions, IsPathCompleteExecutor, IsPathCompleteTemplate, IsWalkableExecutor, IsWalkableTemplate, MoveAlongPathExecutor, MoveAlongPathTemplate, PathfindingNodeDefinitions, RequestPathAsyncExecutor, RequestPathAsyncTemplate, SetObstacleExecutor, SetObstacleTemplate, StepPathExecutor, StepPathTemplate }; //# sourceMappingURL=nodes.js.map