base2020/src/Game/GameComponents.ts

139 lines
3.2 KiB
TypeScript

import { KeyName } from "../Applet/Keyboard";
import { DrawSet, Layer } from "../Applet/Render";
import { Data as EcsData } from "../Ecs/Components";
import { copy, 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<string, any> = {};
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<Boss> = {};
bullet: SparseStore<Bullet> = {};
hp: SparseStore<Hp> = {};
lifetime: SparseStore<Lifetime> = {};
message: SparseStore<Message> = {};
constructor(source?: Partial<Data>) {
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<KeyName[], Data> {
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);
}
}