import { KeyName } from "../Applet/Keyboard"; import { DrawSet, Layer } from "../Applet/Render"; import { Data as EcsData } from "../Ecs/Components"; import { copy, Join, SparseStore } from "../Ecs/Data"; import { DumbMotion } from "../Ecs/Location"; import { INPUT_FREQUENCY, LockstepProcessor } from "../Ecs/Lockstep"; import { Buttons } from "./Input"; export enum GamePhase { TITLE, PLAYING, LOST, WON } export type RGB = [number, number, number]; export class World { width = 500; height = 400; /* * Core Game Status */ phase = GamePhase.TITLE; score = 0; constructor() {} /* * Drawing Layers */ groundLayer = new Layer(0); debugLayer = new Layer(2); bulletLayer = new Layer(10); playerLayer = new Layer(15); smokeLayer = new Layer(16); hudLayer = new Layer(20); bgColor: RGB = [255, 255, 255]; /** * Catch-all debug tool */ debug: Record = {}; drawHud(drawSet: DrawSet) { drawSet.queue(this.hudLayer.toRender((cx, dt) => { cx.font = "16px monospace"; cx.textAlign = "left"; cx.textBaseline = "middle"; const score = `Score: ${this.score}`; cx.fillStyle = "#000"; cx.fillText(score, this.width/3 + 1, this.height - 18 + 1, this.width/4); cx.fillStyle = "#0ff"; cx.fillText(score, this.width/3, this.height - 18, this.width/4); })); } } export class Data extends EcsData { boss: SparseStore = {}; bullet: SparseStore = {}; hp: SparseStore = {}; lifetime: SparseStore = {}; message: SparseStore = {}; constructor(source?: Partial) { super(source); if(source?.boss) this.boss = copy(source.boss); if(source?.bullet) this.bullet = copy(source.bullet); if(source?.hp) this.hp = copy(source.hp); if(source?.lifetime) this.lifetime = copy(source.lifetime); if(source?.message) this.message = copy(source.message); } } export enum Teams { PLAYER, ENEMY } export class Bullet { hit = false; constructor( public team: Teams, public attack: number ) {}; } export class Hp { receivedDamage = 0; constructor( public team: Teams, public hp: number ) {}; } export class Lifetime { constructor( public time: number ) {}; } export class Boss { constructor( public name: string ) {} } export class Message { targetY = 0; constructor( public layer: Layer, public color: string, public message: string, public timeout = 3 ) {} } export class Engine implements LockstepProcessor { cloneState(old: Data) { return new Data(old); } compareInput(a: KeyName[], b: KeyName[]): boolean { if (a.length != b.length) return false; let matches = true; a.forEach((keyA, i) => { if (keyA != b[i]) { matches = false; } }); return matches; } advanceState(state: Data, input: KeyName[]) { DumbMotion(state, INPUT_FREQUENCY); Join(state, "location").forEach(([location]) => { let dir = 0; if(input.indexOf("left") != -1) { dir -= 1; } if(input.indexOf("right") != -1) { dir += 1; } location.VAngle = dir * 0.01; }); } }