Files
HexTowerDefense3/src/app/components/game/vis/VisMain.ts
2025-05-17 15:54:11 +02:00

107 lines
3.4 KiB
TypeScript

import { AssetPreloaderService } from "../../../assetPreloaderService";
import { SplashComponent } from "../../splash/splash.component";
import { SimMain } from "../sim/SimMain";
import { VisLevel } from "./VisLevel";
export class VisMain {
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
wallPattern: CanvasPattern;
visLevel: VisLevel;
simMain: SimMain;
private startTimestamp: number = 0;
private active: boolean = true;
private ready: boolean = false;
private gap: number = 0;
assets: AssetPreloaderService;
constructor(simMain: SimMain, assets: AssetPreloaderService, canvas: HTMLCanvasElement) {
this.assets = assets;
this.simMain = simMain;
this.canvas = canvas;
this.context = this.canvas.getContext("2d")!;
this.context.globalCompositeOperation = "source-over";
this.wallPattern = this.createPattern(assets.getImage("wall.png"), 48);
this.visLevel = new VisLevel(this, this.simMain, this.simMain.gdRoot, assets);
const host = this;
requestAnimationFrame(function step(timestamp) {
host.step(timestamp);
});
}
private createPattern(image: HTMLImageElement, size: number): CanvasPattern {
const tempCanvas = document.createElement("canvas");
const tempContext = tempCanvas.getContext("2d")!;
tempCanvas.width = size;
tempCanvas.height = size;
tempContext.drawImage(image, 0, 0, image.width, image.height, 0, 0, size, size);
return this.context.createPattern(tempCanvas, 'repeat')!;
}
private step(timestamp: number) {
if (!this.active) {
return;
}
const host = this;
requestAnimationFrame((timestamp: number) => {
host.step(timestamp);
});
if (!this.startTimestamp) {
this.startTimestamp = timestamp;
}
const simLevel = this.simMain.currentLevel;
if (!simLevel) {
return;
}
let targetStep = (timestamp - this.startTimestamp) * this.simMain.gdRoot.simulation.stepsPerSecond / 1000 - this.gap;
if (simLevel.paused) {
this.gap += targetStep - simLevel.currentStep;
targetStep = simLevel.currentStep;
}
this.simMain.executeUntilStep(targetStep);
this.visLevel.updateEveryFrame(targetStep);
this.onRender();
};
public onResized() {
const gameHost = document.getElementById("game-host") as HTMLDivElement;
const width = gameHost.clientWidth;
const height = gameHost.clientHeight;
const ratio = window.devicePixelRatio;
this.canvas.width = width * ratio;
this.canvas.height = height * ratio;
this.canvas.style.width = width + "px";
this.canvas.style.height = height + "px";
this.context.scale(ratio, ratio);
this.visLevel.updateSize();
};
private onRender() {
this.clear();
const ctx = this.context;
ctx.font = "12px Tahoma";
const simLevel = this.simMain.currentLevel;
if (!!simLevel) {
if (!this.ready) {
this.onResized();
this.ready = true;
}
this.visLevel.draw();
}
};
private clear() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
private stop() {
this.active = false;
}
}