import { Scene } from "./scene"; import { ZograRenderPipeline, ZograRenderPipelineConstructor, PreviewRenderer, RenderContext } from "../render-pipeline"; import { Camera } from "./camera"; import { ZograRenderer } from "zogra-renderer"; import { EventEmitter, EventDefinitions, IEventSource, EventKeys } from "zogra-renderer"; import { UnknownPhysics } from "../physics/physics-generic"; import { ConstructorType } from "../utils/util"; interface GameTime { time: Readonly, deltaTime: Readonly, } export type Time = Readonly; interface ZograEngineEvents { update: (t: Time) => void; render: (cameras: Camera[]) => void; start: () => void; stop: () => void; "scene-change": (scene: Scene, previous: Scene) => void; } export class ZograEngine implements IEventSource { private _scene: Scene; renderer: ZograRenderer; renderPipeline: RenderPipeline; eventEmitter: EventEmitter; fixedDeltaTime = false; private _time: Time = { deltaTime: 0, time: 0 }; get time(): Time { return this._time; } get scene() { return this._scene } set scene(value) { const previous = this._scene; this._scene = value; value.engine = this as any; this.eventEmitter.emit("scene-change", value, previous); } constructor(canvas:HTMLCanvasElement, RenderPipeline: ConstructorType = PreviewRenderer as any) { this.renderer = new ZograRenderer(canvas, canvas.width, canvas.height); this.renderPipeline = new RenderPipeline(this.renderer); this._scene = new Scene(UnknownPhysics); this.eventEmitter = new EventEmitter(); } renderScene() { const cameras = this.scene.getEntitiesOfType(Camera); this.renderPipeline.render(RenderContext.create(this.renderer), this.scene, cameras); } start() { let previousDelay = 0; let startDelay = 0; let currentTime = 0; const update = (delay: number) => { if (previousDelay === 0) { startDelay = previousDelay = delay; requestAnimationFrame(update); return; } if (this.fixedDeltaTime) currentTime += 16; else currentTime = delay; const time = (currentTime - startDelay) / 1000; const dt = (currentTime - previousDelay) / 1000; previousDelay = currentTime; const t: Time = { time: time, deltaTime: dt }; this._time = t; this.eventEmitter.emit("update", t); this.scene.__update(t); this.eventEmitter.emit("render", this.scene.getEntitiesOfType(Camera)); this.renderScene(); requestAnimationFrame(update); }; requestAnimationFrame(update); } on>(event: T, listener: ZograEngineEvents[T]) { this.eventEmitter.on(event, listener); } off>(event: T, listener: ZograEngineEvents[T]) { this.eventEmitter.off(event, listener); } /*emit(event: T, ...args: Parameters) { this.eventEmitter.emit(event, ...args); }*/ }