70 lines
1.9 KiB
JavaScript
70 lines
1.9 KiB
JavaScript
import Entity from "./entity.js"
|
|
import PriorityQueue from "./priority-queue.js"
|
|
import SATX from "./satx.js"
|
|
|
|
export default class Pathfind {
|
|
static keyFor(pos) {
|
|
return `${pos.x},${pos.y}`
|
|
}
|
|
|
|
static shortestPath(graph, start, goal) {
|
|
const queue = new PriorityQueue((a, b) => a[1] < b[1])
|
|
const visited = new Map()
|
|
|
|
queue.push([[[start, null]], 0])
|
|
|
|
while (!queue.isEmpty()) {
|
|
const [path, cost] = queue.pop()
|
|
const waypoint = path.at(-1).at(0)
|
|
|
|
if (waypoint.equals(goal)) {
|
|
path.shift()
|
|
return path
|
|
}
|
|
|
|
const key = this.keyFor(waypoint)
|
|
if (!visited.has(key) || visited.get(key) > cost) {
|
|
visited.set(key, cost)
|
|
|
|
for (const { to, direction, distance } of graph.filter(e => e.from.equals(waypoint))) {
|
|
const keyTo = this.keyFor(to)
|
|
if (!visited.has(keyTo) || visited.get(keyTo) > cost + distance) {
|
|
queue.push([[...path, [to, direction]], cost + distance])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
static buildGraph(toWaypoints, colliders, fromWaypoints = null) {
|
|
const graph = []
|
|
const calculated = new Set()
|
|
|
|
for (const [from, reverseDirection] of (fromWaypoints ?? toWaypoints)) {
|
|
for (const [to, direction] of toWaypoints) {
|
|
if (from.equals(to)) {
|
|
continue
|
|
}
|
|
|
|
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 lineOfSight = !SATX.collideObjects(SATX.line(from, to), colliders)
|
|
|
|
if (lineOfSight) {
|
|
const distance = from.distanceTo(to)
|
|
graph.push({ from, to, distance, direction })
|
|
graph.push({ to: from, from: to, distance, direction: reverseDirection })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return graph
|
|
}
|
|
}
|