import * as THREE from 'three' export default class Entity { id = crypto.randomUUID() speed = 400 #dest = null #game = null #mesh = null constructor(...options) { Object.entries(options).forEach((value, key) => this[key] = value) const geometry = new THREE.CircleGeometry(options.radius ?? 0) this.#mesh = new THREE.Mesh(geometry) } get game() { return this.#game } get mesh() { return this.#mesh } get pos() { return this.#mesh.position } get radius() { return this.#mesh.userData.radius } get x() { return this.#mesh.position.x } get y() { return this.#mesh.position.y } set game(value) { this.#game = value } set x(value) { this.#mesh.position.x = value } set y(value) { this.#mesh.position.y = value } set radius(value) { this.#mesh.geometry = new THREE.CircleGeometry(value) this.#mesh.userData.radius = value } moveAction(x, y) { this.#dest = new THREE.Vector3(x, y, 0) } state() { return { ...this, pos: { x: this.x, y: this.y, }, radius: this.radius, } } teleport(x, y) { this.#mesh.position.set(x, y, 0) } takeStep() { const speed = this.speed / (this.game?.tickBudget ?? 1000) if (this.#dest != null) { const fixedDest = new THREE.Vector3( Math.min(Math.max(this.radius, this.#dest.x), this.game?.height ?? Infinity), Math.min(Math.max(this.radius, this.#dest.y), this.game?.height ?? Infinity), 0, ) this.pos.add(fixedDest.clone().sub(this.pos).normalize().multiplyScalar(speed)) if (this.pos.clone().sub(fixedDest).length() <= speed) { this.pos.copy(fixedDest) this.#dest = null } } } async update() { await Promise.allSettled([ this.takeStep(), ]) } }