summaryrefslogtreecommitdiff
path: root/src/engine/systems/Collision.ts
blob: 7b1b963cf38733ba46894001acfb22d29e63b92c (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
100
101
102
103
import { System, SystemNames } from ".";
import { Game } from "..";
import { Entity, EntityNames } from "../entities";
import { BoundingBox, Colliding, ComponentNames, Grid } from "../components";

const collisionMap: Record<string, Set<string>> = {
  [EntityNames.Key]: new Set([EntityNames.LockedDoor]),
  [EntityNames.Curry]: new Set([EntityNames.Player]),
};

export class Collision extends System {
  static canCollide(entityName: string, otherEntityName: string) {
    if (collisionMap[entityName]) {
      return collisionMap[entityName].has(otherEntityName);
    }
    return collisionMap[otherEntityName]?.has(entityName) ?? false;
  }

  constructor() {
    super(SystemNames.Collision);
  }

  public update(_dt: number, game: Game) {
    game.forEachEntityWithComponent(ComponentNames.Colliding, (entity) => {
      if (!entity.hasComponent(ComponentNames.BoundingBox)) {
        return;
      }
      const collidingBox = entity.getComponent<BoundingBox>(
        ComponentNames.BoundingBox,
      );
      let collidingGrid = entity.hasComponent(ComponentNames.Grid)
        ? entity.getComponent<Grid>(ComponentNames.Grid)
        : null;

      const collidingWith: Entity[] = [];
      game.forEachEntityWithComponent(
        ComponentNames.BoundingBox,
        (otherEntity) => {
          const otherBoundingBox = otherEntity.getComponent<BoundingBox>(
            ComponentNames.BoundingBox,
          );
          let otherGrid = otherEntity.hasComponent(ComponentNames.Grid)
            ? otherEntity.getComponent<Grid>(ComponentNames.Grid)
            : null;

          if (collidingGrid && otherGrid) {
            if (
              collidingGrid.gridPosition.x === otherGrid.gridPosition.x &&
              collidingGrid.gridPosition.y === otherGrid.gridPosition.y
            ) {
              collidingWith.push(otherEntity);
            }
            return;
          }

          if (collidingBox.isCollidingWith(otherBoundingBox)) {
            collidingWith.push(otherEntity);
          }
        },
      );

      for (const collision of collidingWith) {
        this.handleCollision(entity, collision, game);
      }
    });
  }

  private handleCollision(entity: Entity, otherEntity: Entity, game: Game) {
    if (!Collision.canCollide(entity.name, otherEntity.name)) {
      return;
    }

    const keyDoorPair = [EntityNames.Key, EntityNames.LockedDoor].map((x) =>
      [entity, otherEntity].find((y) => y.name === x),
    );
    const [key, door] = keyDoorPair;
    if (key && door) {
      this.handleKeyDoorCollision(key, door, game);
    }

    const curryPlayerPair = [EntityNames.Curry, EntityNames.Player].map((x) =>
      [entity, otherEntity].find((y) => y.name === x),
    );
    const [curry, player] = curryPlayerPair;
    if (curry && player) {
      this.handleCurryPlayerCollision(curry, player, game);
    }
  }

  private handleKeyDoorCollision(key: Entity, door: Entity, game: Game) {
    game.removeEntity(key.id);
    game.removeEntity(door.id);
  }

  private handleCurryPlayerCollision(
    curry: Entity,
    _player: Entity,
    game: Game,
  ) {
    game.removeEntity(curry.id);
    game.stop();
  }
}