import { getContext } from "../lib/context.ts"; import { TrackSystem } from "../track/system.ts"; import { Train } from "../train.old.ts"; export class StateMachine { private _states: Map> = new Map(); private currentState?: State; update(dt: number, ctx?: CanvasRenderingContext2D) { this.currentState?.update(dt, ctx); } optimizePerformance(percent: number) { const ctx = getContext() as { trains: Train[]; track: TrackSystem }; if (percent < 0.5) { ctx.track.optimize(percent); } } get current() { return this.currentState; } get states() { return this._states; } addState(state: State) { this.states.set(state.name, state); } transitionTo(state: T) { if (!this.current) { this.currentState = this._states.get(state)!; this.currentState.start(); return; } if (this.current?.canTransitionTo(state) && this._states.has(state)) { this.current.stop(); this.currentState = this._states.get(state)!; this.current.start(); } } } export abstract class State { protected stateMachine: StateMachine; protected abstract validTransitions: Set; abstract readonly name: T; constructor( stateMachine: StateMachine, ) { this.stateMachine = stateMachine; } abstract update(dt: number, ctx?: CanvasRenderingContext2D): void; abstract start(): void; abstract stop(): void; canTransitionTo(state: T) { return this.validTransitions.has(state); } } export abstract class ExtensibleState extends State { extensions: Map void> = new Map(); registerExtension(name: string, cb: (...args: unknown[]) => void) { this.extensions.set(name, cb); } constructor(stateMachine: StateMachine) { super(stateMachine); const oldUpdate = this.update; this.update = function (dt: number, ctx?: CanvasRenderingContext2D) { oldUpdate.apply(this, [dt, ctx]); this.runExtensions(dt, ctx); }; } runExtensions(...args: unknown[]) { for (const [name, cb] of this.extensions) { cb(...args); } } }