@esengine/pathfinding 12.1.0 → 13.0.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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ecs/PathfindingAgentComponent.ts","../src/ecs/PathfindingMapComponent.ts","../src/ecs/PathfindingSystem.ts"],"sourcesContent":["/**\n * @zh 寻路代理组件\n * @en Pathfinding Agent Component\n */\n\nimport {\n Component,\n ECSComponent,\n Serializable,\n Serialize,\n Property\n} from '@esengine/ecs-framework';\nimport type { IPoint } from '../core/IPathfinding';\nimport { PathfindingState } from '../core/IIncrementalPathfinding';\n\n// =============================================================================\n// 寻路代理组件 | Pathfinding Agent Component\n// =============================================================================\n\n/**\n * @zh 寻路代理组件\n * @en Pathfinding Agent Component\n *\n * @zh 附加到需要寻路的实体上,管理寻路请求和结果\n * @en Attach to entities that need pathfinding, manages path requests and results\n *\n * @example\n * ```typescript\n * const entity = scene.createEntity('Agent');\n * const agent = entity.addComponent(new PathfindingAgentComponent());\n *\n * // Set initial position\n * agent.x = 10;\n * agent.y = 10;\n *\n * // Request path to target\n * agent.requestPathTo(50, 50);\n *\n * // In movement system, follow the path\n * const waypoint = agent.getNextWaypoint();\n * if (waypoint) {\n * // Move towards waypoint\n * // When reached, call agent.advanceWaypoint()\n * }\n * ```\n */\n@ECSComponent('PathfindingAgent')\n@Serializable({ version: 1, typeId: 'PathfindingAgent' })\nexport class PathfindingAgentComponent extends Component {\n // =========================================================================\n // 位置属性 | Position Properties\n // =========================================================================\n\n /**\n * @zh 当前位置 X 坐标\n * @en Current position X coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Position X' })\n x: number = 0;\n\n /**\n * @zh 当前位置 Y 坐标\n * @en Current position Y coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Position Y' })\n y: number = 0;\n\n // =========================================================================\n // 目标属性 | Target Properties\n // =========================================================================\n\n /**\n * @zh 目标位置 X 坐标\n * @en Target position X coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Target X' })\n targetX: number = 0;\n\n /**\n * @zh 目标位置 Y 坐标\n * @en Target position Y coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Target Y' })\n targetY: number = 0;\n\n /**\n * @zh 是否有新的寻路请求待处理\n * @en Whether there is a new path request pending\n */\n hasRequest: boolean = false;\n\n // =========================================================================\n // 配置属性 | Configuration Properties\n // =========================================================================\n\n /**\n * @zh 寻路优先级(数值越小优先级越高)\n * @en Pathfinding priority (lower number = higher priority)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Priority', min: 0, max: 100 })\n priority: number = 50;\n\n /**\n * @zh 每帧最大迭代次数\n * @en Maximum iterations per frame\n */\n @Serialize()\n @Property({ type: 'number', label: 'Max Iterations/Frame', min: 10, max: 1000 })\n maxIterationsPerFrame: number = 100;\n\n /**\n * @zh 是否启用动态重规划\n * @en Whether dynamic replanning is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Dynamic Replan' })\n enableDynamicReplan: boolean = true;\n\n /**\n * @zh 向前探测距离(用于障碍物检测)\n * @en Lookahead distance for obstacle detection\n */\n @Serialize()\n @Property({ type: 'number', label: 'Lookahead Distance', min: 1, max: 20 })\n lookaheadDistance: number = 5;\n\n /**\n * @zh 路径验证间隔(帧数)\n * @en Path validation interval (in frames)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Validation Interval', min: 1, max: 60 })\n validationInterval: number = 10;\n\n // =========================================================================\n // 运行时状态(不序列化)| Runtime State (not serialized)\n // =========================================================================\n\n /**\n * @zh 当前寻路状态\n * @en Current pathfinding state\n */\n state: PathfindingState = PathfindingState.Idle;\n\n /**\n * @zh 当前请求 ID\n * @en Current request ID\n */\n currentRequestId: number = -1;\n\n /**\n * @zh 当前路径点列表\n * @en Current path waypoints\n */\n path: IPoint[] = [];\n\n /**\n * @zh 当前路径索引\n * @en Current path index\n */\n pathIndex: number = 0;\n\n /**\n * @zh 路径总代价\n * @en Total path cost\n */\n pathCost: number = 0;\n\n /**\n * @zh 寻路进度 (0-1)\n * @en Pathfinding progress (0-1)\n */\n progress: number = 0;\n\n /**\n * @zh 上次验证的帧号\n * @en Last validation frame number\n */\n lastValidationFrame: number = 0;\n\n /**\n * @zh 寻路完成回调\n * @en Pathfinding complete callback\n */\n onPathComplete?: (found: boolean, path: readonly IPoint[]) => void;\n\n /**\n * @zh 寻路进度回调\n * @en Pathfinding progress callback\n */\n onPathProgress?: (progress: number) => void;\n\n // =========================================================================\n // 公共方法 | Public Methods\n // =========================================================================\n\n /**\n * @zh 请求寻路到目标位置\n * @en Request path to target position\n *\n * @param targetX - @zh 目标 X 坐标 @en Target X coordinate\n * @param targetY - @zh 目标 Y 坐标 @en Target Y coordinate\n */\n requestPathTo(targetX: number, targetY: number): void {\n this.targetX = targetX;\n this.targetY = targetY;\n this.hasRequest = true;\n this.state = PathfindingState.Idle;\n this.progress = 0;\n }\n\n /**\n * @zh 取消当前寻路\n * @en Cancel current pathfinding\n */\n cancelPath(): void {\n this.hasRequest = false;\n this.state = PathfindingState.Cancelled;\n this.path = [];\n this.pathIndex = 0;\n this.progress = 0;\n this.currentRequestId = -1;\n }\n\n /**\n * @zh 获取下一个路径点\n * @en Get next waypoint\n *\n * @returns @zh 下一个路径点或 null @en Next waypoint or null\n */\n getNextWaypoint(): IPoint | null {\n if (this.pathIndex < this.path.length) {\n return this.path[this.pathIndex];\n }\n return null;\n }\n\n /**\n * @zh 前进到下一个路径点\n * @en Advance to next waypoint\n */\n advanceWaypoint(): void {\n if (this.pathIndex < this.path.length) {\n this.pathIndex++;\n }\n }\n\n /**\n * @zh 检查是否到达路径终点\n * @en Check if reached path end\n *\n * @returns @zh 是否到达终点 @en Whether reached end\n */\n isPathComplete(): boolean {\n return this.pathIndex >= this.path.length;\n }\n\n /**\n * @zh 检查是否正在寻路\n * @en Check if pathfinding is in progress\n *\n * @returns @zh 是否正在寻路 @en Whether pathfinding is in progress\n */\n isSearching(): boolean {\n return this.state === PathfindingState.InProgress;\n }\n\n /**\n * @zh 检查是否有有效路径\n * @en Check if has valid path\n *\n * @returns @zh 是否有有效路径 @en Whether has valid path\n */\n hasValidPath(): boolean {\n return this.state === PathfindingState.Completed && this.path.length > 0;\n }\n\n /**\n * @zh 获取剩余路径点数量\n * @en Get remaining waypoint count\n *\n * @returns @zh 剩余路径点数量 @en Remaining waypoint count\n */\n getRemainingWaypointCount(): number {\n return Math.max(0, this.path.length - this.pathIndex);\n }\n\n /**\n * @zh 获取当前路径的总长度\n * @en Get total path length\n *\n * @returns @zh 路径总长度 @en Total path length\n */\n getPathLength(): number {\n return this.path.length;\n }\n\n /**\n * @zh 重置组件状态\n * @en Reset component state\n */\n reset(): void {\n this.state = PathfindingState.Idle;\n this.currentRequestId = -1;\n this.path = [];\n this.pathIndex = 0;\n this.pathCost = 0;\n this.progress = 0;\n this.hasRequest = false;\n this.lastValidationFrame = 0;\n }\n\n /**\n * @zh 组件从实体移除时调用\n * @en Called when component is removed from entity\n */\n public onRemovedFromEntity(): void {\n this.reset();\n this.onPathComplete = undefined;\n this.onPathProgress = undefined;\n }\n}\n","/**\n * @zh 寻路地图组件\n * @en Pathfinding Map Component\n */\n\nimport {\n Component,\n ECSComponent,\n Serializable,\n Serialize,\n Property\n} from '@esengine/ecs-framework';\nimport type { IPathfindingMap, IPathSmoother } from '../core/IPathfinding';\nimport type { IIncrementalPathfinder } from '../core/IIncrementalPathfinding';\n\n// =============================================================================\n// 地图类型 | Map Type\n// =============================================================================\n\n/**\n * @zh 地图类型\n * @en Map type\n */\nexport type PathfindingMapType = 'grid' | 'navmesh';\n\n// =============================================================================\n// 寻路地图组件 | Pathfinding Map Component\n// =============================================================================\n\n/**\n * @zh 寻路地图组件\n * @en Pathfinding Map Component\n *\n * @zh 挂载在场景实体上,持有地图实例和增量寻路器\n * @en Attached to scene entity, holds map instance and incremental pathfinder\n *\n * @example\n * ```typescript\n * const mapEntity = scene.createEntity('PathfindingMap');\n * const mapComp = mapEntity.addComponent(new PathfindingMapComponent());\n *\n * // Configure map\n * mapComp.width = 100;\n * mapComp.height = 100;\n * mapComp.iterationsBudget = 2000;\n *\n * // Map and pathfinder will be initialized by PathfindingSystem\n * ```\n */\n@ECSComponent('PathfindingMap')\n@Serializable({ version: 1, typeId: 'PathfindingMap' })\nexport class PathfindingMapComponent extends Component {\n // =========================================================================\n // 地图配置 | Map Configuration\n // =========================================================================\n\n /**\n * @zh 地图类型\n * @en Map type\n */\n @Serialize()\n @Property({\n type: 'enum',\n label: 'Map Type',\n options: [\n { value: 'grid', label: 'Grid' },\n { value: 'navmesh', label: 'NavMesh' }\n ]\n })\n mapType: PathfindingMapType = 'grid';\n\n /**\n * @zh 网格宽度(仅 grid 类型)\n * @en Grid width (grid type only)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Map Width', min: 1, max: 10000 })\n width: number = 100;\n\n /**\n * @zh 网格高度(仅 grid 类型)\n * @en Grid height (grid type only)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Map Height', min: 1, max: 10000 })\n height: number = 100;\n\n /**\n * @zh 是否允许对角移动\n * @en Whether diagonal movement is allowed\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Allow Diagonal' })\n allowDiagonal: boolean = true;\n\n /**\n * @zh 是否避免穿角\n * @en Whether to avoid corner cutting\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Avoid Corners' })\n avoidCorners: boolean = true;\n\n // =========================================================================\n // 系统配置 | System Configuration\n // =========================================================================\n\n /**\n * @zh 每帧处理的最大代理数\n * @en Maximum agents processed per frame\n */\n @Serialize()\n @Property({ type: 'number', label: 'Max Agents/Frame', min: 1, max: 100 })\n maxAgentsPerFrame: number = 10;\n\n /**\n * @zh 每帧总迭代次数预算\n * @en Total iterations budget per frame\n */\n @Serialize()\n @Property({ type: 'number', label: 'Iterations Budget', min: 100, max: 10000 })\n iterationsBudget: number = 1000;\n\n /**\n * @zh 是否启用路径平滑\n * @en Whether path smoothing is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Enable Smoothing' })\n enableSmoothing: boolean = true;\n\n /**\n * @zh 路径平滑类型\n * @en Path smoothing type\n */\n @Serialize()\n @Property({\n type: 'enum',\n label: 'Smoothing Type',\n options: [\n { value: 'los', label: 'Line of Sight' },\n { value: 'catmullrom', label: 'Catmull-Rom' },\n { value: 'combined', label: 'Combined' }\n ]\n })\n smoothingType: 'los' | 'catmullrom' | 'combined' = 'los';\n\n // =========================================================================\n // 缓存配置 | Cache Configuration\n // =========================================================================\n\n /**\n * @zh 是否启用路径缓存\n * @en Whether path caching is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Enable Cache' })\n enableCache: boolean = true;\n\n /**\n * @zh 缓存最大条目数\n * @en Maximum cache entries\n */\n @Serialize()\n @Property({ type: 'number', label: 'Cache Size', min: 100, max: 10000 })\n cacheMaxEntries: number = 1000;\n\n /**\n * @zh 缓存过期时间(毫秒),0 表示不过期\n * @en Cache TTL in milliseconds, 0 means no expiration\n */\n @Serialize()\n @Property({ type: 'number', label: 'Cache TTL (ms)', min: 0, max: 60000 })\n cacheTtlMs: number = 5000;\n\n // =========================================================================\n // 调试配置 | Debug Configuration\n // =========================================================================\n\n /**\n * @zh 是否显示调试信息\n * @en Whether to show debug info\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Debug Mode' })\n debugMode: boolean = false;\n\n /**\n * @zh 是否显示网格\n * @en Whether to show grid\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Show Grid' })\n showGrid: boolean = false;\n\n /**\n * @zh 是否显示路径\n * @en Whether to show paths\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Show Paths' })\n showPaths: boolean = false;\n\n // =========================================================================\n // 运行时实例(不序列化)| Runtime Instances (not serialized)\n // =========================================================================\n\n /**\n * @zh 地图实例\n * @en Map instance\n */\n map: IPathfindingMap | null = null;\n\n /**\n * @zh 增量寻路器实例\n * @en Incremental pathfinder instance\n */\n pathfinder: IIncrementalPathfinder | null = null;\n\n /**\n * @zh 路径平滑器实例\n * @en Path smoother instance\n */\n smoother: IPathSmoother | null = null;\n\n /**\n * @zh 是否已初始化\n * @en Whether initialized\n */\n initialized: boolean = false;\n\n // =========================================================================\n // 统计信息 | Statistics\n // =========================================================================\n\n /**\n * @zh 当前活跃请求数\n * @en Current active request count\n */\n activeRequests: number = 0;\n\n /**\n * @zh 本帧使用的迭代次数\n * @en Iterations used this frame\n */\n iterationsUsedThisFrame: number = 0;\n\n /**\n * @zh 本帧处理的代理数\n * @en Agents processed this frame\n */\n agentsProcessedThisFrame: number = 0;\n\n /**\n * @zh 缓存命中次数\n * @en Cache hit count\n */\n cacheHits: number = 0;\n\n /**\n * @zh 缓存未命中次数\n * @en Cache miss count\n */\n cacheMisses: number = 0;\n\n // =========================================================================\n // 公共方法 | Public Methods\n // =========================================================================\n\n /**\n * @zh 设置网格单元格是否可通行\n * @en Set grid cell walkability\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @param walkable - @zh 是否可通行 @en Is walkable\n */\n setWalkable(x: number, y: number, walkable: boolean): void {\n if (this.map && 'setWalkable' in this.map) {\n (this.map as { setWalkable(x: number, y: number, walkable: boolean): void })\n .setWalkable(x, y, walkable);\n\n if (this.pathfinder) {\n this.pathfinder.notifyObstacleChange(x - 1, y - 1, x + 1, y + 1);\n }\n }\n }\n\n /**\n * @zh 设置矩形区域是否可通行\n * @en Set rectangular area walkability\n *\n * @param x - @zh 起始 X @en Start X\n * @param y - @zh 起始 Y @en Start Y\n * @param width - @zh 宽度 @en Width\n * @param height - @zh 高度 @en Height\n * @param walkable - @zh 是否可通行 @en Is walkable\n */\n setRectWalkable(\n x: number,\n y: number,\n rectWidth: number,\n rectHeight: number,\n walkable: boolean\n ): void {\n if (this.map && 'setRectWalkable' in this.map) {\n (this.map as { setRectWalkable(x: number, y: number, w: number, h: number, walkable: boolean): void })\n .setRectWalkable(x, y, rectWidth, rectHeight, walkable);\n\n if (this.pathfinder) {\n this.pathfinder.notifyObstacleChange(\n x - 1,\n y - 1,\n x + rectWidth + 1,\n y + rectHeight + 1\n );\n }\n }\n }\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @returns @zh 是否可通行 @en Is walkable\n */\n isWalkable(x: number, y: number): boolean {\n return this.map?.isWalkable(x, y) ?? false;\n }\n\n /**\n * @zh 重置统计信息\n * @en Reset statistics\n */\n resetStats(): void {\n this.iterationsUsedThisFrame = 0;\n this.agentsProcessedThisFrame = 0;\n }\n\n /**\n * @zh 获取剩余迭代预算\n * @en Get remaining iteration budget\n *\n * @returns @zh 剩余预算 @en Remaining budget\n */\n getRemainingBudget(): number {\n return Math.max(0, this.iterationsBudget - this.iterationsUsedThisFrame);\n }\n\n /**\n * @zh 获取缓存统计信息\n * @en Get cache statistics\n *\n * @returns @zh 缓存统计 @en Cache statistics\n */\n getCacheStats(): { enabled: boolean; hits: number; misses: number; hitRate: number } {\n const pathfinderWithCache = this.pathfinder as { getCacheStats?: () => { hits: number; misses: number; hitRate: number } };\n if (pathfinderWithCache?.getCacheStats) {\n const stats = pathfinderWithCache.getCacheStats();\n this.cacheHits = stats.hits;\n this.cacheMisses = stats.misses;\n return {\n enabled: this.enableCache,\n hits: stats.hits,\n misses: stats.misses,\n hitRate: stats.hitRate\n };\n }\n return {\n enabled: this.enableCache,\n hits: this.cacheHits,\n misses: this.cacheMisses,\n hitRate: this.cacheHits + this.cacheMisses > 0\n ? this.cacheHits / (this.cacheHits + this.cacheMisses)\n : 0\n };\n }\n\n /**\n * @zh 组件从实体移除时调用\n * @en Called when component is removed from entity\n */\n public onRemovedFromEntity(): void {\n if (this.pathfinder) {\n this.pathfinder.clear();\n }\n\n this.map = null;\n this.pathfinder = null;\n this.smoother = null;\n this.initialized = false;\n }\n}\n","/**\n * @zh 寻路系统\n * @en Pathfinding System\n */\n\nimport {\n EntitySystem,\n Matcher,\n ECSSystem,\n type Entity\n} from '@esengine/ecs-framework';\nimport { PathfindingAgentComponent } from './PathfindingAgentComponent';\nimport { PathfindingMapComponent } from './PathfindingMapComponent';\nimport { PathfindingState } from '../core/IIncrementalPathfinding';\nimport type { IIncrementalPathfinder, IPathProgress } from '../core/IIncrementalPathfinding';\nimport { IncrementalAStarPathfinder } from '../core/IncrementalAStarPathfinder';\nimport { GridMap } from '../grid/GridMap';\nimport { LineOfSightSmoother, CatmullRomSmoother, CombinedSmoother } from '../smoothing/PathSmoother';\nimport { PathValidator } from '../core/PathValidator';\n\n// =============================================================================\n// 代理队列项 | Agent Queue Item\n// =============================================================================\n\n/**\n * @zh 代理队列项\n * @en Agent queue item\n */\ninterface AgentQueueItem {\n entity: Entity;\n component: PathfindingAgentComponent;\n}\n\n// =============================================================================\n// 寻路系统 | Pathfinding System\n// =============================================================================\n\n/**\n * @zh 寻路系统\n * @en Pathfinding System\n *\n * @zh 处理所有 PathfindingAgentComponent,支持时间切片和动态重规划\n * @en Processes all PathfindingAgentComponents, supports time slicing and dynamic replanning\n *\n * @example\n * ```typescript\n * // Add system to scene\n * scene.addSystem(new PathfindingSystem());\n *\n * // Create map entity\n * const mapEntity = scene.createEntity('Map');\n * mapEntity.addComponent(new PathfindingMapComponent());\n *\n * // Create agents\n * const agent = scene.createEntity('Agent');\n * const pathAgent = agent.addComponent(new PathfindingAgentComponent());\n * pathAgent.requestPathTo(50, 50);\n *\n * // System handles pathfinding automatically each frame\n * ```\n */\n@ECSSystem('Pathfinding', { updateOrder: 0 })\nexport class PathfindingSystem extends EntitySystem {\n private mapEntity: Entity | null = null;\n private mapComponent: PathfindingMapComponent | null = null;\n private pathValidator: PathValidator;\n\n private agentQueue: AgentQueueItem[] = [];\n private frameCounter: number = 0;\n\n constructor() {\n super(Matcher.all(PathfindingAgentComponent));\n this.pathValidator = new PathValidator();\n }\n\n /**\n * @zh 系统初始化\n * @en System initialization\n */\n protected onInitialize(): void {\n this.findMapEntity();\n this.initializeMap();\n }\n\n /**\n * @zh 系统激活时调用\n * @en Called when system is enabled\n */\n protected onEnable(): void {\n this.findMapEntity();\n }\n\n /**\n * @zh 处理实体\n * @en Process entities\n */\n protected process(entities: readonly Entity[]): void {\n if (!this.mapComponent?.pathfinder) {\n this.findMapEntity();\n if (!this.mapComponent?.pathfinder) {\n return;\n }\n }\n\n this.frameCounter++;\n this.mapComponent.resetStats();\n\n this.buildAgentQueue(entities);\n\n this.processAgentsWithBudget();\n\n this.validatePaths(entities);\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n /**\n * @zh 查找地图实体\n * @en Find map entity\n */\n private findMapEntity(): void {\n if (!this.scene) return;\n\n const entities = this.scene.entities.findEntitiesWithComponent(PathfindingMapComponent);\n if (entities.length > 0) {\n const entity = entities[0]!;\n const mapComp = entity.getComponent(PathfindingMapComponent);\n if (mapComp) {\n this.mapEntity = entity;\n this.mapComponent = mapComp;\n\n if (!mapComp.initialized) {\n this.initializeMap();\n }\n }\n }\n }\n\n /**\n * @zh 初始化地图\n * @en Initialize map\n */\n private initializeMap(): void {\n if (!this.mapComponent) return;\n if (this.mapComponent.initialized) return;\n\n if (!this.mapComponent.map) {\n if (this.mapComponent.mapType === 'grid') {\n this.mapComponent.map = new GridMap(\n this.mapComponent.width,\n this.mapComponent.height,\n {\n allowDiagonal: this.mapComponent.allowDiagonal,\n avoidCorners: this.mapComponent.avoidCorners\n }\n );\n }\n }\n\n if (!this.mapComponent.pathfinder && this.mapComponent.map) {\n this.mapComponent.pathfinder = new IncrementalAStarPathfinder(\n this.mapComponent.map,\n {\n enableCache: this.mapComponent.enableCache,\n cacheConfig: {\n maxEntries: this.mapComponent.cacheMaxEntries,\n ttlMs: this.mapComponent.cacheTtlMs\n }\n }\n );\n }\n\n if (!this.mapComponent.smoother && this.mapComponent.enableSmoothing) {\n switch (this.mapComponent.smoothingType) {\n case 'catmullrom':\n this.mapComponent.smoother = new CatmullRomSmoother();\n break;\n case 'combined':\n this.mapComponent.smoother = new CombinedSmoother();\n break;\n case 'los':\n default:\n this.mapComponent.smoother = new LineOfSightSmoother();\n break;\n }\n }\n\n this.mapComponent.initialized = true;\n }\n\n /**\n * @zh 构建代理优先级队列\n * @en Build agent priority queue\n */\n private buildAgentQueue(entities: readonly Entity[]): void {\n this.agentQueue.length = 0;\n\n for (const entity of entities) {\n const agent = entity.getComponent(PathfindingAgentComponent);\n if (!agent) continue;\n\n if (!agent.hasRequest &&\n (agent.state === PathfindingState.Idle ||\n agent.state === PathfindingState.Completed ||\n agent.state === PathfindingState.Cancelled)) {\n continue;\n }\n\n this.agentQueue.push({ entity, component: agent });\n }\n\n this.agentQueue.sort((a, b) => a.component.priority - b.component.priority);\n }\n\n /**\n * @zh 使用预算处理代理\n * @en Process agents with budget\n */\n private processAgentsWithBudget(): void {\n const pathfinder = this.mapComponent!.pathfinder!;\n const maxAgents = this.mapComponent!.maxAgentsPerFrame;\n let remainingBudget = this.mapComponent!.iterationsBudget;\n let agentsProcessed = 0;\n\n for (const { component: agent } of this.agentQueue) {\n if (agentsProcessed >= maxAgents || remainingBudget <= 0) {\n break;\n }\n\n if (agent.hasRequest && agent.state === PathfindingState.Idle) {\n this.startNewRequest(agent, pathfinder);\n }\n\n if (agent.state === PathfindingState.InProgress) {\n const iterations = Math.min(\n agent.maxIterationsPerFrame,\n remainingBudget\n );\n\n const progress = pathfinder.step(agent.currentRequestId, iterations);\n this.updateAgentFromProgress(agent, progress, pathfinder);\n\n remainingBudget -= progress.nodesSearched;\n this.mapComponent!.iterationsUsedThisFrame += progress.nodesSearched;\n }\n\n agentsProcessed++;\n }\n\n this.mapComponent!.agentsProcessedThisFrame = agentsProcessed;\n }\n\n /**\n * @zh 启动新的寻路请求\n * @en Start new pathfinding request\n */\n private startNewRequest(\n agent: PathfindingAgentComponent,\n pathfinder: IIncrementalPathfinder\n ): void {\n if (agent.currentRequestId >= 0) {\n pathfinder.cancel(agent.currentRequestId);\n pathfinder.cleanup(agent.currentRequestId);\n }\n\n const request = pathfinder.requestPath(\n agent.x,\n agent.y,\n agent.targetX,\n agent.targetY,\n { priority: agent.priority }\n );\n\n agent.currentRequestId = request.id;\n agent.state = PathfindingState.InProgress;\n agent.hasRequest = false;\n agent.progress = 0;\n agent.path = [];\n agent.pathIndex = 0;\n\n this.mapComponent!.activeRequests++;\n }\n\n /**\n * @zh 从进度更新代理状态\n * @en Update agent state from progress\n */\n private updateAgentFromProgress(\n agent: PathfindingAgentComponent,\n progress: IPathProgress,\n pathfinder: IIncrementalPathfinder\n ): void {\n agent.state = progress.state;\n agent.progress = progress.estimatedProgress;\n\n agent.onPathProgress?.(progress.estimatedProgress);\n\n if (progress.state === PathfindingState.Completed) {\n const result = pathfinder.getResult(agent.currentRequestId);\n if (result && result.found) {\n const smoother = this.mapComponent?.smoother;\n const map = this.mapComponent?.map;\n\n if (smoother && map && this.mapComponent?.enableSmoothing) {\n agent.path = smoother.smooth(result.path, map);\n } else {\n agent.path = [...result.path];\n }\n\n agent.pathIndex = 0;\n agent.pathCost = result.cost;\n\n agent.onPathComplete?.(true, agent.path);\n } else {\n agent.path = [];\n agent.state = PathfindingState.Failed;\n agent.onPathComplete?.(false, []);\n }\n\n pathfinder.cleanup(agent.currentRequestId);\n this.mapComponent!.activeRequests--;\n } else if (progress.state === PathfindingState.Failed) {\n agent.path = [];\n agent.onPathComplete?.(false, []);\n pathfinder.cleanup(agent.currentRequestId);\n this.mapComponent!.activeRequests--;\n }\n }\n\n /**\n * @zh 周期性验证路径有效性\n * @en Periodically validate path validity\n */\n private validatePaths(entities: readonly Entity[]): void {\n const map = this.mapComponent?.map;\n if (!map) return;\n\n for (const entity of entities) {\n const agent = entity.getComponent(PathfindingAgentComponent);\n if (!agent || !agent.enableDynamicReplan) continue;\n if (agent.path.length === 0 || agent.isPathComplete()) continue;\n\n if (this.frameCounter - agent.lastValidationFrame < agent.validationInterval) {\n continue;\n }\n\n agent.lastValidationFrame = this.frameCounter;\n\n const checkEnd = Math.min(\n agent.pathIndex + agent.lookaheadDistance,\n agent.path.length\n );\n\n const result = this.pathValidator.validatePath(\n agent.path,\n agent.pathIndex,\n checkEnd,\n map\n );\n\n if (!result.valid) {\n agent.x = agent.path[agent.pathIndex]?.x ?? agent.x;\n agent.y = agent.path[agent.pathIndex]?.y ?? agent.y;\n agent.requestPathTo(agent.targetX, agent.targetY);\n }\n }\n }\n}\n"],"mappings":"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","names":["Component","ECSComponent","Serializable","Serialize","Property","PathfindingAgentComponent","Component","x","y","targetX","targetY","hasRequest","priority","maxIterationsPerFrame","enableDynamicReplan","lookaheadDistance","validationInterval","state","PathfindingState","Idle","currentRequestId","path","pathIndex","pathCost","progress","lastValidationFrame","onPathComplete","onPathProgress","requestPathTo","cancelPath","Cancelled","getNextWaypoint","length","advanceWaypoint","isPathComplete","isSearching","InProgress","hasValidPath","Completed","getRemainingWaypointCount","Math","max","getPathLength","reset","onRemovedFromEntity","undefined","type","label","min","version","typeId","Component","ECSComponent","Serializable","Serialize","Property","PathfindingMapComponent","Component","mapType","width","height","allowDiagonal","avoidCorners","maxAgentsPerFrame","iterationsBudget","enableSmoothing","smoothingType","enableCache","cacheMaxEntries","cacheTtlMs","debugMode","showGrid","showPaths","map","pathfinder","smoother","initialized","activeRequests","iterationsUsedThisFrame","agentsProcessedThisFrame","cacheHits","cacheMisses","setWalkable","x","y","walkable","notifyObstacleChange","setRectWalkable","rectWidth","rectHeight","isWalkable","resetStats","getRemainingBudget","Math","max","getCacheStats","pathfinderWithCache","stats","hits","misses","enabled","hitRate","onRemovedFromEntity","clear","type","label","options","value","min","version","typeId","EntitySystem","Matcher","ECSSystem","PathfindingSystem","EntitySystem","Matcher","all","PathfindingAgentComponent","mapEntity","mapComponent","pathValidator","agentQueue","frameCounter","PathValidator","onInitialize","findMapEntity","initializeMap","onEnable","process","entities","pathfinder","resetStats","buildAgentQueue","processAgentsWithBudget","validatePaths","scene","findEntitiesWithComponent","PathfindingMapComponent","length","entity","mapComp","getComponent","initialized","map","mapType","GridMap","width","height","allowDiagonal","avoidCorners","IncrementalAStarPathfinder","enableCache","cacheConfig","maxEntries","cacheMaxEntries","ttlMs","cacheTtlMs","smoother","enableSmoothing","smoothingType","CatmullRomSmoother","CombinedSmoother","LineOfSightSmoother","agent","hasRequest","state","PathfindingState","Idle","Completed","Cancelled","push","component","sort","a","b","priority","maxAgents","maxAgentsPerFrame","remainingBudget","iterationsBudget","agentsProcessed","startNewRequest","InProgress","iterations","Math","min","maxIterationsPerFrame","progress","step","currentRequestId","updateAgentFromProgress","nodesSearched","iterationsUsedThisFrame","agentsProcessedThisFrame","cancel","cleanup","request","requestPath","x","y","targetX","targetY","id","path","pathIndex","activeRequests","estimatedProgress","onPathProgress","result","getResult","found","smooth","pathCost","cost","onPathComplete","Failed","enableDynamicReplan","isPathComplete","lastValidationFrame","validationInterval","checkEnd","lookaheadDistance","validatePath","valid","requestPathTo","updateOrder"]}
1
+ {"version":3,"sources":["../src/ecs/PathfindingAgentComponent.ts","../src/ecs/PathfindingMapComponent.ts","../src/ecs/PathfindingSystem.ts","../src/ecs/AvoidanceAgentComponent.ts","../src/ecs/AvoidanceWorldComponent.ts","../src/ecs/LocalAvoidanceSystem.ts"],"sourcesContent":["/**\n * @zh 寻路代理组件\n * @en Pathfinding Agent Component\n */\n\nimport {\n Component,\n ECSComponent,\n Serializable,\n Serialize,\n Property\n} from '@esengine/ecs-framework';\nimport type { IPoint } from '../core/IPathfinding';\nimport { PathfindingState } from '../core/IIncrementalPathfinding';\n\n// =============================================================================\n// 寻路代理组件 | Pathfinding Agent Component\n// =============================================================================\n\n/**\n * @zh 寻路代理组件\n * @en Pathfinding Agent Component\n *\n * @zh 附加到需要寻路的实体上,管理寻路请求和结果\n * @en Attach to entities that need pathfinding, manages path requests and results\n *\n * @example\n * ```typescript\n * const entity = scene.createEntity('Agent');\n * const agent = entity.addComponent(new PathfindingAgentComponent());\n *\n * // Set initial position\n * agent.x = 10;\n * agent.y = 10;\n *\n * // Request path to target\n * agent.requestPathTo(50, 50);\n *\n * // In movement system, follow the path\n * const waypoint = agent.getNextWaypoint();\n * if (waypoint) {\n * // Move towards waypoint\n * // When reached, call agent.advanceWaypoint()\n * }\n * ```\n */\n@ECSComponent('PathfindingAgent')\n@Serializable({ version: 1, typeId: 'PathfindingAgent' })\nexport class PathfindingAgentComponent extends Component {\n // =========================================================================\n // 位置属性 | Position Properties\n // =========================================================================\n\n /**\n * @zh 当前位置 X 坐标\n * @en Current position X coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Position X' })\n x: number = 0;\n\n /**\n * @zh 当前位置 Y 坐标\n * @en Current position Y coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Position Y' })\n y: number = 0;\n\n // =========================================================================\n // 目标属性 | Target Properties\n // =========================================================================\n\n /**\n * @zh 目标位置 X 坐标\n * @en Target position X coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Target X' })\n targetX: number = 0;\n\n /**\n * @zh 目标位置 Y 坐标\n * @en Target position Y coordinate\n */\n @Serialize()\n @Property({ type: 'number', label: 'Target Y' })\n targetY: number = 0;\n\n /**\n * @zh 是否有新的寻路请求待处理\n * @en Whether there is a new path request pending\n */\n hasRequest: boolean = false;\n\n // =========================================================================\n // 配置属性 | Configuration Properties\n // =========================================================================\n\n /**\n * @zh 寻路优先级(数值越小优先级越高)\n * @en Pathfinding priority (lower number = higher priority)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Priority', min: 0, max: 100 })\n priority: number = 50;\n\n /**\n * @zh 每帧最大迭代次数\n * @en Maximum iterations per frame\n */\n @Serialize()\n @Property({ type: 'number', label: 'Max Iterations/Frame', min: 10, max: 1000 })\n maxIterationsPerFrame: number = 100;\n\n /**\n * @zh 是否启用动态重规划\n * @en Whether dynamic replanning is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Dynamic Replan' })\n enableDynamicReplan: boolean = true;\n\n /**\n * @zh 向前探测距离(用于障碍物检测)\n * @en Lookahead distance for obstacle detection\n */\n @Serialize()\n @Property({ type: 'number', label: 'Lookahead Distance', min: 1, max: 20 })\n lookaheadDistance: number = 5;\n\n /**\n * @zh 路径验证间隔(帧数)\n * @en Path validation interval (in frames)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Validation Interval', min: 1, max: 60 })\n validationInterval: number = 10;\n\n // =========================================================================\n // 运行时状态(不序列化)| Runtime State (not serialized)\n // =========================================================================\n\n /**\n * @zh 当前寻路状态\n * @en Current pathfinding state\n */\n state: PathfindingState = PathfindingState.Idle;\n\n /**\n * @zh 当前请求 ID\n * @en Current request ID\n */\n currentRequestId: number = -1;\n\n /**\n * @zh 当前路径点列表\n * @en Current path waypoints\n */\n path: IPoint[] = [];\n\n /**\n * @zh 当前路径索引\n * @en Current path index\n */\n pathIndex: number = 0;\n\n /**\n * @zh 路径总代价\n * @en Total path cost\n */\n pathCost: number = 0;\n\n /**\n * @zh 寻路进度 (0-1)\n * @en Pathfinding progress (0-1)\n */\n progress: number = 0;\n\n /**\n * @zh 上次验证的帧号\n * @en Last validation frame number\n */\n lastValidationFrame: number = 0;\n\n /**\n * @zh 寻路完成回调\n * @en Pathfinding complete callback\n */\n onPathComplete?: (found: boolean, path: readonly IPoint[]) => void;\n\n /**\n * @zh 寻路进度回调\n * @en Pathfinding progress callback\n */\n onPathProgress?: (progress: number) => void;\n\n // =========================================================================\n // 公共方法 | Public Methods\n // =========================================================================\n\n /**\n * @zh 请求寻路到目标位置\n * @en Request path to target position\n *\n * @param targetX - @zh 目标 X 坐标 @en Target X coordinate\n * @param targetY - @zh 目标 Y 坐标 @en Target Y coordinate\n */\n requestPathTo(targetX: number, targetY: number): void {\n this.targetX = targetX;\n this.targetY = targetY;\n this.hasRequest = true;\n this.state = PathfindingState.Idle;\n this.progress = 0;\n }\n\n /**\n * @zh 取消当前寻路\n * @en Cancel current pathfinding\n */\n cancelPath(): void {\n this.hasRequest = false;\n this.state = PathfindingState.Cancelled;\n this.path = [];\n this.pathIndex = 0;\n this.progress = 0;\n this.currentRequestId = -1;\n }\n\n /**\n * @zh 获取下一个路径点\n * @en Get next waypoint\n *\n * @returns @zh 下一个路径点或 null @en Next waypoint or null\n */\n getNextWaypoint(): IPoint | null {\n if (this.pathIndex < this.path.length) {\n return this.path[this.pathIndex];\n }\n return null;\n }\n\n /**\n * @zh 前进到下一个路径点\n * @en Advance to next waypoint\n */\n advanceWaypoint(): void {\n if (this.pathIndex < this.path.length) {\n this.pathIndex++;\n }\n }\n\n /**\n * @zh 检查是否到达路径终点\n * @en Check if reached path end\n *\n * @returns @zh 是否到达终点 @en Whether reached end\n */\n isPathComplete(): boolean {\n return this.pathIndex >= this.path.length;\n }\n\n /**\n * @zh 检查是否正在寻路\n * @en Check if pathfinding is in progress\n *\n * @returns @zh 是否正在寻路 @en Whether pathfinding is in progress\n */\n isSearching(): boolean {\n return this.state === PathfindingState.InProgress;\n }\n\n /**\n * @zh 检查是否有有效路径\n * @en Check if has valid path\n *\n * @returns @zh 是否有有效路径 @en Whether has valid path\n */\n hasValidPath(): boolean {\n return this.state === PathfindingState.Completed && this.path.length > 0;\n }\n\n /**\n * @zh 获取剩余路径点数量\n * @en Get remaining waypoint count\n *\n * @returns @zh 剩余路径点数量 @en Remaining waypoint count\n */\n getRemainingWaypointCount(): number {\n return Math.max(0, this.path.length - this.pathIndex);\n }\n\n /**\n * @zh 获取当前路径的总长度\n * @en Get total path length\n *\n * @returns @zh 路径总长度 @en Total path length\n */\n getPathLength(): number {\n return this.path.length;\n }\n\n /**\n * @zh 重置组件状态\n * @en Reset component state\n */\n reset(): void {\n this.state = PathfindingState.Idle;\n this.currentRequestId = -1;\n this.path = [];\n this.pathIndex = 0;\n this.pathCost = 0;\n this.progress = 0;\n this.hasRequest = false;\n this.lastValidationFrame = 0;\n }\n\n /**\n * @zh 组件从实体移除时调用\n * @en Called when component is removed from entity\n */\n public onRemovedFromEntity(): void {\n this.reset();\n this.onPathComplete = undefined;\n this.onPathProgress = undefined;\n }\n}\n","/**\n * @zh 寻路地图组件\n * @en Pathfinding Map Component\n */\n\nimport {\n Component,\n ECSComponent,\n Serializable,\n Serialize,\n Property\n} from '@esengine/ecs-framework';\nimport type { IPathfindingMap, IPathSmoother } from '../core/IPathfinding';\nimport type { IIncrementalPathfinder } from '../core/IIncrementalPathfinding';\n\n// =============================================================================\n// 地图类型 | Map Type\n// =============================================================================\n\n/**\n * @zh 地图类型\n * @en Map type\n */\nexport type PathfindingMapType = 'grid' | 'navmesh';\n\n// =============================================================================\n// 寻路地图组件 | Pathfinding Map Component\n// =============================================================================\n\n/**\n * @zh 寻路地图组件\n * @en Pathfinding Map Component\n *\n * @zh 挂载在场景实体上,持有地图实例和增量寻路器\n * @en Attached to scene entity, holds map instance and incremental pathfinder\n *\n * @example\n * ```typescript\n * const mapEntity = scene.createEntity('PathfindingMap');\n * const mapComp = mapEntity.addComponent(new PathfindingMapComponent());\n *\n * // Configure map\n * mapComp.width = 100;\n * mapComp.height = 100;\n * mapComp.iterationsBudget = 2000;\n *\n * // Map and pathfinder will be initialized by PathfindingSystem\n * ```\n */\n@ECSComponent('PathfindingMap')\n@Serializable({ version: 1, typeId: 'PathfindingMap' })\nexport class PathfindingMapComponent extends Component {\n // =========================================================================\n // 地图配置 | Map Configuration\n // =========================================================================\n\n /**\n * @zh 地图类型\n * @en Map type\n */\n @Serialize()\n @Property({\n type: 'enum',\n label: 'Map Type',\n options: [\n { value: 'grid', label: 'Grid' },\n { value: 'navmesh', label: 'NavMesh' }\n ]\n })\n mapType: PathfindingMapType = 'grid';\n\n /**\n * @zh 网格宽度(仅 grid 类型)\n * @en Grid width (grid type only)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Map Width', min: 1, max: 10000 })\n width: number = 100;\n\n /**\n * @zh 网格高度(仅 grid 类型)\n * @en Grid height (grid type only)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Map Height', min: 1, max: 10000 })\n height: number = 100;\n\n /**\n * @zh 是否允许对角移动\n * @en Whether diagonal movement is allowed\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Allow Diagonal' })\n allowDiagonal: boolean = true;\n\n /**\n * @zh 是否避免穿角\n * @en Whether to avoid corner cutting\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Avoid Corners' })\n avoidCorners: boolean = true;\n\n // =========================================================================\n // 系统配置 | System Configuration\n // =========================================================================\n\n /**\n * @zh 每帧处理的最大代理数\n * @en Maximum agents processed per frame\n */\n @Serialize()\n @Property({ type: 'number', label: 'Max Agents/Frame', min: 1, max: 100 })\n maxAgentsPerFrame: number = 10;\n\n /**\n * @zh 每帧总迭代次数预算\n * @en Total iterations budget per frame\n */\n @Serialize()\n @Property({ type: 'number', label: 'Iterations Budget', min: 100, max: 10000 })\n iterationsBudget: number = 1000;\n\n /**\n * @zh 是否启用路径平滑\n * @en Whether path smoothing is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Enable Smoothing' })\n enableSmoothing: boolean = true;\n\n /**\n * @zh 路径平滑类型\n * @en Path smoothing type\n */\n @Serialize()\n @Property({\n type: 'enum',\n label: 'Smoothing Type',\n options: [\n { value: 'los', label: 'Line of Sight' },\n { value: 'catmullrom', label: 'Catmull-Rom' },\n { value: 'combined', label: 'Combined' }\n ]\n })\n smoothingType: 'los' | 'catmullrom' | 'combined' = 'los';\n\n // =========================================================================\n // 缓存配置 | Cache Configuration\n // =========================================================================\n\n /**\n * @zh 是否启用路径缓存\n * @en Whether path caching is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Enable Cache' })\n enableCache: boolean = true;\n\n /**\n * @zh 缓存最大条目数\n * @en Maximum cache entries\n */\n @Serialize()\n @Property({ type: 'number', label: 'Cache Size', min: 100, max: 10000 })\n cacheMaxEntries: number = 1000;\n\n /**\n * @zh 缓存过期时间(毫秒),0 表示不过期\n * @en Cache TTL in milliseconds, 0 means no expiration\n */\n @Serialize()\n @Property({ type: 'number', label: 'Cache TTL (ms)', min: 0, max: 60000 })\n cacheTtlMs: number = 5000;\n\n // =========================================================================\n // 调试配置 | Debug Configuration\n // =========================================================================\n\n /**\n * @zh 是否显示调试信息\n * @en Whether to show debug info\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Debug Mode' })\n debugMode: boolean = false;\n\n /**\n * @zh 是否显示网格\n * @en Whether to show grid\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Show Grid' })\n showGrid: boolean = false;\n\n /**\n * @zh 是否显示路径\n * @en Whether to show paths\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Show Paths' })\n showPaths: boolean = false;\n\n // =========================================================================\n // 运行时实例(不序列化)| Runtime Instances (not serialized)\n // =========================================================================\n\n /**\n * @zh 地图实例\n * @en Map instance\n */\n map: IPathfindingMap | null = null;\n\n /**\n * @zh 增量寻路器实例\n * @en Incremental pathfinder instance\n */\n pathfinder: IIncrementalPathfinder | null = null;\n\n /**\n * @zh 路径平滑器实例\n * @en Path smoother instance\n */\n smoother: IPathSmoother | null = null;\n\n /**\n * @zh 是否已初始化\n * @en Whether initialized\n */\n initialized: boolean = false;\n\n // =========================================================================\n // 统计信息 | Statistics\n // =========================================================================\n\n /**\n * @zh 当前活跃请求数\n * @en Current active request count\n */\n activeRequests: number = 0;\n\n /**\n * @zh 本帧使用的迭代次数\n * @en Iterations used this frame\n */\n iterationsUsedThisFrame: number = 0;\n\n /**\n * @zh 本帧处理的代理数\n * @en Agents processed this frame\n */\n agentsProcessedThisFrame: number = 0;\n\n /**\n * @zh 缓存命中次数\n * @en Cache hit count\n */\n cacheHits: number = 0;\n\n /**\n * @zh 缓存未命中次数\n * @en Cache miss count\n */\n cacheMisses: number = 0;\n\n // =========================================================================\n // 公共方法 | Public Methods\n // =========================================================================\n\n /**\n * @zh 设置网格单元格是否可通行\n * @en Set grid cell walkability\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @param walkable - @zh 是否可通行 @en Is walkable\n */\n setWalkable(x: number, y: number, walkable: boolean): void {\n if (this.map && 'setWalkable' in this.map) {\n (this.map as { setWalkable(x: number, y: number, walkable: boolean): void })\n .setWalkable(x, y, walkable);\n\n if (this.pathfinder) {\n this.pathfinder.notifyObstacleChange(x - 1, y - 1, x + 1, y + 1);\n }\n }\n }\n\n /**\n * @zh 设置矩形区域是否可通行\n * @en Set rectangular area walkability\n *\n * @param x - @zh 起始 X @en Start X\n * @param y - @zh 起始 Y @en Start Y\n * @param width - @zh 宽度 @en Width\n * @param height - @zh 高度 @en Height\n * @param walkable - @zh 是否可通行 @en Is walkable\n */\n setRectWalkable(\n x: number,\n y: number,\n rectWidth: number,\n rectHeight: number,\n walkable: boolean\n ): void {\n if (this.map && 'setRectWalkable' in this.map) {\n (this.map as { setRectWalkable(x: number, y: number, w: number, h: number, walkable: boolean): void })\n .setRectWalkable(x, y, rectWidth, rectHeight, walkable);\n\n if (this.pathfinder) {\n this.pathfinder.notifyObstacleChange(\n x - 1,\n y - 1,\n x + rectWidth + 1,\n y + rectHeight + 1\n );\n }\n }\n }\n\n /**\n * @zh 检查位置是否可通行\n * @en Check if position is walkable\n *\n * @param x - @zh X 坐标 @en X coordinate\n * @param y - @zh Y 坐标 @en Y coordinate\n * @returns @zh 是否可通行 @en Is walkable\n */\n isWalkable(x: number, y: number): boolean {\n return this.map?.isWalkable(x, y) ?? false;\n }\n\n /**\n * @zh 重置统计信息\n * @en Reset statistics\n */\n resetStats(): void {\n this.iterationsUsedThisFrame = 0;\n this.agentsProcessedThisFrame = 0;\n }\n\n /**\n * @zh 获取剩余迭代预算\n * @en Get remaining iteration budget\n *\n * @returns @zh 剩余预算 @en Remaining budget\n */\n getRemainingBudget(): number {\n return Math.max(0, this.iterationsBudget - this.iterationsUsedThisFrame);\n }\n\n /**\n * @zh 获取缓存统计信息\n * @en Get cache statistics\n *\n * @returns @zh 缓存统计 @en Cache statistics\n */\n getCacheStats(): { enabled: boolean; hits: number; misses: number; hitRate: number } {\n const pathfinderWithCache = this.pathfinder as { getCacheStats?: () => { hits: number; misses: number; hitRate: number } };\n if (pathfinderWithCache?.getCacheStats) {\n const stats = pathfinderWithCache.getCacheStats();\n this.cacheHits = stats.hits;\n this.cacheMisses = stats.misses;\n return {\n enabled: this.enableCache,\n hits: stats.hits,\n misses: stats.misses,\n hitRate: stats.hitRate\n };\n }\n return {\n enabled: this.enableCache,\n hits: this.cacheHits,\n misses: this.cacheMisses,\n hitRate: this.cacheHits + this.cacheMisses > 0\n ? this.cacheHits / (this.cacheHits + this.cacheMisses)\n : 0\n };\n }\n\n /**\n * @zh 组件从实体移除时调用\n * @en Called when component is removed from entity\n */\n public onRemovedFromEntity(): void {\n if (this.pathfinder) {\n this.pathfinder.clear();\n }\n\n this.map = null;\n this.pathfinder = null;\n this.smoother = null;\n this.initialized = false;\n }\n}\n","/**\n * @zh 寻路系统\n * @en Pathfinding System\n */\n\nimport {\n EntitySystem,\n Matcher,\n ECSSystem,\n type Entity\n} from '@esengine/ecs-framework';\nimport { PathfindingAgentComponent } from './PathfindingAgentComponent';\nimport { PathfindingMapComponent } from './PathfindingMapComponent';\nimport { PathfindingState } from '../core/IIncrementalPathfinding';\nimport type { IIncrementalPathfinder, IPathProgress } from '../core/IIncrementalPathfinding';\nimport { IncrementalAStarPathfinder } from '../core/IncrementalAStarPathfinder';\nimport { GridMap } from '../grid/GridMap';\nimport { LineOfSightSmoother, CatmullRomSmoother, CombinedSmoother } from '../smoothing/PathSmoother';\nimport { PathValidator } from '../core/PathValidator';\n\n// =============================================================================\n// 代理队列项 | Agent Queue Item\n// =============================================================================\n\n/**\n * @zh 代理队列项\n * @en Agent queue item\n */\ninterface AgentQueueItem {\n entity: Entity;\n component: PathfindingAgentComponent;\n}\n\n// =============================================================================\n// 寻路系统 | Pathfinding System\n// =============================================================================\n\n/**\n * @zh 寻路系统\n * @en Pathfinding System\n *\n * @zh 处理所有 PathfindingAgentComponent,支持时间切片和动态重规划\n * @en Processes all PathfindingAgentComponents, supports time slicing and dynamic replanning\n *\n * @example\n * ```typescript\n * // Add system to scene\n * scene.addSystem(new PathfindingSystem());\n *\n * // Create map entity\n * const mapEntity = scene.createEntity('Map');\n * mapEntity.addComponent(new PathfindingMapComponent());\n *\n * // Create agents\n * const agent = scene.createEntity('Agent');\n * const pathAgent = agent.addComponent(new PathfindingAgentComponent());\n * pathAgent.requestPathTo(50, 50);\n *\n * // System handles pathfinding automatically each frame\n * ```\n */\n@ECSSystem('Pathfinding', { updateOrder: 0 })\nexport class PathfindingSystem extends EntitySystem {\n private mapEntity: Entity | null = null;\n private mapComponent: PathfindingMapComponent | null = null;\n private pathValidator: PathValidator;\n\n private agentQueue: AgentQueueItem[] = [];\n private frameCounter: number = 0;\n\n constructor() {\n super(Matcher.all(PathfindingAgentComponent));\n this.pathValidator = new PathValidator();\n }\n\n /**\n * @zh 系统初始化\n * @en System initialization\n */\n protected onInitialize(): void {\n this.findMapEntity();\n this.initializeMap();\n }\n\n /**\n * @zh 系统激活时调用\n * @en Called when system is enabled\n */\n protected onEnable(): void {\n this.findMapEntity();\n }\n\n /**\n * @zh 处理实体\n * @en Process entities\n */\n protected process(entities: readonly Entity[]): void {\n if (!this.mapComponent?.pathfinder) {\n this.findMapEntity();\n if (!this.mapComponent?.pathfinder) {\n return;\n }\n }\n\n this.frameCounter++;\n this.mapComponent.resetStats();\n\n this.buildAgentQueue(entities);\n\n this.processAgentsWithBudget();\n\n this.validatePaths(entities);\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n /**\n * @zh 查找地图实体\n * @en Find map entity\n */\n private findMapEntity(): void {\n if (!this.scene) return;\n\n const entities = this.scene.entities.findEntitiesWithComponent(PathfindingMapComponent);\n if (entities.length > 0) {\n const entity = entities[0]!;\n const mapComp = entity.getComponent(PathfindingMapComponent);\n if (mapComp) {\n this.mapEntity = entity;\n this.mapComponent = mapComp;\n\n if (!mapComp.initialized) {\n this.initializeMap();\n }\n }\n }\n }\n\n /**\n * @zh 初始化地图\n * @en Initialize map\n */\n private initializeMap(): void {\n if (!this.mapComponent) return;\n if (this.mapComponent.initialized) return;\n\n if (!this.mapComponent.map) {\n if (this.mapComponent.mapType === 'grid') {\n this.mapComponent.map = new GridMap(\n this.mapComponent.width,\n this.mapComponent.height,\n {\n allowDiagonal: this.mapComponent.allowDiagonal,\n avoidCorners: this.mapComponent.avoidCorners\n }\n );\n }\n }\n\n if (!this.mapComponent.pathfinder && this.mapComponent.map) {\n this.mapComponent.pathfinder = new IncrementalAStarPathfinder(\n this.mapComponent.map,\n {\n enableCache: this.mapComponent.enableCache,\n cacheConfig: {\n maxEntries: this.mapComponent.cacheMaxEntries,\n ttlMs: this.mapComponent.cacheTtlMs\n }\n }\n );\n }\n\n if (!this.mapComponent.smoother && this.mapComponent.enableSmoothing) {\n switch (this.mapComponent.smoothingType) {\n case 'catmullrom':\n this.mapComponent.smoother = new CatmullRomSmoother();\n break;\n case 'combined':\n this.mapComponent.smoother = new CombinedSmoother();\n break;\n case 'los':\n default:\n this.mapComponent.smoother = new LineOfSightSmoother();\n break;\n }\n }\n\n this.mapComponent.initialized = true;\n }\n\n /**\n * @zh 构建代理优先级队列\n * @en Build agent priority queue\n */\n private buildAgentQueue(entities: readonly Entity[]): void {\n this.agentQueue.length = 0;\n\n for (const entity of entities) {\n const agent = entity.getComponent(PathfindingAgentComponent);\n if (!agent) continue;\n\n if (!agent.hasRequest &&\n (agent.state === PathfindingState.Idle ||\n agent.state === PathfindingState.Completed ||\n agent.state === PathfindingState.Cancelled)) {\n continue;\n }\n\n this.agentQueue.push({ entity, component: agent });\n }\n\n this.agentQueue.sort((a, b) => a.component.priority - b.component.priority);\n }\n\n /**\n * @zh 使用预算处理代理\n * @en Process agents with budget\n */\n private processAgentsWithBudget(): void {\n const pathfinder = this.mapComponent!.pathfinder!;\n const maxAgents = this.mapComponent!.maxAgentsPerFrame;\n let remainingBudget = this.mapComponent!.iterationsBudget;\n let agentsProcessed = 0;\n\n for (const { component: agent } of this.agentQueue) {\n if (agentsProcessed >= maxAgents || remainingBudget <= 0) {\n break;\n }\n\n if (agent.hasRequest && agent.state === PathfindingState.Idle) {\n this.startNewRequest(agent, pathfinder);\n }\n\n if (agent.state === PathfindingState.InProgress) {\n const iterations = Math.min(\n agent.maxIterationsPerFrame,\n remainingBudget\n );\n\n const progress = pathfinder.step(agent.currentRequestId, iterations);\n this.updateAgentFromProgress(agent, progress, pathfinder);\n\n remainingBudget -= progress.nodesSearched;\n this.mapComponent!.iterationsUsedThisFrame += progress.nodesSearched;\n }\n\n agentsProcessed++;\n }\n\n this.mapComponent!.agentsProcessedThisFrame = agentsProcessed;\n }\n\n /**\n * @zh 启动新的寻路请求\n * @en Start new pathfinding request\n */\n private startNewRequest(\n agent: PathfindingAgentComponent,\n pathfinder: IIncrementalPathfinder\n ): void {\n if (agent.currentRequestId >= 0) {\n pathfinder.cancel(agent.currentRequestId);\n pathfinder.cleanup(agent.currentRequestId);\n }\n\n const request = pathfinder.requestPath(\n agent.x,\n agent.y,\n agent.targetX,\n agent.targetY,\n { priority: agent.priority }\n );\n\n agent.currentRequestId = request.id;\n agent.state = PathfindingState.InProgress;\n agent.hasRequest = false;\n agent.progress = 0;\n agent.path = [];\n agent.pathIndex = 0;\n\n this.mapComponent!.activeRequests++;\n }\n\n /**\n * @zh 从进度更新代理状态\n * @en Update agent state from progress\n */\n private updateAgentFromProgress(\n agent: PathfindingAgentComponent,\n progress: IPathProgress,\n pathfinder: IIncrementalPathfinder\n ): void {\n agent.state = progress.state;\n agent.progress = progress.estimatedProgress;\n\n agent.onPathProgress?.(progress.estimatedProgress);\n\n if (progress.state === PathfindingState.Completed) {\n const result = pathfinder.getResult(agent.currentRequestId);\n if (result && result.found) {\n const smoother = this.mapComponent?.smoother;\n const map = this.mapComponent?.map;\n\n if (smoother && map && this.mapComponent?.enableSmoothing) {\n agent.path = smoother.smooth(result.path, map);\n } else {\n agent.path = [...result.path];\n }\n\n agent.pathIndex = 0;\n agent.pathCost = result.cost;\n\n agent.onPathComplete?.(true, agent.path);\n } else {\n agent.path = [];\n agent.state = PathfindingState.Failed;\n agent.onPathComplete?.(false, []);\n }\n\n pathfinder.cleanup(agent.currentRequestId);\n this.mapComponent!.activeRequests--;\n } else if (progress.state === PathfindingState.Failed) {\n agent.path = [];\n agent.onPathComplete?.(false, []);\n pathfinder.cleanup(agent.currentRequestId);\n this.mapComponent!.activeRequests--;\n }\n }\n\n /**\n * @zh 周期性验证路径有效性\n * @en Periodically validate path validity\n */\n private validatePaths(entities: readonly Entity[]): void {\n const map = this.mapComponent?.map;\n if (!map) return;\n\n for (const entity of entities) {\n const agent = entity.getComponent(PathfindingAgentComponent);\n if (!agent || !agent.enableDynamicReplan) continue;\n if (agent.path.length === 0 || agent.isPathComplete()) continue;\n\n if (this.frameCounter - agent.lastValidationFrame < agent.validationInterval) {\n continue;\n }\n\n agent.lastValidationFrame = this.frameCounter;\n\n const checkEnd = Math.min(\n agent.pathIndex + agent.lookaheadDistance,\n agent.path.length\n );\n\n const result = this.pathValidator.validatePath(\n agent.path,\n agent.pathIndex,\n checkEnd,\n map\n );\n\n if (!result.valid) {\n agent.x = agent.path[agent.pathIndex]?.x ?? agent.x;\n agent.y = agent.path[agent.pathIndex]?.y ?? agent.y;\n agent.requestPathTo(agent.targetX, agent.targetY);\n }\n }\n }\n}\n","/**\n * @zh 避让代理组件\n * @en Avoidance Agent Component\n */\n\nimport {\n Component,\n ECSComponent,\n Serializable,\n Serialize,\n Property\n} from '@esengine/ecs-framework';\nimport { DEFAULT_AGENT_PARAMS } from '../avoidance/ILocalAvoidance';\n\n// =============================================================================\n// 避让代理组件 | Avoidance Agent Component\n// =============================================================================\n\n/**\n * @zh 避让代理组件\n * @en Avoidance Agent Component\n *\n * @zh 附加到需要局部避让的实体上,与 ORCA 系统配合使用\n * @en Attach to entities that need local avoidance, works with ORCA system\n *\n * @example\n * ```typescript\n * const entity = scene.createEntity('Monster');\n *\n * // 添加避让代理\n * const avoidance = entity.addComponent(new AvoidanceAgentComponent());\n * avoidance.radius = 0.5;\n * avoidance.maxSpeed = 5.0;\n *\n * // 设置首选速度(朝向目标)\n * avoidance.setPreferredVelocityTowards(targetX, targetY, currentX, currentY);\n *\n * // 系统计算后,使用新速度更新位置\n * // After system computes, use new velocity to update position\n * x += avoidance.newVelocityX * deltaTime;\n * y += avoidance.newVelocityY * deltaTime;\n * ```\n */\n@ECSComponent('AvoidanceAgent')\n@Serializable({ version: 1, typeId: 'AvoidanceAgent' })\nexport class AvoidanceAgentComponent extends Component {\n // =========================================================================\n // 物理属性 | Physical Properties\n // =========================================================================\n\n /**\n * @zh 代理半径\n * @en Agent radius\n *\n * @zh 用于碰撞检测和避让计算\n * @en Used for collision detection and avoidance computation\n */\n @Serialize()\n @Property({ type: 'number', label: 'Radius', min: 0.1, max: 10 })\n radius: number = DEFAULT_AGENT_PARAMS.radius;\n\n /**\n * @zh 最大速度\n * @en Maximum speed\n */\n @Serialize()\n @Property({ type: 'number', label: 'Max Speed', min: 0.1, max: 100 })\n maxSpeed: number = DEFAULT_AGENT_PARAMS.maxSpeed;\n\n // =========================================================================\n // ORCA 参数 | ORCA Parameters\n // =========================================================================\n\n /**\n * @zh 邻居检测距离\n * @en Neighbor detection distance\n *\n * @zh 只考虑此范围内的其他代理\n * @en Only considers other agents within this range\n */\n @Serialize()\n @Property({ type: 'number', label: 'Neighbor Dist', min: 1, max: 100 })\n neighborDist: number = DEFAULT_AGENT_PARAMS.neighborDist;\n\n /**\n * @zh 最大邻居数量\n * @en Maximum number of neighbors to consider\n *\n * @zh 限制计算量,优先考虑最近的邻居\n * @en Limits computation, prioritizes closest neighbors\n */\n @Serialize()\n @Property({ type: 'number', label: 'Max Neighbors', min: 1, max: 50 })\n maxNeighbors: number = DEFAULT_AGENT_PARAMS.maxNeighbors;\n\n /**\n * @zh 代理避让时间视野(秒)\n * @en Time horizon for agent avoidance (seconds)\n *\n * @zh 更大的值会让代理更早开始避让,但可能导致过于保守\n * @en Larger values make agents start avoiding earlier, but may be too conservative\n */\n @Serialize()\n @Property({ type: 'number', label: 'Time Horizon', min: 0.1, max: 10 })\n timeHorizon: number = DEFAULT_AGENT_PARAMS.timeHorizon;\n\n /**\n * @zh 障碍物避让时间视野(秒)\n * @en Time horizon for obstacle avoidance (seconds)\n */\n @Serialize()\n @Property({ type: 'number', label: 'Time Horizon Obst', min: 0.1, max: 10 })\n timeHorizonObst: number = DEFAULT_AGENT_PARAMS.timeHorizonObst;\n\n // =========================================================================\n // 位置和速度(运行时状态)| Position & Velocity (Runtime State)\n // =========================================================================\n\n /**\n * @zh 当前位置 X\n * @en Current position X\n *\n * @zh 如果实体有 Transform 组件,系统会自动同步\n * @en If entity has Transform component, system will sync automatically\n */\n positionX: number = 0;\n\n /**\n * @zh 当前位置 Y\n * @en Current position Y\n */\n positionY: number = 0;\n\n /**\n * @zh 当前速度 X\n * @en Current velocity X\n */\n velocityX: number = 0;\n\n /**\n * @zh 当前速度 Y\n * @en Current velocity Y\n */\n velocityY: number = 0;\n\n /**\n * @zh 首选速度 X(通常指向目标方向)\n * @en Preferred velocity X (usually towards target)\n */\n preferredVelocityX: number = 0;\n\n /**\n * @zh 首选速度 Y\n * @en Preferred velocity Y\n */\n preferredVelocityY: number = 0;\n\n /**\n * @zh ORCA 计算的新速度 X\n * @en New velocity X computed by ORCA\n */\n newVelocityX: number = 0;\n\n /**\n * @zh ORCA 计算的新速度 Y\n * @en New velocity Y computed by ORCA\n */\n newVelocityY: number = 0;\n\n // =========================================================================\n // 配置选项 | Configuration Options\n // =========================================================================\n\n /**\n * @zh 是否启用避让\n * @en Whether avoidance is enabled\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Enabled' })\n enabled: boolean = true;\n\n /**\n * @zh 是否自动应用新速度\n * @en Whether to automatically apply new velocity\n *\n * @zh 如果为 true,系统会在计算后自动将 newVelocity 赋值给 velocity\n * @en If true, system will automatically assign newVelocity to velocity after computation\n */\n @Serialize()\n @Property({ type: 'boolean', label: 'Auto Apply' })\n autoApplyVelocity: boolean = true;\n\n // =========================================================================\n // 公共方法 | Public Methods\n // =========================================================================\n\n /**\n * @zh 设置位置\n * @en Set position\n */\n setPosition(x: number, y: number): void {\n this.positionX = x;\n this.positionY = y;\n }\n\n /**\n * @zh 设置当前速度\n * @en Set current velocity\n */\n setVelocity(x: number, y: number): void {\n this.velocityX = x;\n this.velocityY = y;\n }\n\n /**\n * @zh 设置首选速度\n * @en Set preferred velocity\n */\n setPreferredVelocity(x: number, y: number): void {\n this.preferredVelocityX = x;\n this.preferredVelocityY = y;\n }\n\n /**\n * @zh 设置首选速度朝向目标\n * @en Set preferred velocity towards target\n *\n * @param targetX - @zh 目标 X @en Target X\n * @param targetY - @zh 目标 Y @en Target Y\n * @param currentX - @zh 当前 X(可选,默认使用 positionX)@en Current X (optional, defaults to positionX)\n * @param currentY - @zh 当前 Y(可选,默认使用 positionY)@en Current Y (optional, defaults to positionY)\n */\n setPreferredVelocityTowards(\n targetX: number,\n targetY: number,\n currentX?: number,\n currentY?: number\n ): void {\n const x = currentX ?? this.positionX;\n const y = currentY ?? this.positionY;\n\n const dx = targetX - x;\n const dy = targetY - y;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n if (dist > 0.0001) {\n const speed = Math.min(this.maxSpeed, dist);\n this.preferredVelocityX = (dx / dist) * speed;\n this.preferredVelocityY = (dy / dist) * speed;\n } else {\n this.preferredVelocityX = 0;\n this.preferredVelocityY = 0;\n }\n }\n\n /**\n * @zh 应用 ORCA 计算的新速度\n * @en Apply new velocity computed by ORCA\n */\n applyNewVelocity(): void {\n this.velocityX = this.newVelocityX;\n this.velocityY = this.newVelocityY;\n }\n\n /**\n * @zh 获取新速度的长度\n * @en Get length of new velocity\n */\n getNewSpeed(): number {\n return Math.sqrt(\n this.newVelocityX * this.newVelocityX +\n this.newVelocityY * this.newVelocityY\n );\n }\n\n /**\n * @zh 获取当前速度的长度\n * @en Get length of current velocity\n */\n getCurrentSpeed(): number {\n return Math.sqrt(\n this.velocityX * this.velocityX +\n this.velocityY * this.velocityY\n );\n }\n\n /**\n * @zh 停止代理\n * @en Stop the agent\n */\n stop(): void {\n this.velocityX = 0;\n this.velocityY = 0;\n this.preferredVelocityX = 0;\n this.preferredVelocityY = 0;\n this.newVelocityX = 0;\n this.newVelocityY = 0;\n }\n\n /**\n * @zh 重置组件状态\n * @en Reset component state\n */\n reset(): void {\n this.positionX = 0;\n this.positionY = 0;\n this.velocityX = 0;\n this.velocityY = 0;\n this.preferredVelocityX = 0;\n this.preferredVelocityY = 0;\n this.newVelocityX = 0;\n this.newVelocityY = 0;\n }\n\n /**\n * @zh 组件从实体移除时调用\n * @en Called when component is removed from entity\n */\n public onRemovedFromEntity(): void {\n this.reset();\n }\n}\n","/**\n * @zh 避让世界组件\n * @en Avoidance World Component\n */\n\nimport {\n Component,\n ECSComponent,\n Serializable,\n Serialize,\n Property\n} from '@esengine/ecs-framework';\nimport type { IObstacle, IORCASolverConfig } from '../avoidance/ILocalAvoidance';\nimport { DEFAULT_ORCA_CONFIG } from '../avoidance/ILocalAvoidance';\nimport type { ORCASolver } from '../avoidance/ORCASolver';\nimport type { KDTree } from '../avoidance/KDTree';\n\n// =============================================================================\n// 避让世界组件 | Avoidance World Component\n// =============================================================================\n\n/**\n * @zh 避让世界组件\n * @en Avoidance World Component\n *\n * @zh 挂载在场景实体上,持有 ORCA 求解器和静态障碍物\n * @en Attached to scene entity, holds ORCA solver and static obstacles\n *\n * @example\n * ```typescript\n * const worldEntity = scene.createEntity('AvoidanceWorld');\n * const world = worldEntity.addComponent(new AvoidanceWorldComponent());\n *\n * // 添加静态障碍物(墙壁)\n * world.addObstacle({\n * vertices: [\n * { x: 0, y: 0 },\n * { x: 10, y: 0 },\n * { x: 10, y: 1 },\n * { x: 0, y: 1 }\n * ]\n * });\n *\n * // LocalAvoidanceSystem 会自动使用此组件\n * ```\n */\n@ECSComponent('AvoidanceWorld')\n@Serializable({ version: 1, typeId: 'AvoidanceWorld' })\nexport class AvoidanceWorldComponent extends Component {\n // =========================================================================\n // ORCA 配置 | ORCA Configuration\n // =========================================================================\n\n /**\n * @zh 默认时间视野(代理)\n * @en Default time horizon for agents\n */\n @Serialize()\n @Property({ type: 'number', label: 'Time Horizon', min: 0.1, max: 10 })\n defaultTimeHorizon: number = DEFAULT_ORCA_CONFIG.defaultTimeHorizon;\n\n /**\n * @zh 默认时间视野(障碍物)\n * @en Default time horizon for obstacles\n */\n @Serialize()\n @Property({ type: 'number', label: 'Time Horizon Obst', min: 0.1, max: 10 })\n defaultTimeHorizonObst: number = DEFAULT_ORCA_CONFIG.defaultTimeHorizonObst;\n\n /**\n * @zh 时间步长\n * @en Time step\n */\n @Serialize()\n @Property({ type: 'number', label: 'Time Step', min: 0.001, max: 0.1 })\n timeStep: number = DEFAULT_ORCA_CONFIG.timeStep;\n\n // =========================================================================\n // 运行时实例(不序列化)| Runtime Instances (not serialized)\n // =========================================================================\n\n /**\n * @zh ORCA 求解器实例\n * @en ORCA solver instance\n */\n solver: ORCASolver | null = null;\n\n /**\n * @zh KD-Tree 实例\n * @en KD-Tree instance\n */\n kdTree: KDTree | null = null;\n\n /**\n * @zh 静态障碍物列表\n * @en List of static obstacles\n */\n obstacles: IObstacle[] = [];\n\n /**\n * @zh 是否已初始化\n * @en Whether initialized\n */\n initialized: boolean = false;\n\n // =========================================================================\n // 统计信息 | Statistics\n // =========================================================================\n\n /**\n * @zh 当前代理数量\n * @en Current agent count\n */\n agentCount: number = 0;\n\n /**\n * @zh 本帧处理的代理数\n * @en Agents processed this frame\n */\n agentsProcessedThisFrame: number = 0;\n\n /**\n * @zh 本帧 ORCA 计算耗时(毫秒)\n * @en ORCA computation time this frame (ms)\n */\n computeTimeMs: number = 0;\n\n // =========================================================================\n // 公共方法 | Public Methods\n // =========================================================================\n\n /**\n * @zh 获取 ORCA 配置\n * @en Get ORCA configuration\n */\n getConfig(): IORCASolverConfig {\n return {\n defaultTimeHorizon: this.defaultTimeHorizon,\n defaultTimeHorizonObst: this.defaultTimeHorizonObst,\n timeStep: this.timeStep\n };\n }\n\n /**\n * @zh 添加静态障碍物\n * @en Add static obstacle\n *\n * @param obstacle - @zh 障碍物(顶点列表,逆时针顺序)@en Obstacle (vertex list, counter-clockwise)\n */\n addObstacle(obstacle: IObstacle): void {\n this.obstacles.push(obstacle);\n }\n\n /**\n * @zh 添加矩形障碍物\n * @en Add rectangular obstacle\n *\n * @param x - @zh 左下角 X @en Bottom-left X\n * @param y - @zh 左下角 Y @en Bottom-left Y\n * @param width - @zh 宽度 @en Width\n * @param height - @zh 高度 @en Height\n */\n addRectObstacle(x: number, y: number, width: number, height: number): void {\n this.obstacles.push({\n vertices: [\n { x: x, y: y },\n { x: x + width, y: y },\n { x: x + width, y: y + height },\n { x: x, y: y + height }\n ]\n });\n }\n\n /**\n * @zh 移除所有障碍物\n * @en Remove all obstacles\n */\n clearObstacles(): void {\n this.obstacles = [];\n }\n\n /**\n * @zh 重置统计信息\n * @en Reset statistics\n */\n resetStats(): void {\n this.agentsProcessedThisFrame = 0;\n this.computeTimeMs = 0;\n }\n\n /**\n * @zh 组件从实体移除时调用\n * @en Called when component is removed from entity\n */\n public onRemovedFromEntity(): void {\n this.solver = null;\n this.kdTree = null;\n this.obstacles = [];\n this.initialized = false;\n }\n}\n","/**\n * @zh 局部避让系统\n * @en Local Avoidance System\n */\n\nimport {\n EntitySystem,\n Matcher,\n ECSSystem,\n type Entity\n} from '@esengine/ecs-framework';\nimport { AvoidanceAgentComponent } from './AvoidanceAgentComponent';\nimport { AvoidanceWorldComponent } from './AvoidanceWorldComponent';\nimport { PathfindingAgentComponent } from './PathfindingAgentComponent';\nimport { ORCASolver, createORCASolver } from '../avoidance/ORCASolver';\nimport { KDTree, createKDTree } from '../avoidance/KDTree';\nimport type { IAvoidanceAgent } from '../avoidance/ILocalAvoidance';\n\n// =============================================================================\n// 局部避让系统 | Local Avoidance System\n// =============================================================================\n\n/**\n * @zh 局部避让系统\n * @en Local Avoidance System\n *\n * @zh 使用 ORCA 算法计算代理的避让速度\n * @en Uses ORCA algorithm to compute avoidance velocities for agents\n *\n * @example\n * ```typescript\n * // 添加系统到场景\n * scene.addSystem(new LocalAvoidanceSystem());\n *\n * // 创建避让世界(可选,用于静态障碍物)\n * const worldEntity = scene.createEntity('AvoidanceWorld');\n * worldEntity.addComponent(new AvoidanceWorldComponent());\n *\n * // 创建代理\n * const agent = scene.createEntity('Agent');\n * const avoidance = agent.addComponent(new AvoidanceAgentComponent());\n *\n * // 可选:同时添加寻路代理,系统会自动同步位置\n * agent.addComponent(new PathfindingAgentComponent());\n *\n * // 每帧设置首选速度(朝向目标)\n * avoidance.setPreferredVelocityTowards(targetX, targetY);\n *\n * // 系统计算后,newVelocity 会被更新\n * // 如果 autoApplyVelocity = true,velocity 也会自动更新\n * ```\n */\n@ECSSystem('LocalAvoidance', { updateOrder: 50 })\nexport class LocalAvoidanceSystem extends EntitySystem {\n private worldEntity: Entity | null = null;\n private worldComponent: AvoidanceWorldComponent | null = null;\n\n private solver: ORCASolver | null = null;\n private kdTree: KDTree | null = null;\n\n constructor() {\n super(Matcher.all(AvoidanceAgentComponent));\n }\n\n /**\n * @zh 系统初始化\n * @en System initialization\n */\n protected onInitialize(): void {\n this.findWorldEntity();\n this.initializeSolver();\n }\n\n /**\n * @zh 系统激活时调用\n * @en Called when system is enabled\n */\n protected onEnable(): void {\n this.findWorldEntity();\n }\n\n /**\n * @zh 处理实体\n * @en Process entities\n */\n protected process(entities: readonly Entity[]): void {\n if (entities.length === 0) return;\n\n // 确保求解器已初始化\n if (!this.solver) {\n this.initializeSolver();\n }\n\n const startTime = performance.now();\n\n // 1. 收集所有代理数据\n const agents = this.collectAgentData(entities);\n\n // 2. 构建 KD-Tree\n this.kdTree!.build(agents);\n\n // 3. 获取静态障碍物\n const obstacles = this.worldComponent?.obstacles ?? [];\n\n // 4. 计算每个代理的新速度\n const deltaTime = this.worldComponent?.timeStep ?? (1 / 60);\n\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i]!;\n const component = entity.getComponent(AvoidanceAgentComponent)!;\n\n if (!component.enabled) continue;\n\n const agent = agents[i]!;\n\n // 查询邻居\n const neighborResults = this.kdTree!.queryNeighbors(\n agent.position,\n agent.neighborDist,\n agent.maxNeighbors,\n agent.id\n );\n\n const neighbors = neighborResults.map(r => r.agent);\n\n // ORCA 求解\n const newVelocity = this.solver!.computeNewVelocity(\n agent,\n neighbors,\n obstacles,\n deltaTime\n );\n\n // 更新组件\n component.newVelocityX = newVelocity.x;\n component.newVelocityY = newVelocity.y;\n\n // 自动应用新速度\n if (component.autoApplyVelocity) {\n component.applyNewVelocity();\n }\n }\n\n // 更新统计信息\n const endTime = performance.now();\n if (this.worldComponent) {\n this.worldComponent.agentCount = entities.length;\n this.worldComponent.agentsProcessedThisFrame = entities.length;\n this.worldComponent.computeTimeMs = endTime - startTime;\n }\n }\n\n // =========================================================================\n // 私有方法 | Private Methods\n // =========================================================================\n\n /**\n * @zh 查找世界实体\n * @en Find world entity\n */\n private findWorldEntity(): void {\n if (!this.scene) return;\n\n const entities = this.scene.entities.findEntitiesWithComponent(AvoidanceWorldComponent);\n if (entities.length > 0) {\n const entity = entities[0]!;\n const worldComp = entity.getComponent(AvoidanceWorldComponent);\n if (worldComp) {\n this.worldEntity = entity;\n this.worldComponent = worldComp;\n\n // 共享求解器和 KD-Tree 到世界组件\n if (this.solver && !worldComp.solver) {\n worldComp.solver = this.solver;\n }\n if (this.kdTree && !worldComp.kdTree) {\n worldComp.kdTree = this.kdTree;\n }\n worldComp.initialized = true;\n }\n }\n }\n\n /**\n * @zh 初始化求解器\n * @en Initialize solver\n */\n private initializeSolver(): void {\n const config = this.worldComponent?.getConfig();\n this.solver = createORCASolver(config);\n this.kdTree = createKDTree();\n\n if (this.worldComponent) {\n this.worldComponent.solver = this.solver;\n this.worldComponent.kdTree = this.kdTree;\n }\n }\n\n /**\n * @zh 收集代理数据\n * @en Collect agent data\n */\n private collectAgentData(entities: readonly Entity[]): IAvoidanceAgent[] {\n const agents: IAvoidanceAgent[] = [];\n\n for (const entity of entities) {\n const avoidance = entity.getComponent(AvoidanceAgentComponent)!;\n\n // 尝试从 PathfindingAgent 同步位置\n const pathAgent = entity.getComponent(PathfindingAgentComponent);\n if (pathAgent) {\n avoidance.positionX = pathAgent.x;\n avoidance.positionY = pathAgent.y;\n\n // 如果有有效路径,自动设置首选速度\n const waypoint = pathAgent.getNextWaypoint();\n if (waypoint && avoidance.preferredVelocityX === 0 && avoidance.preferredVelocityY === 0) {\n avoidance.setPreferredVelocityTowards(waypoint.x, waypoint.y);\n }\n }\n\n agents.push({\n id: entity.id,\n position: {\n x: avoidance.positionX,\n y: avoidance.positionY\n },\n velocity: {\n x: avoidance.velocityX,\n y: avoidance.velocityY\n },\n preferredVelocity: {\n x: avoidance.preferredVelocityX,\n y: avoidance.preferredVelocityY\n },\n radius: avoidance.radius,\n maxSpeed: avoidance.maxSpeed,\n neighborDist: avoidance.neighborDist,\n maxNeighbors: avoidance.maxNeighbors,\n timeHorizon: avoidance.timeHorizon,\n timeHorizonObst: avoidance.timeHorizonObst\n });\n }\n\n return agents;\n }\n}\n"],"mappings":"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","names":["Component","ECSComponent","Serializable","Serialize","Property","PathfindingAgentComponent","Component","x","y","targetX","targetY","hasRequest","priority","maxIterationsPerFrame","enableDynamicReplan","lookaheadDistance","validationInterval","state","PathfindingState","Idle","currentRequestId","path","pathIndex","pathCost","progress","lastValidationFrame","onPathComplete","onPathProgress","requestPathTo","cancelPath","Cancelled","getNextWaypoint","length","advanceWaypoint","isPathComplete","isSearching","InProgress","hasValidPath","Completed","getRemainingWaypointCount","Math","max","getPathLength","reset","onRemovedFromEntity","undefined","type","label","min","version","typeId","Component","ECSComponent","Serializable","Serialize","Property","PathfindingMapComponent","Component","mapType","width","height","allowDiagonal","avoidCorners","maxAgentsPerFrame","iterationsBudget","enableSmoothing","smoothingType","enableCache","cacheMaxEntries","cacheTtlMs","debugMode","showGrid","showPaths","map","pathfinder","smoother","initialized","activeRequests","iterationsUsedThisFrame","agentsProcessedThisFrame","cacheHits","cacheMisses","setWalkable","x","y","walkable","notifyObstacleChange","setRectWalkable","rectWidth","rectHeight","isWalkable","resetStats","getRemainingBudget","Math","max","getCacheStats","pathfinderWithCache","stats","hits","misses","enabled","hitRate","onRemovedFromEntity","clear","type","label","options","value","min","version","typeId","EntitySystem","Matcher","ECSSystem","PathfindingSystem","EntitySystem","Matcher","all","PathfindingAgentComponent","mapEntity","mapComponent","pathValidator","agentQueue","frameCounter","PathValidator","onInitialize","findMapEntity","initializeMap","onEnable","process","entities","pathfinder","resetStats","buildAgentQueue","processAgentsWithBudget","validatePaths","scene","findEntitiesWithComponent","PathfindingMapComponent","length","entity","mapComp","getComponent","initialized","map","mapType","GridMap","width","height","allowDiagonal","avoidCorners","IncrementalAStarPathfinder","enableCache","cacheConfig","maxEntries","cacheMaxEntries","ttlMs","cacheTtlMs","smoother","enableSmoothing","smoothingType","CatmullRomSmoother","CombinedSmoother","LineOfSightSmoother","agent","hasRequest","state","PathfindingState","Idle","Completed","Cancelled","push","component","sort","a","b","priority","maxAgents","maxAgentsPerFrame","remainingBudget","iterationsBudget","agentsProcessed","startNewRequest","InProgress","iterations","Math","min","maxIterationsPerFrame","progress","step","currentRequestId","updateAgentFromProgress","nodesSearched","iterationsUsedThisFrame","agentsProcessedThisFrame","cancel","cleanup","request","requestPath","x","y","targetX","targetY","id","path","pathIndex","activeRequests","estimatedProgress","onPathProgress","result","getResult","found","smooth","pathCost","cost","onPathComplete","Failed","enableDynamicReplan","isPathComplete","lastValidationFrame","validationInterval","checkEnd","lookaheadDistance","validatePath","valid","requestPathTo","updateOrder","Component","ECSComponent","Serializable","Serialize","Property","AvoidanceAgentComponent","Component","radius","DEFAULT_AGENT_PARAMS","maxSpeed","neighborDist","maxNeighbors","timeHorizon","timeHorizonObst","positionX","positionY","velocityX","velocityY","preferredVelocityX","preferredVelocityY","newVelocityX","newVelocityY","enabled","autoApplyVelocity","setPosition","x","y","setVelocity","setPreferredVelocity","setPreferredVelocityTowards","targetX","targetY","currentX","currentY","dx","dy","dist","Math","sqrt","speed","min","applyNewVelocity","getNewSpeed","getCurrentSpeed","stop","reset","onRemovedFromEntity","type","label","max","version","typeId","Component","ECSComponent","Serializable","Serialize","Property","AvoidanceWorldComponent","Component","defaultTimeHorizon","DEFAULT_ORCA_CONFIG","defaultTimeHorizonObst","timeStep","solver","kdTree","obstacles","initialized","agentCount","agentsProcessedThisFrame","computeTimeMs","getConfig","addObstacle","obstacle","push","addRectObstacle","x","y","width","height","vertices","clearObstacles","resetStats","onRemovedFromEntity","type","label","min","max","version","typeId","EntitySystem","Matcher","ECSSystem","LocalAvoidanceSystem","EntitySystem","Matcher","all","AvoidanceAgentComponent","worldEntity","worldComponent","solver","kdTree","onInitialize","findWorldEntity","initializeSolver","onEnable","process","entities","length","startTime","performance","now","agents","collectAgentData","build","obstacles","deltaTime","timeStep","i","entity","component","getComponent","enabled","agent","neighborResults","queryNeighbors","position","neighborDist","maxNeighbors","id","neighbors","map","r","newVelocity","computeNewVelocity","newVelocityX","x","newVelocityY","y","autoApplyVelocity","applyNewVelocity","endTime","agentCount","agentsProcessedThisFrame","computeTimeMs","scene","findEntitiesWithComponent","AvoidanceWorldComponent","worldComp","initialized","config","getConfig","createORCASolver","createKDTree","avoidance","pathAgent","PathfindingAgentComponent","positionX","positionY","waypoint","getNextWaypoint","preferredVelocityX","preferredVelocityY","setPreferredVelocityTowards","push","velocity","velocityX","velocityY","preferredVelocity","radius","maxSpeed","timeHorizon","timeHorizonObst","updateOrder"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { I as IPathfinder, a as IPathfindingMap, b as IPathfindingOptions, c as IPathResult, H as HeuristicFunction, d as IPathNode, e as IPoint, f as IIncrementalPathfinder, g as IIncrementalPathfindingOptions, h as IPathRequest, i as IPathProgress, j as IIncrementalPathResult, k as IPathValidator, l as IPathValidationResult, m as IPathSmoother } from './IIncrementalPathfinding-3qs7e_pO.js';
2
- export { D as DEFAULT_PATHFINDING_OPTIONS, t as DEFAULT_REPLANNING_CONFIG, E as EMPTY_PATH_RESULT, u as EMPTY_PROGRESS, s as IReplanningConfig, L as LineOfSightCheck, P as PathfindingState, q as chebyshevDistance, n as createPoint, p as euclideanDistance, o as manhattanDistance, r as octileDistance } from './IIncrementalPathfinding-3qs7e_pO.js';
1
+ import { I as IPathfinder, a as IPathfindingMap, b as IPathfindingOptions, c as IPathResult, H as HeuristicFunction, d as IPathNode, e as IPoint, f as IIncrementalPathfinder, g as IIncrementalPathfindingOptions, h as IPathRequest, i as IPathProgress, j as IIncrementalPathResult, k as IPathValidator, l as IPathValidationResult, m as IPathSmoother, n as IORCALine } from './KDTree-Bw4Faf2O.js';
2
+ export { G as DEFAULT_AGENT_PARAMS, F as DEFAULT_ORCA_CONFIG, D as DEFAULT_PATHFINDING_OPTIONS, u as DEFAULT_REPLANNING_CONFIG, E as EMPTY_PATH_RESULT, v as EMPTY_PROGRESS, w as IAvoidanceAgent, B as INeighborResult, z as IORCAResult, A as IORCASolver, y as IORCASolverConfig, x as IObstacle, t as IReplanningConfig, C as ISpatialIndex, K as KDTree, L as LineOfSightCheck, O as ORCASolver, P as PathfindingState, r as chebyshevDistance, M as createKDTree, J as createORCASolver, o as createPoint, q as euclideanDistance, p as manhattanDistance, s as octileDistance } from './KDTree-Bw4Faf2O.js';
3
+ import { IVector2, Vector2 } from '@esengine/ecs-framework-math';
4
+ export { IVector2 } from '@esengine/ecs-framework-math';
3
5
 
4
6
  /**
5
7
  * @zh 二叉堆(优先队列)
@@ -1431,4 +1433,27 @@ declare function createCatmullRomSmoother(segments?: number, tension?: number):
1431
1433
  */
1432
1434
  declare function createCombinedSmoother(curveSegments?: number, tension?: number): CombinedSmoother;
1433
1435
 
1434
- export { AStarPathfinder, BinaryHeap, CatmullRomSmoother, CombinedSmoother, DEFAULT_GRID_OPTIONS, DEFAULT_HPA_CONFIG, DEFAULT_PATH_CACHE_CONFIG, DIRECTIONS_4, DIRECTIONS_8, GridMap, GridNode, GridPathfinder, type GridPathfinderMode, HPAPathfinder, HeuristicFunction, type IChangeRegion, type IGridMapOptions, type IGridPathfinderConfig, type IHPAConfig, type IHeapIndexable, IIncrementalPathResult, IIncrementalPathfinder, type IIncrementalPathfinderConfig, IIncrementalPathfindingOptions, type INavPolygon, type IObstacleChange, type IPathCacheConfig, IPathNode, IPathProgress, IPathRequest, IPathResult, IPathSmoother, IPathValidationResult, IPathValidator, IPathfinder, IPathfindingMap, IPathfindingOptions, IPoint, type IPortal, IncrementalAStarPathfinder, IndexedBinaryHeap, JPSPathfinder, LineOfSightSmoother, NavMesh, ObstacleChangeManager, PathCache, PathValidator, bresenhamLineOfSight, createAStarPathfinder, createCatmullRomSmoother, createCombinedSmoother, createGridMap, createGridPathfinder, createHPAPathfinder, createIncrementalAStarPathfinder, createJPSPathfinder, createLineOfSightSmoother, createNavMesh, createObstacleChangeManager, createPathCache, createPathValidator, raycastLineOfSight };
1436
+ /**
1437
+ * @zh 2D 线性规划求解器
1438
+ * @en 2D Linear Programming Solver
1439
+ *
1440
+ * @zh 用于 ORCA 算法中的速度优化求解
1441
+ * @en Used for velocity optimization in ORCA algorithm
1442
+ */
1443
+
1444
+ /**
1445
+ * @zh 求解 ORCA 线性规划
1446
+ * @en Solve ORCA Linear Programming
1447
+ *
1448
+ * @zh 综合使用 2D 和 3D 线性规划求解最优速度
1449
+ * @en Use both 2D and 3D LP to solve for optimal velocity
1450
+ *
1451
+ * @param lines - @zh ORCA 约束线列表 @en List of ORCA constraint lines
1452
+ * @param numObstLines - @zh 障碍物约束线数量(优先级更高)@en Number of obstacle lines (higher priority)
1453
+ * @param maxSpeed - @zh 最大速度 @en Maximum speed
1454
+ * @param preferredVelocity - @zh 首选速度 @en Preferred velocity
1455
+ * @returns @zh 计算得到的新速度 @en Computed new velocity
1456
+ */
1457
+ declare function solveORCALinearProgram(lines: IORCALine[], numObstLines: number, maxSpeed: number, preferredVelocity: IVector2): Vector2;
1458
+
1459
+ export { AStarPathfinder, BinaryHeap, CatmullRomSmoother, CombinedSmoother, DEFAULT_GRID_OPTIONS, DEFAULT_HPA_CONFIG, DEFAULT_PATH_CACHE_CONFIG, DIRECTIONS_4, DIRECTIONS_8, GridMap, GridNode, GridPathfinder, type GridPathfinderMode, HPAPathfinder, HeuristicFunction, type IChangeRegion, type IGridMapOptions, type IGridPathfinderConfig, type IHPAConfig, type IHeapIndexable, IIncrementalPathResult, IIncrementalPathfinder, type IIncrementalPathfinderConfig, IIncrementalPathfindingOptions, type INavPolygon, IORCALine, type IObstacleChange, type IPathCacheConfig, IPathNode, IPathProgress, IPathRequest, IPathResult, IPathSmoother, IPathValidationResult, IPathValidator, IPathfinder, IPathfindingMap, IPathfindingOptions, IPoint, type IPortal, IncrementalAStarPathfinder, IndexedBinaryHeap, JPSPathfinder, LineOfSightSmoother, NavMesh, ObstacleChangeManager, PathCache, PathValidator, bresenhamLineOfSight, createAStarPathfinder, createCatmullRomSmoother, createCombinedSmoother, createGridMap, createGridPathfinder, createHPAPathfinder, createIncrementalAStarPathfinder, createJPSPathfinder, createLineOfSightSmoother, createNavMesh, createObstacleChangeManager, createPathCache, createPathValidator, raycastLineOfSight, solveORCALinearProgram };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  CatmullRomSmoother,
3
3
  CombinedSmoother,
4
+ DEFAULT_AGENT_PARAMS,
4
5
  DEFAULT_GRID_OPTIONS,
6
+ DEFAULT_ORCA_CONFIG,
5
7
  DEFAULT_PATHFINDING_OPTIONS,
6
8
  DEFAULT_PATH_CACHE_CONFIG,
7
9
  DIRECTIONS_4,
@@ -11,7 +13,9 @@ import {
11
13
  GridNode,
12
14
  IncrementalAStarPathfinder,
13
15
  IndexedBinaryHeap,
16
+ KDTree,
14
17
  LineOfSightSmoother,
18
+ ORCASolver,
15
19
  ObstacleChangeManager,
16
20
  PathCache,
17
21
  PathValidator,
@@ -21,7 +25,9 @@ import {
21
25
  createCombinedSmoother,
22
26
  createGridMap,
23
27
  createIncrementalAStarPathfinder,
28
+ createKDTree,
24
29
  createLineOfSightSmoother,
30
+ createORCASolver,
25
31
  createObstacleChangeManager,
26
32
  createPathCache,
27
33
  createPathValidator,
@@ -29,8 +35,9 @@ import {
29
35
  euclideanDistance,
30
36
  manhattanDistance,
31
37
  octileDistance,
32
- raycastLineOfSight
33
- } from "./chunk-TPT7Q3E3.js";
38
+ raycastLineOfSight,
39
+ solveORCALinearProgram
40
+ } from "./chunk-OA7ZZQMH.js";
34
41
  import {
35
42
  DEFAULT_REPLANNING_CONFIG,
36
43
  EMPTY_PROGRESS,
@@ -2364,8 +2371,10 @@ export {
2364
2371
  BinaryHeap,
2365
2372
  CatmullRomSmoother,
2366
2373
  CombinedSmoother,
2374
+ DEFAULT_AGENT_PARAMS,
2367
2375
  DEFAULT_GRID_OPTIONS,
2368
2376
  DEFAULT_HPA_CONFIG,
2377
+ DEFAULT_ORCA_CONFIG,
2369
2378
  DEFAULT_PATHFINDING_OPTIONS,
2370
2379
  DEFAULT_PATH_CACHE_CONFIG,
2371
2380
  DEFAULT_REPLANNING_CONFIG,
@@ -2380,8 +2389,10 @@ export {
2380
2389
  IncrementalAStarPathfinder,
2381
2390
  IndexedBinaryHeap,
2382
2391
  JPSPathfinder,
2392
+ KDTree,
2383
2393
  LineOfSightSmoother,
2384
2394
  NavMesh,
2395
+ ORCASolver,
2385
2396
  ObstacleChangeManager,
2386
2397
  PathCache,
2387
2398
  PathValidator,
@@ -2396,8 +2407,10 @@ export {
2396
2407
  createHPAPathfinder,
2397
2408
  createIncrementalAStarPathfinder,
2398
2409
  createJPSPathfinder,
2410
+ createKDTree,
2399
2411
  createLineOfSightSmoother,
2400
2412
  createNavMesh,
2413
+ createORCASolver,
2401
2414
  createObstacleChangeManager,
2402
2415
  createPathCache,
2403
2416
  createPathValidator,
@@ -2405,6 +2418,7 @@ export {
2405
2418
  euclideanDistance,
2406
2419
  manhattanDistance,
2407
2420
  octileDistance,
2408
- raycastLineOfSight
2421
+ raycastLineOfSight,
2422
+ solveORCALinearProgram
2409
2423
  };
2410
2424
  //# sourceMappingURL=index.js.map