From 0f8a73911f3a9718baa03b121da056adcbfb01f0 Mon Sep 17 00:00:00 2001 From: Thayol Date: Wed, 25 Dec 2024 11:19:01 +0900 Subject: [PATCH] check bi-directional paths in graph building --- src/entity.js | 25 +++++++++++++++---------- src/pathfind.js | 35 ++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/entity.js b/src/entity.js index 55de6d1..cb1b635 100644 --- a/src/entity.js +++ b/src/entity.js @@ -88,20 +88,21 @@ export default class Entity { async takeStep(distanceTraveled = 0) { const speed = (this.speed / (this.game?.tickBudget ?? 1000)) - distanceTraveled + const collidables = this.collidables() if (this.#dest != null) { - const fixedDest = SATX.clamp(SATX.fixCollisions(this.#dest, this.collidables(), this.radius), this.game?.width, this.game?.height, this.radius) + const fixedDest = SATX.clamp(SATX.fixCollisions(this.#dest, collidables, this.radius), this.game?.width, this.game?.height, this.radius) - if (this.#path.length < 1 || !this.#path.at(-1).equals(this.#dest)) { + if (this.#path.length < 1 || !this.#path.at(-1).equals(fixedDest)) { console.time('pathfinding') - console.time('waypoints') - const waypoints = (this.game?.unadjustedWaypoints.map(([unadjusted, direction]) => unadjusted.clone().add(direction.clone().multiplyScalar(this.radius))) ?? []).concat([this.position, fixedDest]) - console.timeEnd('waypoints') - console.time('graph') - const graph = Pathfind.buildGraph(waypoints, this.collidables(), this.radius) - console.timeEnd('graph') - console.time('path') + // console.time('waypoints') + const waypoints = this.waypoints().concat([this.position, fixedDest]) + // console.timeEnd('waypoints') + // console.time('graph') + const graph = Pathfind.buildGraph(waypoints, collidables, this.radius) + // console.timeEnd('graph') + // console.time('path') this.#path = Pathfind.shortestPath(graph, this.position, fixedDest) - console.timeEnd('path') + // console.timeEnd('path') console.timeEnd('pathfinding') } @@ -137,4 +138,8 @@ export default class Entity { this.takeStep(), ]) } + + waypoints() { + return this.game?.unadjustedWaypoints.map(([waypoint, direction]) => waypoint.clone().add(direction.clone().multiplyScalar(this.radius))) ?? [] + } } diff --git a/src/pathfind.js b/src/pathfind.js index 3972651..8620963 100644 --- a/src/pathfind.js +++ b/src/pathfind.js @@ -3,8 +3,11 @@ import PriorityQueue from "./priority-queue.js" import SATX from "./satx.js" export default class Pathfind { + static key(pos) { + return `${pos.x},${pos.y}` + } + static shortestPath(graph, start, goal) { - const key = (pos) => `${pos.x},${pos.y}` const queue = new PriorityQueue((a, b) => a[1] < b[1]) const visited = new Map() @@ -19,11 +22,13 @@ export default class Pathfind { return path } - if (!visited.has(key(waypoint)) || visited.get(key(waypoint)) > cost) { - visited.set(key(waypoint), cost) + const waypointKey = this.key(waypoint) + if (!visited.has(waypointKey) || visited.get(waypointKey) > cost) { + visited.set(waypointKey, cost) for (const { to, distance } of graph.filter(e => e.from.equals(waypoint))) { - if (!visited.has(key(to)) || visited.get(key(to)) > cost + distance) { + const toKey = this.key(to) + if (!visited.has(toKey) || visited.get(toKey) > cost + distance) { queue.push([[...path, to], cost + distance]) } } @@ -35,6 +40,7 @@ export default class Pathfind { static buildGraph(waypoints = [], colliders = [], radius = 0) { const graph = [] + const calculated = new Set() for (const from of waypoints) { for (const to of waypoints) { @@ -42,15 +48,22 @@ export default class Pathfind { continue } - const tunnel = SATX.entityTunnel(from, to, radius) - const collider = Entity.collider(from.x, from.y, radius) + const key = `${from.x},${from.y};${to.x},${to.y}` + if (!calculated.has(key)) { + calculated.add(key) + calculated.add(`${to.x},${to.y};${from.x},${from.y}`) - const tunnelClear = !SATX.collideObjects(tunnel, colliders) - const waypointAvailable = !SATX.collideObjects(collider, colliders) + const tunnel = SATX.entityTunnel(from, to, radius) + const collider = Entity.collider(from.x, from.y, radius) - if (waypointAvailable && tunnelClear) { - const distance = from.distanceTo(to) - graph.push({ from, to, distance }) + const tunnelClear = !SATX.collideObjects(tunnel, colliders) + const waypointAvailable = !SATX.collideObjects(collider, colliders) + + if (waypointAvailable && tunnelClear) { + const distance = from.distanceTo(to) + graph.push({ from, to, distance }) + graph.push({ from: to, to: from, distance }) + } } } }