This commit is contained in:
parent
2347ecd201
commit
10a81ba474
45 changed files with 1974 additions and 490 deletions
|
|
@ -22,7 +22,11 @@ export default class GameLoop {
|
|||
private static readonly DEV_STATS_INTERVAL_MS = 250;
|
||||
|
||||
private readonly resources: GameLoopResources;
|
||||
private readonly audio = new GardenAudio(gardenAudioConfig);
|
||||
private readonly audio = new GardenAudio(
|
||||
gardenAudioConfig,
|
||||
appConfig.audioEngine,
|
||||
appConfig.simulation.maxMirrorSegmentCount
|
||||
);
|
||||
private readonly renderInputs = new RenderInputCache();
|
||||
private readonly introPrompt: IntroPrompt;
|
||||
private readonly eraserPreview: EraserPreview;
|
||||
|
|
@ -30,12 +34,13 @@ export default class GameLoop {
|
|||
private readonly agentPopulation: AgentPopulation;
|
||||
private readonly export4KRenderer: Export4KRenderer;
|
||||
private readonly framePerformance = new FramePerformance();
|
||||
private readonly devStatsElement: HTMLDivElement | null = null;
|
||||
private readonly devStatsElement: HTMLDivElement | null;
|
||||
private readonly seed = Math.floor(Math.random() * 0xffffffff).toString(16);
|
||||
private readonly resizeListener = this.resize.bind(this);
|
||||
private readonly keydownListener: (event: KeyboardEvent) => void;
|
||||
|
||||
private lastDevStatsUpdateAt = 0;
|
||||
private isStatsOverlayPinned = false;
|
||||
private hasFinished = false;
|
||||
private readonly finished = Promise.withResolvers<void>();
|
||||
|
||||
|
|
@ -46,9 +51,8 @@ export default class GameLoop {
|
|||
ui: GardenUi
|
||||
) {
|
||||
this.resize();
|
||||
if (import.meta.env.DEV) {
|
||||
this.devStatsElement = this.createDevStatsElement();
|
||||
}
|
||||
this.devStatsElement = this.createDevStatsElement();
|
||||
this.syncDevStatsVisibility();
|
||||
this.resources = new GameLoopResources(canvas, device, this.canvasSize);
|
||||
this.introPrompt = new IntroPrompt(ui.prompt);
|
||||
this.eraserPreview = new EraserPreview(canvas, ui.eraserPreview);
|
||||
|
|
@ -108,6 +112,17 @@ export default class GameLoop {
|
|||
this.audio.setMuted(isMuted);
|
||||
}
|
||||
|
||||
public setStatsOverlayPinned(isPinned: boolean): void {
|
||||
const wasVisible = this.shouldShowDevStats;
|
||||
this.isStatsOverlayPinned = isPinned;
|
||||
this.syncDevStatsVisibility();
|
||||
|
||||
if (!wasVisible && this.shouldShowDevStats) {
|
||||
this.lastDevStatsUpdateAt = Number.NEGATIVE_INFINITY;
|
||||
this.updateDevStats(performance.now());
|
||||
}
|
||||
}
|
||||
|
||||
public startAudio(userGesture = false): void {
|
||||
this.audio.start(activeVibe, { userGesture });
|
||||
}
|
||||
|
|
@ -205,7 +220,7 @@ export default class GameLoop {
|
|||
frameCpuStartedAt,
|
||||
encodeCpuMs,
|
||||
activeAgentCount: this.agentPopulation.activeAgentCount,
|
||||
targetAgentBudget: this.agentPopulation.targetAgentBudget,
|
||||
agentBudgetMax: settings.agentBudgetMax,
|
||||
canvas: this.canvas,
|
||||
devicePixelRatio: this.devicePixelRatio,
|
||||
renderSpeed: settings.renderSpeed,
|
||||
|
|
@ -235,22 +250,31 @@ export default class GameLoop {
|
|||
private updateDevStats(time: DOMHighResTimeStamp): void {
|
||||
if (
|
||||
!this.devStatsElement ||
|
||||
!this.shouldShowDevStats ||
|
||||
time - this.lastDevStatsUpdateAt < GameLoop.DEV_STATS_INTERVAL_MS
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastDevStatsUpdateAt = time;
|
||||
const displayRefreshFps = Math.round(this.framePerformance.displayRefreshFps);
|
||||
this.devStatsElement.textContent = [
|
||||
`FPS ${this.framePerformance.smoothedFps.toFixed(1)} / ${Math.round(
|
||||
this.framePerformance.refreshTargetFps
|
||||
)}`,
|
||||
`FPS ${this.framePerformance.smoothedFps.toFixed(1)} / ${displayRefreshFps}`,
|
||||
`Agents ${this.formatDevStatNumber(this.agentPopulation.activeAgentCount)}`,
|
||||
`Target ${this.formatDevStatNumber(this.agentPopulation.targetAgentBudget)}`,
|
||||
`Cap ${this.formatDevStatNumber(settings.agentBudgetMax)}`,
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
private syncDevStatsVisibility(): void {
|
||||
if (!this.devStatsElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isVisible = this.shouldShowDevStats;
|
||||
this.devStatsElement.hidden = !isVisible;
|
||||
this.devStatsElement.setAttribute('aria-hidden', String(!isVisible));
|
||||
}
|
||||
|
||||
private formatDevStatNumber(value: number): string {
|
||||
return Math.max(0, Math.round(value)).toLocaleString('en-US');
|
||||
}
|
||||
|
|
@ -298,4 +322,8 @@ export default class GameLoop {
|
|||
: 1;
|
||||
return Math.min(GameLoop.MAX_MIRROR_SEGMENT_COUNT, Math.max(1, Math.round(count)));
|
||||
}
|
||||
|
||||
private get shouldShowDevStats(): boolean {
|
||||
return import.meta.env.DEV || this.isStatsOverlayPinned;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue