fix waypoints going out of bounds
This commit is contained in:
+24
-27
@@ -2,7 +2,6 @@ import { Vector2 } from 'three'
|
|||||||
import SAT from 'sat'
|
import SAT from 'sat'
|
||||||
import SATX from './satx.js'
|
import SATX from './satx.js'
|
||||||
import Pathfind from './pathfind.js'
|
import Pathfind from './pathfind.js'
|
||||||
import Terrain from './terrain.js'
|
|
||||||
|
|
||||||
export default class Entity {
|
export default class Entity {
|
||||||
id = crypto.randomUUID()
|
id = crypto.randomUUID()
|
||||||
@@ -69,8 +68,19 @@ export default class Entity {
|
|||||||
return SATX.collideObjects(this.collider, colliders)
|
return SATX.collideObjects(this.collider, colliders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: calculate convex hulls of collidables because tris handle collisions sequentially
|
||||||
moveAction(x, y) {
|
moveAction(x, y) {
|
||||||
this.#dest = new Vector2(x, y)
|
const temp = SATX.fixCollisions(new Vector2(x, y), this.collidables(), this.radius)
|
||||||
|
// const entity = new Entity()
|
||||||
|
// entity.teleport(temp.x, temp.y)
|
||||||
|
// entity.radius = this.radius
|
||||||
|
// this.game.spawn_entity(entity)
|
||||||
|
this.#dest = SATX.clamp(
|
||||||
|
temp,
|
||||||
|
this.game?.width,
|
||||||
|
this.game?.height,
|
||||||
|
this.radius,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
state() {
|
state() {
|
||||||
@@ -87,9 +97,8 @@ export default class Entity {
|
|||||||
this.position.set(x, y)
|
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?)
|
// TODO: pathfinding stops if wall is clicked (did you forget to fix the destination?)
|
||||||
async takeStep(distanceTraveled = 0) {
|
takeStep(distanceTraveled = 0) {
|
||||||
const speed = (this.speed / (this.game?.tickBudget ?? 1000)) - distanceTraveled
|
const speed = (this.speed / (this.game?.tickBudget ?? 1000)) - distanceTraveled
|
||||||
const collidables = this.collidables()
|
const collidables = this.collidables()
|
||||||
if (this.#dest != null) {
|
if (this.#dest != null) {
|
||||||
@@ -97,29 +106,12 @@ export default class Entity {
|
|||||||
|
|
||||||
if (this.#path.length < 1 || !this.#path.at(-1).equals(fixedDest)) {
|
if (this.#path.length < 1 || !this.#path.at(-1).equals(fixedDest)) {
|
||||||
console.time('pathfinding')
|
console.time('pathfinding')
|
||||||
console.time('waypoints')
|
|
||||||
const start = SATX.vectorToFloat32Array(this.position)
|
const start = SATX.vectorToFloat32Array(this.position)
|
||||||
const goal = SATX.vectorToFloat32Array(fixedDest)
|
const goal = SATX.vectorToFloat32Array(fixedDest)
|
||||||
const nonUniqueWaypoints = this.waypoints().map((w) => SATX.vectorToFloat32Array(w)).concat([start, goal])
|
const nonUniqueWaypoints = this.waypoints().map((w) => SATX.vectorToFloat32Array(w)).concat([start, goal])
|
||||||
const waypoints = Pathfind.uniqueWaypoints(nonUniqueWaypoints)
|
const waypoints = Pathfind.uniqueWaypoints(nonUniqueWaypoints)
|
||||||
|
|
||||||
console.timeEnd('waypoints')
|
|
||||||
console.time('graph')
|
|
||||||
const graph = Pathfind.buildGraph(waypoints, collidables, this.radius)
|
const graph = Pathfind.buildGraph(waypoints, collidables, this.radius)
|
||||||
|
|
||||||
// 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))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// tunnels.map((t) => SATX.satPolygonToVectors(t)).forEach((t) => this.#game.add_terrain(new Terrain(t)))
|
|
||||||
// this.#dest = null
|
|
||||||
|
|
||||||
console.timeEnd('graph')
|
|
||||||
console.time('path')
|
|
||||||
this.#path = Pathfind.shortestPath(graph, start, goal).map((waypoint) => new Vector2(waypoint[0], waypoint[1]))
|
this.#path = Pathfind.shortestPath(graph, start, goal).map((waypoint) => new Vector2(waypoint[0], waypoint[1]))
|
||||||
console.log(this.#path)
|
|
||||||
console.timeEnd('path')
|
|
||||||
console.timeEnd('pathfinding')
|
console.timeEnd('pathfinding')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +132,7 @@ export default class Entity {
|
|||||||
if (this.position.equals(destination)) {
|
if (this.position.equals(destination)) {
|
||||||
this.#path = this.#path.slice(1)
|
this.#path = this.#path.slice(1)
|
||||||
if (this.#path.length > 0) {
|
if (this.#path.length > 0) {
|
||||||
await this.takeStep(distance)
|
this.takeStep(distance)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.#dest = null
|
this.#dest = null
|
||||||
@@ -150,10 +142,8 @@ export default class Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async update() {
|
update() {
|
||||||
await Promise.allSettled([
|
this.takeStep()
|
||||||
this.takeStep(),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
waypoints() {
|
waypoints() {
|
||||||
@@ -161,6 +151,13 @@ export default class Entity {
|
|||||||
const terrainColliders = (this.game?.terrains ?? [])
|
const terrainColliders = (this.game?.terrains ?? [])
|
||||||
const unadjustedWaypoints = entityColliders.concat(terrainColliders).map((e) => e.unadjustedWaypoints).flat()
|
const unadjustedWaypoints = entityColliders.concat(terrainColliders).map((e) => e.unadjustedWaypoints).flat()
|
||||||
|
|
||||||
return unadjustedWaypoints.map(([waypoint, direction]) => waypoint.clone().add(direction.clone().multiplyScalar(this.radius))) ?? []
|
return unadjustedWaypoints.map(([waypoint, direction]) => {
|
||||||
|
return SATX.clamp(
|
||||||
|
waypoint.clone().add(direction.clone().multiplyScalar(this.radius)),
|
||||||
|
this.game?.width,
|
||||||
|
this.game?.height,
|
||||||
|
this.radius,
|
||||||
|
)
|
||||||
|
}) ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -42,14 +42,14 @@ export default class Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
start() {
|
||||||
const start = performance.now()
|
const start = performance.now()
|
||||||
await this.update()
|
this.update()
|
||||||
setTimeout(() => this.start(), Math.max(0, this.#tickBudget - (performance.now() - start)))
|
setTimeout(() => this.start(), Math.max(0, this.#tickBudget - (performance.now() - start)))
|
||||||
}
|
}
|
||||||
|
|
||||||
async update() {
|
update() {
|
||||||
Promise.allSettled(this.#entities.map((e) => e.update()))
|
this.#entities.map((e) => e.update())
|
||||||
this.currentTick++
|
this.currentTick++
|
||||||
this.eventEmitter.emit('tick')
|
this.eventEmitter.emit('tick')
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -115,9 +115,9 @@ app.listen(port, () => {
|
|||||||
pole.id = 'pole'
|
pole.id = 'pole'
|
||||||
game.add_terrain(pole)
|
game.add_terrain(pole)
|
||||||
|
|
||||||
entity1.moveAction(1000, 500)
|
// entity1.moveAction(1000, 500)
|
||||||
|
|
||||||
setTimeout(() => entity1.moveAction(100, 400), 10)
|
// setTimeout(() => entity1.moveAction(100, 400), 10)
|
||||||
|
|
||||||
game.start()
|
game.start()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user