summaryrefslogtreecommitdiff
path: root/src/engine/Game.ts
blob: fd8be7d5f243576f6fe0e902005262e3fbf50c77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import { Entity } from "./entities";
import { System } from "./systems";

export class Game {
  private systemOrder: string[];

  private running: boolean;
  private lastTimeStamp: number;

  public entities: Map<string, Entity>;
  public systems: Map<string, System>;
  public componentEntities: Map<string, Set<string>>;

  constructor() {
    this.lastTimeStamp = performance.now();
    this.running = false;
    this.systemOrder = [];
    this.systems = new Map();
    this.entities = new Map();
    this.componentEntities = new Map();
  }

  public resetState() {
    this.entities.clear();
    this.componentEntities.clear();
  }

  public start() {
    this.lastTimeStamp = performance.now();
    this.running = true;
  }

  public stop() {
    this.running = false;
  }

  public addEntity(entity: Entity) {
    this.entities.set(entity.id, entity);
  }

  public getEntity(id: string): Entity | undefined {
    return this.entities.get(id);
  }

  public removeEntity(id: string) {
    this.entities.delete(id);
  }

  public forEachEntityWithComponent(
    componentName: string,
    callback: (entity: Entity) => void
  ) {
    this.componentEntities.get(componentName)?.forEach((entityId) => {
      const entity = this.getEntity(entityId);
      if (!entity) return;

      callback(entity);
    });
  }

  public addSystem(system: System) {
    if (!this.systemOrder.includes(system.name)) {
      this.systemOrder.push(system.name);
    }
    this.systems.set(system.name, system);
  }

  public getSystem<T>(name: string): T {
    return this.systems.get(name) as unknown as T;
  }

  public doGameLoop(timeStamp: number) {
    if (!this.running) {
      return;
    }

    const dt = timeStamp - this.lastTimeStamp;
    this.lastTimeStamp = timeStamp;

    // rebuild the Component -> { Entity } map
    this.componentEntities.clear();
    this.entities.forEach((entity) =>
      entity.getComponents().forEach((component) => {
        if (!this.componentEntities.has(component.name)) {
          this.componentEntities.set(
            component.name,
            new Set<string>([entity.id])
          );
          return;
        }
        this.componentEntities.get(component.name)?.add(entity.id);
      })
    );

    this.systemOrder.forEach((systemName) => {
      this.systems.get(systemName)?.update(dt, this);
    });
  }
}