Spaces:
Running
Running
refactored game loop timing
Browse files
index.js
CHANGED
@@ -11,7 +11,10 @@ import { CANVAS, CTX, COLORS, RENDER_PASS_DESCRIPTOR } from './wgpu-constants.js
|
|
11 |
const canvas = document.querySelector('canvas');
|
12 |
const state = createState(config);
|
13 |
|
14 |
-
|
|
|
|
|
|
|
15 |
const adapter = await navigator.gpu?.requestAdapter();
|
16 |
const { device, context, presentationFormat } = await initializeWebGPU(navigator, adapter, canvas);
|
17 |
if (!device) return;
|
@@ -31,16 +34,16 @@ async function main() {
|
|
31 |
glyphCanvas.style.backgroundColor = '#222';
|
32 |
|
33 |
// Create vertex and index buffers
|
34 |
-
|
35 |
|
36 |
// Generate vertex buffer data and texture
|
37 |
-
|
38 |
|
39 |
// Start the game loop
|
40 |
-
|
41 |
}
|
42 |
|
43 |
-
function
|
44 |
const vertexBufferSize = config.maxGlyphs * config.vertsPerGlyph * config.floatsPerVertex * 4;
|
45 |
state.vertexBuffer = state.device.createBuffer({
|
46 |
label: 'vertices',
|
@@ -54,18 +57,18 @@ function createBuffers() {
|
|
54 |
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
|
55 |
});
|
56 |
|
57 |
-
const indices =
|
58 |
state.device.queue.writeBuffer(state.indexBuffer, 0, new Uint32Array(indices));
|
59 |
}
|
60 |
|
61 |
-
function
|
62 |
return Array.from({ length: maxGlyphs * 6 }, (_, i) => {
|
63 |
const ndx = Math.floor(i / 6) * 4;
|
64 |
return (i % 6 < 3 ? [ndx, ndx + 1, ndx + 2] : [ndx + 2, ndx + 1, ndx + 3])[i % 3];
|
65 |
});
|
66 |
}
|
67 |
|
68 |
-
function
|
69 |
const { vertexData, numGlyphs, width, height } = generateGlyphVerticesForText('Hello\nworld!\nText in\nWebGPU!', COLORS, config, glyphCanvas);
|
70 |
state.device.queue.writeBuffer(state.vertexBuffer, 0, vertexData);
|
71 |
|
@@ -97,28 +100,40 @@ function generateVertexDataAndTexture(glyphCanvas) {
|
|
97 |
state.height = height;
|
98 |
}
|
99 |
|
100 |
-
function
|
101 |
let lastTime = performance.now();
|
102 |
-
|
103 |
|
104 |
-
function
|
105 |
const currentTime = performance.now();
|
106 |
-
const
|
|
|
|
|
|
|
|
|
107 |
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
111 |
}
|
112 |
|
113 |
-
|
|
|
|
|
|
|
|
|
114 |
}
|
115 |
|
116 |
-
|
117 |
}
|
118 |
|
119 |
-
function
|
120 |
state.time += deltaTime;
|
|
|
|
|
121 |
|
|
|
122 |
// Set up projection and view matrices
|
123 |
const fov = 60 * Math.PI / 180;
|
124 |
const aspect = canvas.clientWidth / canvas.clientHeight;
|
@@ -141,4 +156,4 @@ function update(deltaTime, context) {
|
|
141 |
state.device.queue.submit([encoder.finish()]);
|
142 |
}
|
143 |
|
144 |
-
|
|
|
11 |
const canvas = document.querySelector('canvas');
|
12 |
const state = createState(config);
|
13 |
|
14 |
+
const FIXED_DELTA_TIME = 1 / 60; // Fixed time step of 60 FPS for physics and game logic
|
15 |
+
const MAX_FRAME_TIME = 0.25; // Maximum time to simulate per frame to prevent spiral of death
|
16 |
+
|
17 |
+
async function Main() {
|
18 |
const adapter = await navigator.gpu?.requestAdapter();
|
19 |
const { device, context, presentationFormat } = await initializeWebGPU(navigator, adapter, canvas);
|
20 |
if (!device) return;
|
|
|
34 |
glyphCanvas.style.backgroundColor = '#222';
|
35 |
|
36 |
// Create vertex and index buffers
|
37 |
+
CreateBuffers();
|
38 |
|
39 |
// Generate vertex buffer data and texture
|
40 |
+
GenerateVertexDataAndTexture(glyphCanvas);
|
41 |
|
42 |
// Start the game loop
|
43 |
+
GameLoop(context);
|
44 |
}
|
45 |
|
46 |
+
function CreateBuffers() {
|
47 |
const vertexBufferSize = config.maxGlyphs * config.vertsPerGlyph * config.floatsPerVertex * 4;
|
48 |
state.vertexBuffer = state.device.createBuffer({
|
49 |
label: 'vertices',
|
|
|
57 |
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
|
58 |
});
|
59 |
|
60 |
+
const indices = GenerateIndices(config.maxGlyphs);
|
61 |
state.device.queue.writeBuffer(state.indexBuffer, 0, new Uint32Array(indices));
|
62 |
}
|
63 |
|
64 |
+
function GenerateIndices(maxGlyphs) {
|
65 |
return Array.from({ length: maxGlyphs * 6 }, (_, i) => {
|
66 |
const ndx = Math.floor(i / 6) * 4;
|
67 |
return (i % 6 < 3 ? [ndx, ndx + 1, ndx + 2] : [ndx + 2, ndx + 1, ndx + 3])[i % 3];
|
68 |
});
|
69 |
}
|
70 |
|
71 |
+
function GenerateVertexDataAndTexture(glyphCanvas) {
|
72 |
const { vertexData, numGlyphs, width, height } = generateGlyphVerticesForText('Hello\nworld!\nText in\nWebGPU!', COLORS, config, glyphCanvas);
|
73 |
state.device.queue.writeBuffer(state.vertexBuffer, 0, vertexData);
|
74 |
|
|
|
100 |
state.height = height;
|
101 |
}
|
102 |
|
103 |
+
function GameLoop(context) {
|
104 |
let lastTime = performance.now();
|
105 |
+
let accumulator = 0;
|
106 |
|
107 |
+
function Tick() {
|
108 |
const currentTime = performance.now();
|
109 |
+
const frameTime = (currentTime - lastTime) / 1000;
|
110 |
+
lastTime = currentTime;
|
111 |
+
|
112 |
+
const deltaTime = Math.min(frameTime, MAX_FRAME_TIME);
|
113 |
+
accumulator += deltaTime;
|
114 |
|
115 |
+
// Fixed time step updates for game logic
|
116 |
+
while (accumulator >= FIXED_DELTA_TIME) {
|
117 |
+
FixedUpdate(FIXED_DELTA_TIME);
|
118 |
+
accumulator -= FIXED_DELTA_TIME;
|
119 |
}
|
120 |
|
121 |
+
// Variable time step update for rendering
|
122 |
+
const alpha = accumulator / FIXED_DELTA_TIME;
|
123 |
+
Render(alpha, context);
|
124 |
+
|
125 |
+
requestAnimationFrame(Tick);
|
126 |
}
|
127 |
|
128 |
+
Tick();
|
129 |
}
|
130 |
|
131 |
+
function FixedUpdate(deltaTime) {
|
132 |
state.time += deltaTime;
|
133 |
+
// Perform game logic updates here, such as physics and AI
|
134 |
+
}
|
135 |
|
136 |
+
function Render(alpha, context) {
|
137 |
// Set up projection and view matrices
|
138 |
const fov = 60 * Math.PI / 180;
|
139 |
const aspect = canvas.clientWidth / canvas.clientHeight;
|
|
|
156 |
state.device.queue.submit([encoder.finish()]);
|
157 |
}
|
158 |
|
159 |
+
Main();
|