This repository has been archived on 2026-05-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
instructions-clear/src/game.js
T
2025-01-13 14:08:10 +09:00

117 lines
3.0 KiB
JavaScript

import { EventEmitter } from 'node:events'
import Entity from './entity.js'
import Terrain from './terrain.js'
import Projectile from './projectile.js'
export default class Game {
tickRate = 30
currentTick = 0
width = 2000
height = 2000
nextTickAt = 0
#logic = null
#entities = []
#eventEmitter = new EventEmitter()
#projectiles = []
#terrains = []
#tickBudget = 1000 / this.tickRate
get logic() { return this.#logic }
get entities() { return this.#entities }
get eventEmitter() { return this.#eventEmitter }
get projectiles() { return this.#projectiles }
get terrains() { return this.#terrains }
get tickBudget() { return this.#tickBudget }
set logic(value) { this.#logic = value }
get unadjustedWaypoints() {
return this.terrains.map((t) => t.unadjustedWaypoints).concat(this.entities.map((e) => e.unadjustedWaypoints)).flat()
}
addTerrain(terrain) {
this.#terrains.push(terrain)
}
despawn(object) {
if (object instanceof Entity) { this.despawnEntity(object) }
else if (object instanceof Terrain) { this.removeTerrain(object) }
else if (object instanceof Projectile) { this.despawnProjectile(object) }
else { console.error({ error: { reason: 'Can\'t despawn object', object } }) }
}
despawnEntity(entity) {
this.#entities = this.#entities.filter((e) => e.id != entity.id)
entity.game = null
}
despawnProjectile(projectile) {
this.#projectiles = this.#projectiles.filter((p) => p.id != projectile.id)
projectile.game = null
}
removeTerrain(terrain) {
this.#terrains = this.#terrains.filter((t) => t.id != terrain.id)
}
secToTick(sec) {
return Math.floor(this.tickRate * sec)
}
spawn(object) {
if (object instanceof Entity) { this.spawnEntity(object) }
else if (object instanceof Terrain) { this.addTerrain(object) }
else if (object instanceof Projectile) { this.spawnProjectile(object) }
else { console.error({ error: { reason: 'Can\'t spawn object', object } }) }
}
spawnEntity(entity) {
this.#entities.push(entity)
entity.game = this
}
spawnProjectile(projectile) {
this.#projectiles.push(projectile)
projectile.game = this
}
state() {
return {
...this,
entities: this.#entities.map((e) => e.state()),
terrains: this.#terrains.map((t) => t.state()),
projectiles: this.#projectiles.map((p) => p.state()),
}
}
gameLoop() {
const tickBudget = this.#tickBudget
if (this.nextTickAt != null) {
const nextTickAt = this.nextTickAt
this.nextTickAt = null
let start = performance.now()
while (start < nextTickAt) { start = performance.now() }
this.update()
this.nextTickAt = start + tickBudget
}
}
start() {
setInterval(() => this.gameLoop(), 1)
}
update() {
this.#entities.forEach((e) => e.update())
this.#projectiles.forEach((p) => p.update())
if (this.#logic != null) {
this.#logic()
}
this.currentTick++
this.eventEmitter.emit('tick')
}
}