aboutsummaryrefslogtreecommitdiff
path: root/static/src/engine/game.ts
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth@simponic.xyz>2024-09-07 20:20:07 -0700
committerElizabeth Hunt <elizabeth@simponic.xyz>2024-09-12 17:23:30 -0700
commit8ec7f5368232d59f344e1067e1bad5e48dbcb7ae (patch)
tree1ad2df4dc00773f2307d1525cc80ac7410ea8fba /static/src/engine/game.ts
parente4e31978bae7e45be57b376415a4b925ac8cbc03 (diff)
downloadkennel.hatecomputers.club-8ec7f5368232d59f344e1067e1bad5e48dbcb7ae.tar.gz
kennel.hatecomputers.club-8ec7f5368232d59f344e1067e1bad5e48dbcb7ae.zip
get "cats" up there
Diffstat (limited to 'static/src/engine/game.ts')
-rw-r--r--static/src/engine/game.ts112
1 files changed, 112 insertions, 0 deletions
diff --git a/static/src/engine/game.ts b/static/src/engine/game.ts
new file mode 100644
index 0000000..64f63b5
--- /dev/null
+++ b/static/src/engine/game.ts
@@ -0,0 +1,112 @@
+import { System, SystemType } from "./system";
+import { Entity } from "./entity";
+import { ComponentType } from "./component";
+
+export class Game {
+ private running: boolean;
+ private last_update: number;
+
+ private readonly entities: Map<string, Entity> = new Map();
+ private readonly component_entities: Map<ComponentType, Set<string>> =
+ new Map();
+ private readonly systems: Map<SystemType, System> = new Map();
+ private readonly system_order: SystemType[];
+
+ constructor(
+ public readonly client_id: string,
+ systems: System[],
+ ) {
+ this.last_update = performance.now();
+ this.running = false;
+
+ systems.forEach((system) => this.systems.set(system.system_type, system));
+ this.system_order = systems.map(({ system_type }) => system_type);
+ }
+
+ public start() {
+ if (this.running) return;
+
+ console.log("starting game");
+ this.running = true;
+ this.last_update = performance.now();
+
+ const game_loop = (timestamp: number) => {
+ if (!this.running) return;
+
+ // rebuild component -> { entity } map
+ this.component_entities.clear();
+ Array.from(this.entities.values()).forEach((entity) =>
+ Object.values(entity.components).forEach((component) => {
+ const set =
+ this.component_entities.get(component.name) ?? new Set<string>();
+ set.add(entity.id);
+ this.component_entities.set(component.name, set);
+ }),
+ );
+
+ const dt = timestamp - this.last_update;
+
+ this.system_order.forEach((system_type) =>
+ this.systems.get(system_type)!.update(dt, this),
+ );
+
+ this.last_update = timestamp;
+ requestAnimationFrame(game_loop); // tail call recursion! /s
+ };
+ requestAnimationFrame(game_loop);
+ }
+
+ public stop() {
+ if (!this.running) return;
+ this.running = false;
+ }
+
+ public for_each_entity_with_component(
+ component: ComponentType,
+ callback: (entity: Entity) => void,
+ ) {
+ this.component_entities.get(component)?.forEach((entity_id) => {
+ const entity = this.entities.get(entity_id);
+ if (!entity) return;
+
+ callback(entity);
+ });
+ }
+
+ public get_entity(id: string) {
+ return this.entities.get(id);
+ }
+
+ public put_entity(entity: Entity) {
+ const old_entity = this.entities.get(entity.id);
+ if (old_entity) this.clear_entity_components(old_entity);
+
+ Object.values(entity.components).forEach((component) => {
+ const set =
+ this.component_entities.get(component.name) ?? new Set<string>();
+ set.add(entity.id);
+ this.component_entities.set(component.name, set);
+ });
+ this.entities.set(entity.id, entity);
+ }
+
+ public remove_entity(id: string) {
+ const entity = this.entities.get(id);
+ if (typeof entity === "undefined") return;
+
+ this.clear_entity_components(entity);
+ this.entities.delete(id);
+ }
+
+ private clear_entity_components(entity: Entity) {
+ Object.values(entity.components).forEach((component) => {
+ const set = this.component_entities.get(component.name);
+ if (typeof set === "undefined") return;
+ set.delete(entity.id);
+ });
+ }
+
+ public get_system<T extends System>(system_type: SystemType): T | undefined {
+ return this.systems.get(system_type) as T;
+ }
+}