p3nGu1nZz commited on
Commit
6802c16
·
1 Parent(s): 538ade1

refactored game loop timing

Browse files
Files changed (1) hide show
  1. index.js +34 -19
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
- async function main() {
 
 
 
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
- createBuffers();
35
 
36
  // Generate vertex buffer data and texture
37
- generateVertexDataAndTexture(glyphCanvas);
38
 
39
  // Start the game loop
40
- gameLoop(context);
41
  }
42
 
43
- function createBuffers() {
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 = generateIndices(config.maxGlyphs);
58
  state.device.queue.writeBuffer(state.indexBuffer, 0, new Uint32Array(indices));
59
  }
60
 
61
- function generateIndices(maxGlyphs) {
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 generateVertexDataAndTexture(glyphCanvas) {
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 gameLoop(context) {
101
  let lastTime = performance.now();
102
- const frameInterval = 1000 / config.maxFPS;
103
 
104
- function tick() {
105
  const currentTime = performance.now();
106
- const deltaTime = (currentTime - lastTime) / 1000;
 
 
 
 
107
 
108
- if (currentTime - lastTime >= frameInterval) {
109
- update(deltaTime, context);
110
- lastTime = currentTime;
 
111
  }
112
 
113
- setTimeout(tick, 0);
 
 
 
 
114
  }
115
 
116
- tick();
117
  }
118
 
119
- function update(deltaTime, context) {
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
- main();
 
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();