This commit is contained in:
Andras Schmelczer 2026-05-17 14:12:01 +01:00
commit 80ed37298b
73 changed files with 3619 additions and 1295 deletions

View file

@ -17,8 +17,6 @@ import { RenderInputCache } from './render-input-cache';
import { ToolbarContrastMonitor } from './toolbar-contrast-monitor';
export default class GameLoop {
private static readonly MAX_MIRROR_SEGMENT_COUNT = appConfig.toolbar.mirror.max;
private readonly resources: GameLoopResources;
private readonly audio = new GardenAudio(gardenAudioConfig);
private readonly renderInputs = new RenderInputCache();
@ -29,10 +27,12 @@ export default class GameLoop {
private readonly export4KRenderer: Export4KRenderer;
private readonly framePerformance = new FramePerformance();
private readonly toolbarContrastMonitor: ToolbarContrastMonitor;
private readonly seed = Math.floor(Math.random() * 0xffffffff).toString(16);
private readonly seedValue = Math.floor(Math.random() * 0xffffffff);
private readonly seed = this.seedValue.toString(16);
private readonly resizeListener = this.resize.bind(this);
private readonly keydownListener: (event: KeyboardEvent) => void;
private pendingIntroResizeAt: DOMHighResTimeStamp | null = null;
private hasFinished = false;
private readonly finished = Promise.withResolvers<void>();
@ -47,7 +47,10 @@ export default class GameLoop {
this.introPrompt = new IntroPrompt(ui.prompt);
this.eraserPreview = new EraserPreview(canvas, ui.eraserPreview);
this.toolbarContrastMonitor = new ToolbarContrastMonitor(canvas, ui.toolbar, device);
this.agentPopulation = new AgentPopulation(this.resources.agentGenerationPipeline);
this.agentPopulation = new AgentPopulation(
this.resources.agentGenerationPipeline,
this.seedValue
);
this.agentPopulation.initializeIntroAgents(this.canvasSize);
this.pointerInput = new GardenPointerInput({
canvas,
@ -102,6 +105,10 @@ export default class GameLoop {
this.audio.setMuted(isMuted);
}
public setAudioVolume(volume: number): void {
this.audio.setMasterVolume(volume);
}
public startAudio(userGesture = false): void {
this.audio.start(activeVibe, { userGesture });
}
@ -141,9 +148,10 @@ export default class GameLoop {
const deltaTime = this.deltaTimeCalculator.calculateDeltaTimeInSeconds(time);
this.framePerformance.update(time);
this.agentPopulation.growBudget(deltaTime, this.framePerformance.smoothedFps);
this.introPrompt.update();
this.introPrompt.update(this.pendingIntroResizeAt === null ? deltaTime : 0);
this.resize();
this.resizeSimulationToCanvas();
this.resizeSimulationToCanvas(time);
this.regenerateIntroAfterSettledResize(time);
const { channelColors, backgroundColor } = this.renderInputs.get();
const introProgress = this.introPrompt.progress;
@ -198,7 +206,7 @@ export default class GameLoop {
this.canvas.height = height;
}
private resizeSimulationToCanvas(): void {
private resizeSimulationToCanvas(time: DOMHighResTimeStamp): void {
const scale = this.resources.resizeSimulationTo(this.canvasSize);
if (!scale) {
return;
@ -206,6 +214,32 @@ export default class GameLoop {
this.agentPopulation.resizeAgents(scale);
this.pointerInput.scaleLastPointerPosition(scale);
if (this.introPrompt.shouldRegenerateTitleOnResize) {
this.pendingIntroResizeAt = time;
}
}
private regenerateIntroAfterSettledResize(time: DOMHighResTimeStamp): void {
if (this.pendingIntroResizeAt === null) {
return;
}
if (!this.introPrompt.shouldRegenerateTitleOnResize) {
this.pendingIntroResizeAt = null;
return;
}
if (time - this.pendingIntroResizeAt < appConfig.simulation.intro.resizeSettleMs) {
return;
}
this.introPrompt.rewindToLeaveRemainingTime(
appConfig.simulation.intro.resizeMinimumRemainingSeconds
);
this.resources.clearSimulation();
this.agentPopulation.replaceIntroAgents(this.canvasSize, this.introPrompt.progress);
this.pendingIntroResizeAt = null;
}
private get canvasSize(): vec2 {
@ -220,7 +254,10 @@ export default class GameLoop {
private get mirrorSegmentCount(): number {
const count = Number.isFinite(settings.mirrorSegmentCount)
? settings.mirrorSegmentCount
: 1;
return Math.min(GameLoop.MAX_MIRROR_SEGMENT_COUNT, Math.max(1, Math.round(count)));
: appConfig.toolbar.mirror.min;
return Math.min(
appConfig.toolbar.mirror.max,
Math.max(appConfig.toolbar.mirror.min, Math.round(count))
);
}
}