clean up
This commit is contained in:
parent
d6a8f898d1
commit
15e99380b5
84 changed files with 1659 additions and 4726 deletions
|
|
@ -6,11 +6,13 @@ import { appConfig } from '../config';
|
|||
import { activeVibe, settings } from '../settings';
|
||||
import { DeltaTimeCalculator } from '../utils/delta-time-calculator';
|
||||
import { AgentPopulation } from './agent-population';
|
||||
import { DevStatsOverlay } from './dev-stats-overlay';
|
||||
import { EraserPreview } from './eraser-preview';
|
||||
import { Export4KRenderer } from './export-4k-renderer';
|
||||
import { FramePerformance } from './frame-performance';
|
||||
import { GameLoopResources } from './game-loop-resources';
|
||||
import { GardenUi } from './game-loop-types';
|
||||
import { getInternalRenderSize } from './internal-render-size';
|
||||
import { IntroPrompt } from './intro-prompt';
|
||||
import { GardenPointerInput } from './pointer-input';
|
||||
import { RenderInputCache } from './render-input-cache';
|
||||
|
|
@ -26,11 +28,11 @@ export default class GameLoop {
|
|||
private readonly agentPopulation: AgentPopulation;
|
||||
private readonly export4KRenderer: Export4KRenderer;
|
||||
private readonly framePerformance = new FramePerformance();
|
||||
private readonly devStatsOverlay: DevStatsOverlay | null;
|
||||
private readonly toolbarContrastMonitor: ToolbarContrastMonitor;
|
||||
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;
|
||||
|
|
@ -38,11 +40,14 @@ export default class GameLoop {
|
|||
|
||||
public constructor(
|
||||
private readonly canvas: HTMLCanvasElement,
|
||||
device: GPUDevice,
|
||||
private readonly device: GPUDevice,
|
||||
private readonly deltaTimeCalculator: DeltaTimeCalculator,
|
||||
ui: GardenUi
|
||||
) {
|
||||
this.resize();
|
||||
this.devStatsOverlay = import.meta.env.DEV
|
||||
? new DevStatsOverlay(canvas.parentElement ?? document.body)
|
||||
: null;
|
||||
this.resources = new GameLoopResources(canvas, device, this.canvasSize);
|
||||
this.introPrompt = new IntroPrompt(ui.prompt);
|
||||
this.eraserPreview = new EraserPreview(canvas, ui.eraserPreview);
|
||||
|
|
@ -50,7 +55,7 @@ export default class GameLoop {
|
|||
this.agentPopulation = new AgentPopulation(
|
||||
this.resources.agentGenerationPipeline,
|
||||
this.seedValue,
|
||||
() => this.devicePixelRatio
|
||||
() => this.canvasPixelRatio
|
||||
);
|
||||
this.agentPopulation.initializeIntroAgents(this.canvasSize);
|
||||
this.pointerInput = new GardenPointerInput({
|
||||
|
|
@ -60,7 +65,7 @@ export default class GameLoop {
|
|||
eraserAgentPipeline: this.resources.eraserAgentPipeline,
|
||||
eraserTexturePipeline: this.resources.eraserTexturePipeline,
|
||||
eraserPreview: this.eraserPreview,
|
||||
getDevicePixelRatio: () => this.devicePixelRatio,
|
||||
getCanvasPixelRatio: () => this.canvasPixelRatio,
|
||||
getMirrorSegmentCount: () => this.mirrorSegmentCount,
|
||||
onStartDrawing: () => this.introPrompt.markStartedDrawing(),
|
||||
onEraseGestureEnded: () => this.agentPopulation.requestCompactionAfterErase(),
|
||||
|
|
@ -79,13 +84,8 @@ export default class GameLoop {
|
|||
getSourceTextureView: () => this.resources.textures.sourceMapA.getTextureView(),
|
||||
getVibeId: () => activeVibe.id,
|
||||
});
|
||||
this.keydownListener = () => {
|
||||
this.audio.start(activeVibe, { userGesture: true });
|
||||
this.introPrompt.complete();
|
||||
};
|
||||
|
||||
window.addEventListener('resize', this.resizeListener);
|
||||
window.addEventListener('keydown', this.keydownListener, { once: true });
|
||||
this.pointerInput.attach();
|
||||
}
|
||||
|
||||
|
|
@ -132,15 +132,16 @@ export default class GameLoop {
|
|||
await this.finished.promise;
|
||||
|
||||
window.removeEventListener('resize', this.resizeListener);
|
||||
window.removeEventListener('keydown', this.keydownListener);
|
||||
this.pointerInput.detach();
|
||||
this.devStatsOverlay?.destroy();
|
||||
this.toolbarContrastMonitor.destroy();
|
||||
this.introPrompt.destroy();
|
||||
await this.agentPopulation.waitForCompaction();
|
||||
this.resources.destroy();
|
||||
await this.audio.destroy();
|
||||
}
|
||||
|
||||
private readonly render = async (time: DOMHighResTimeStamp) => {
|
||||
private readonly render = (time: DOMHighResTimeStamp) => {
|
||||
if (this.hasFinished) {
|
||||
this.finished.resolve();
|
||||
return;
|
||||
|
|
@ -148,7 +149,10 @@ export default class GameLoop {
|
|||
|
||||
const deltaTime = this.deltaTimeCalculator.calculateDeltaTimeInSeconds(time);
|
||||
this.framePerformance.update(time);
|
||||
this.agentPopulation.growBudget(deltaTime, this.framePerformance.smoothedFps);
|
||||
this.agentPopulation.growBudget(
|
||||
this.framePerformance.frameDeltaSeconds,
|
||||
this.framePerformance.smoothedFps
|
||||
);
|
||||
this.introPrompt.update(this.pendingIntroResizeAt === null ? deltaTime : 0);
|
||||
this.resize();
|
||||
this.resizeSimulationToCanvas(time);
|
||||
|
|
@ -156,8 +160,8 @@ export default class GameLoop {
|
|||
|
||||
const { channelColors, backgroundColor } = this.renderInputs.get();
|
||||
const introProgress = this.introPrompt.progress;
|
||||
const devicePixelRatio = this.devicePixelRatio;
|
||||
const eraserPixelSize = settings.eraserSize * devicePixelRatio;
|
||||
const canvasPixelRatio = this.canvasPixelRatio;
|
||||
const eraserPixelSize = settings.eraserSize * canvasPixelRatio;
|
||||
const isErasing = this.pointerInput.isEraseMode;
|
||||
const accentColor = channelColors[settings.selectedColorIndex] ?? channelColors[0];
|
||||
this.renderInputs.updateAccentColor(accentColor);
|
||||
|
|
@ -171,7 +175,7 @@ export default class GameLoop {
|
|||
deltaTime,
|
||||
canvasSize: this.canvasSize,
|
||||
activeAgentCount: this.agentPopulation.activeAgentCount,
|
||||
devicePixelRatio,
|
||||
canvasPixelRatio,
|
||||
introProgress,
|
||||
selectedColorIndex: settings.selectedColorIndex,
|
||||
isErasing,
|
||||
|
|
@ -186,20 +190,28 @@ export default class GameLoop {
|
|||
);
|
||||
|
||||
this.pointerInput.clearSwipesIfIdle();
|
||||
await this.agentPopulation.compactAfterErase(this.pointerInput.isSwipeActive);
|
||||
this.agentPopulation.compactAfterErase(this.pointerInput.isSwipeActive);
|
||||
this.devStatsOverlay?.update({
|
||||
time,
|
||||
fps: this.framePerformance.measuredFps,
|
||||
agentCount: this.agentPopulation.activeAgentCount,
|
||||
frameTimeMs: this.framePerformance.measuredFrameTimeMs,
|
||||
renderWidth: this.canvas.width,
|
||||
renderHeight: this.canvas.height,
|
||||
});
|
||||
|
||||
requestAnimationFrame(this.render);
|
||||
};
|
||||
|
||||
private resize(): void {
|
||||
const width = Math.max(
|
||||
1,
|
||||
Math.floor(this.canvas.clientWidth * this.devicePixelRatio)
|
||||
);
|
||||
const height = Math.max(
|
||||
1,
|
||||
Math.floor(this.canvas.clientHeight * this.devicePixelRatio)
|
||||
);
|
||||
const rect = this.canvas.getBoundingClientRect();
|
||||
const { width, height } = getInternalRenderSize({
|
||||
clientHeight: rect.height || this.canvas.clientHeight,
|
||||
clientWidth: rect.width || this.canvas.clientWidth,
|
||||
maxPixelScale: appConfig.simulation.maxDevicePixelRatio,
|
||||
maxTextureDimension: this.device.limits.maxTextureDimension2D,
|
||||
targetAreaMegapixels: settings.internalRenderAreaMegapixels,
|
||||
});
|
||||
|
||||
if (this.canvas.width === width && this.canvas.height === height) {
|
||||
return;
|
||||
|
|
@ -249,8 +261,11 @@ export default class GameLoop {
|
|||
return vec2.fromValues(this.canvas.width, this.canvas.height);
|
||||
}
|
||||
|
||||
private get devicePixelRatio(): number {
|
||||
const ratio = window.devicePixelRatio;
|
||||
private get canvasPixelRatio(): number {
|
||||
const rect = this.canvas.getBoundingClientRect();
|
||||
const xScale = rect.width > 0 ? this.canvas.width / rect.width : 1;
|
||||
const yScale = rect.height > 0 ? this.canvas.height / rect.height : xScale;
|
||||
const ratio = (xScale + yScale) / 2;
|
||||
return Number.isFinite(ratio) && ratio > 0 ? ratio : 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue