diff options
Diffstat (limited to 'src/engine/systems/Collision.ts')
-rw-r--r-- | src/engine/systems/Collision.ts | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/engine/systems/Collision.ts b/src/engine/systems/Collision.ts new file mode 100644 index 0000000..7b1b963 --- /dev/null +++ b/src/engine/systems/Collision.ts @@ -0,0 +1,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(); + } +} |