All files / games/engine/src engine.ts

100% Statements 36/36
87.5% Branches 7/8
100% Functions 14/14
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 10411x 11x         11x   11x 11x     11x               12x 12x 12x 12x 12x       7x   7x   7x       2x   2x   2x       3x       2x       1x       1x 1x         4x 3x       3x     1x       1x       1x       1x             4x 9x 9x     4x 1x   1x     4x      
import { random } from "jga-algorithms-random";
import { Engine as BaseEngine, EntityInterface } from "jga-patterns-ecs";
import { Command, CommandManager, CommandResultInterface } from "jga-patterns-command";
import { GameMap, PositionInterface } from "jga-games-maps";
 
import { Scheduler } from "./scheduler";
import { Loop } from "./loop";
 
import { Entity, Player } from "./entities";
import { ComponentName, PositionComponent } from "./components";
import { System } from "./systems";
 
export class Engine extends BaseEngine {
    private player!: Player;
    private scheduler: Scheduler;
    private map: GameMap;
    private loop: Loop;
    private commandManager: CommandManager;
 
    public constructor(scheduler: Scheduler, map: GameMap, commandManager: CommandManager) {
        super();
        this.scheduler = scheduler;
        this.map = map;
        this.loop = new Loop(this.scheduler);
        this.commandManager = commandManager;
    }
 
    public addEntity(entity: Entity, repeatable = false): Map<string, EntityInterface> {
        const entities = super.addEntity(entity);
 
        this.scheduler.add(entity, repeatable);
 
        return entities;
    }
 
    public createPlayer(): Player {
        this.player = new Player(this.generateId());
 
        this.addEntityAtRandomPosition(this.player, true);
 
        return this.getPlayer();
    }
 
    public getPlayer(): Player {
        return this.player;
    }
 
    public getMap(): GameMap {
        return this.map;
    }
 
    public execute(command: Command): CommandResultInterface {
        return this.commandManager.execute(command);
    }
 
    public process(systems: System[]): void {
        return systems.forEach((system): void => {
            system.run(this.map);
        });
    }
 
    public addEntityAtRandomPosition(entity: Entity, repeatable = false): Map<string, EntityInterface> {
        if (true === entity.hasComponent(ComponentName.POSITION)) {
            (entity.getComponent(ComponentName.POSITION) as PositionComponent).setPosition(
                this.getRandomFloorPosition(),
            );
 
            return this.addEntity(entity, repeatable);
        }
 
        return this.entities;
    }
 
    public lock(): Loop {
        return this.loop.lock();
    }
 
    public unlock(): Loop {
        return this.loop.unlock();
    }
 
    public async mainLoop(): Promise<Loop> {
        return this.loop.start();
    }
 
    private getRandomFloorPosition(): PositionInterface {
        let x: number;
        let y: number;
 
        do {
            x = random(0, this.map.getWidth());
            y = random(0, this.map.getHeight());
        } while (null !== this.map.getTile({ x, y }) && !this.map.getTile({ x, y }).isWalkable);
 
        const targets: EntityInterface[] = Array.from(this.entities.values()).filter((entity) => {
            const entityPosition = entity.getComponent(ComponentName.POSITION) as PositionComponent;
 
            return { x, y } === entityPosition.getPosition();
        });
 
        return targets.length === 0 ? { x, y } : this.getRandomFloorPosition();
    }
}