diff --git a/src/entity.js b/src/entity.js index 89d1c72..2cc0ee9 100644 --- a/src/entity.js +++ b/src/entity.js @@ -87,6 +87,8 @@ export default class Entity { this.position.set(x, y) } + // TODO: waypoints go out of bounds + // TODO: pathfinding stops if wall is clicked (did you forget to fix the destination?) async takeStep(distanceTraveled = 0) { const speed = (this.speed / (this.game?.tickBudget ?? 1000)) - distanceTraveled const collidables = this.collidables() @@ -100,11 +102,11 @@ export default class Entity { const goal = SATX.vectorToFloat32Array(fixedDest) const nonUniqueWaypoints = this.waypoints().map((w) => SATX.vectorToFloat32Array(w)).concat([start, goal]) const waypoints = Pathfind.uniqueWaypoints(nonUniqueWaypoints) + console.timeEnd('waypoints') console.time('graph') const graph = Pathfind.buildGraph(waypoints, collidables, this.radius) - // console.log(Pathfind.formatFloat32Array(graph, 5, true)) // const tunnels = [] // for (let i = 0; i < graph.length; i += 5) { // tunnels.push(SATX.entityTunnel(graph[i], graph[i + 1], graph[i + 2], graph[i + 3], 1)) diff --git a/src/index.js b/src/index.js index 83cf888..afa3fdc 100644 --- a/src/index.js +++ b/src/index.js @@ -46,78 +46,78 @@ app.listen(port, () => { entity1.radius = 50 game.spawn_entity(entity1) - // const entity2 = new Entity() - // entity2.id = '2' - // entity2.teleport(110, 110) - // entity2.radius = 50 - // game.spawn_entity(entity2) - - const triangle = new Terrain([ - { x: 400, y: 200 }, - { x: 400, y: 600 }, - { x: 600, y: 300 }, - ]) - triangle.id = 'triangle' - game.add_terrain(triangle) + const entity2 = new Entity() + entity2.id = '2' + entity2.teleport(110, 110) + entity2.radius = 50 + game.spawn_entity(entity2) - // const horseshoe = new Terrain([ + // const triangle = new Terrain([ // { x: 400, y: 200 }, - // { x: 600, y: 200 }, - // { x: 700, y: 300 }, - // { x: 650, y: 600 }, // { x: 400, y: 600 }, - // { x: 400, y: 450 }, - // { x: 600, y: 500 }, // { x: 600, y: 300 }, - // { x: 400, y: 300 }, // ]) - // horseshoe.id = 'horseshoe' - // game.add_terrain(horseshoe) + // triangle.id = 'triangle' + // game.add_terrain(triangle) - // const stopsign = new Terrain([ - // { x: 800, y: 800 }, - // { x: 900, y: 900 }, - // { x: 900, y: 1000 }, - // { x: 800, y: 1100 }, - // { x: 800, y: 1100 }, - // { x: 700, y: 1100 }, - // { x: 600, y: 1000 }, - // { x: 600, y: 900 }, - // { x: 700, y: 800 }, - // ]) - // stopsign.id = 'stopsign' - // game.add_terrain(stopsign) + const horseshoe = new Terrain([ + { x: 400, y: 200 }, + { x: 600, y: 200 }, + { x: 700, y: 300 }, + { x: 650, y: 600 }, + { x: 400, y: 600 }, + { x: 400, y: 450 }, + { x: 600, y: 500 }, + { x: 600, y: 300 }, + { x: 400, y: 300 }, + ]) + horseshoe.id = 'horseshoe' + game.add_terrain(horseshoe) - // const box = new Terrain([ - // { x: 1200, y: 700 }, - // { x: 1200, y: 800 }, - // { x: 1300, y: 800 }, - // { x: 1300, y: 700 }, - // ]) - // box.id = 'box' - // game.add_terrain(box) + const stopsign = new Terrain([ + { x: 800, y: 800 }, + { x: 900, y: 900 }, + { x: 900, y: 1000 }, + { x: 800, y: 1100 }, + { x: 800, y: 1100 }, + { x: 700, y: 1100 }, + { x: 600, y: 1000 }, + { x: 600, y: 900 }, + { x: 700, y: 800 }, + ]) + stopsign.id = 'stopsign' + game.add_terrain(stopsign) - // const diamond = new Terrain([ - // { x: 1000, y: 300 }, - // { x: 1100, y: 400 }, - // { x: 1000, y: 500 }, - // { x: 900, y: 400 }, - // ]) - // diamond.id = 'diamond' - // game.add_terrain(diamond) + const box = new Terrain([ + { x: 1200, y: 700 }, + { x: 1200, y: 800 }, + { x: 1300, y: 800 }, + { x: 1300, y: 700 }, + ]) + box.id = 'box' + game.add_terrain(box) - // const pole = new Terrain([ - // { x: 400, y: 1000 }, - // { x: 410, y: 1000 }, - // { x: 410, y: 1010 }, - // { x: 400, y: 1010 }, - // ]) - // pole.id = 'pole' - // game.add_terrain(pole) + const diamond = new Terrain([ + { x: 1000, y: 300 }, + { x: 1100, y: 400 }, + { x: 1000, y: 500 }, + { x: 900, y: 400 }, + ]) + diamond.id = 'diamond' + game.add_terrain(diamond) + + const pole = new Terrain([ + { x: 400, y: 1000 }, + { x: 410, y: 1000 }, + { x: 410, y: 1010 }, + { x: 400, y: 1010 }, + ]) + pole.id = 'pole' + game.add_terrain(pole) entity1.moveAction(1000, 500) - // setTimeout(() => entity1.moveAction(100, 400), 10) + setTimeout(() => entity1.moveAction(100, 400), 10) game.start() }) diff --git a/src/pathfind.js b/src/pathfind.js index 30d679f..3a8a348 100644 --- a/src/pathfind.js +++ b/src/pathfind.js @@ -7,10 +7,11 @@ export default class Pathfind { static precision = 0.001 static multiplier = 1000 // (1 / this.precision) - static key(pos) { - return `${pos.x},${pos.y}` + static key2(a, b) { + return `${a},${b}` } + // TODO: Value exceeds safe integer limit: collisions cause waypointing anomalies static floatKey4(a, b, c, d) { return Math.floor(a * Pathfind.multiplier) + Math.floor(b * Pathfind.multiplier) * Pathfind.multiplier + @@ -18,16 +19,11 @@ export default class Pathfind { Math.floor(d * Pathfind.multiplier) * Pathfind.multiplier ** 3 } - static floatKey2(a, b) { - return Math.floor(a * Pathfind.multiplier) + - Math.floor(b * Pathfind.multiplier) * Pathfind.multiplier - } - static uniqueWaypoints(waypoints) { const included = new Set() const uniqueWaypoints = [] for (const waypoint of waypoints) { - const key = Pathfind.floatKey2(waypoint[0], waypoint[1]) + const key = Pathfind.key2(waypoint[0], waypoint[1]) if (!included.has(key)) { included.add(key) uniqueWaypoints.push(waypoint) @@ -52,16 +48,16 @@ export default class Pathfind { return path } - const waypointKey = Pathfind.floatKey2(waypoint) + const waypointKey = Pathfind.key2(waypoint[0], waypoint[1]) if (!visited.has(waypointKey) || visited.get(waypointKey) > cost) { visited.set(waypointKey, cost) for (let i = 0; i < graph.length; i += 5) { - if (Math.abs(waypoint[0] - graph[i]) < Pathfind.precision && Math.abs(waypoint[1] - graph[i + 1]) < Pathfind.precision) { - continue + if (Math.abs(waypoint[0] - graph[i]) > Pathfind.precision || Math.abs(waypoint[1] - graph[i + 1]) > Pathfind.precision) { + continue // waypoint and graph.from aren't the same (so graph.to isn't a neighbor) } - const nextKey = `${graph[i + 2]},${graph[i + 3]}` + const nextKey = Pathfind.key2(graph[i + 2], graph[i + 3]) if (!visited.has(nextKey) || visited.get(nextKey) > cost + graph[i + 4]) { const next = new Float32Array(2) next[0] = graph[i + 2]