89 lines
2.2 KiB
JavaScript
89 lines
2.2 KiB
JavaScript
import { Vector2 } from 'three'
|
|
import SAT from 'sat'
|
|
import SATX from './satx.js'
|
|
|
|
export default class Projectile {
|
|
id = crypto.randomUUID()
|
|
after = null
|
|
height = 50
|
|
memory = {}
|
|
onCollide = null
|
|
owner = null
|
|
position = new Vector2()
|
|
radius = 5
|
|
speed = 1000
|
|
visualRadius = null
|
|
|
|
#dest = null
|
|
#homingTarget = null
|
|
#game = null
|
|
|
|
get game() { return this.#game }
|
|
set game(value) { this.#game = value }
|
|
set destination(value) { this.#dest = value }
|
|
set homingTarget(value) { this.#homingTarget = value }
|
|
|
|
get destination() {
|
|
return this.#dest ?? this.#homingTarget?.position
|
|
}
|
|
|
|
constructor(options = {}) {
|
|
Object.entries(options).forEach(([key, value]) => this[key] = value)
|
|
if (this.visualRadius == null) {
|
|
this.visualRadius = this.radius
|
|
}
|
|
}
|
|
|
|
checkCollisions(collider) {
|
|
(this.game?.entities ?? []).filter((e) => e.id != this.id).forEach((e) => {
|
|
if (e.id == this.owner?.id) { return }
|
|
|
|
if (SATX.collideObject(collider, e.collider())) {
|
|
if (this.onCollide != null) { this.onCollide(this, e) }
|
|
}
|
|
})
|
|
}
|
|
|
|
collider() {
|
|
return new SAT.Circle(new SAT.Vector(this.position.x, this.position.y), this.radius)
|
|
}
|
|
|
|
despawn() {
|
|
this.game?.despawn(this)
|
|
}
|
|
|
|
update() {
|
|
this.#move()
|
|
if (this.onCollide != null) { this.checkCollisions(this.collider()) }
|
|
this.#checkIfArrived()
|
|
}
|
|
|
|
#checkIfArrived() {
|
|
if (this.destination == null) { return }
|
|
if (!this.position.equals(this.destination)) { return }
|
|
|
|
if (this.after != null) {
|
|
this.after(this, this.#homingTarget)
|
|
}
|
|
|
|
this.despawn()
|
|
}
|
|
|
|
#move() {
|
|
if (this.destination == null) { return }
|
|
|
|
const speed = (this.speed / (this.game?.tickBudget ?? 1000))
|
|
const prevPos = this.position.clone()
|
|
if (this.position.distanceTo(this.destination) < speed) {
|
|
this.position.copy(this.destination)
|
|
}
|
|
else {
|
|
const step = this.destination.clone().sub(this.position).normalize().multiplyScalar(speed)
|
|
this.position.add(step)
|
|
}
|
|
|
|
const tunnel = SATX.entityTunnel(prevPos.x, prevPos.y, this.position.x, this.position.y, this.radius)
|
|
if (this.onCollide != null) { this.checkCollisions(tunnel) }
|
|
}
|
|
}
|