GameLoop
The foundation of every DN game. Runs a fixed-timestep update loop with a separate render callback — ensuring consistent physics and game logic regardless of the device’s frame rate.
The Problem It Solves
requestAnimationFrame fires at the monitor’s refresh rate — 60hz, 90hz, 144hz, or
whatever the device supports. If your game logic runs once per frame, it literally runs
faster on high-refresh displays.
GameLoop solves this by accumulating elapsed time and running the update in
fixed-size chunks (dt = 1 / fps). The render fires only when an update occurred,
preventing wasted draw calls on frames where nothing changed.
Include
<script src="/js/dn/gameLoop.js"></script>
Constructor
new GameLoop({
fps: 60, // target update rate (default: 60)
updateCallback: (dt) => {}, // called each fixed step; receives dt in seconds
renderCallback: () => {}, // called after any update in a frame
})
Both callbacks are optional, but a loop with neither does nothing useful.
Methods
| Method | Description |
|---|---|
startLoop() | Start the loop. Sets up the first requestAnimationFrame. |
stopLoop() | Cancel the current requestAnimationFrame. Call to pause. |
Delta Time (dt)
dt is always 1 / fps — seconds per update step. Use it to make movement and
physics framerate-independent:
// ✅ Correct — moves at `speed` pixels per second, always
player.x += player.speed * dt;
// ❌ Wrong — moves faster on higher framerates
player.x += player.speed;
Full Example
// Dependencies: mathUtils.js (for Vector2D)
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
let ballPos = new Vector2D(canvas.width / 2, canvas.height / 2);
let ballVel = new Vector2D(150, 100); // pixels per second
function update(dt) {
ballPos.x += ballVel.x * dt;
ballPos.y += ballVel.y * dt;
// Bounce off walls
if (ballPos.x < 0 || ballPos.x > canvas.width) ballVel.x *= -1;
if (ballPos.y < 0 || ballPos.y > canvas.height) ballVel.y *= -1;
}
function render() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = '#4bb8d5';
context.beginPath();
context.arc(ballPos.x, ballPos.y, 10, 0, Math.PI * 2);
context.fill();
}
const loop = new GameLoop({ fps: 60, updateCallback: update, renderCallback: render });
loop.startLoop();
Used In
- Every game in the DN Arcade
- The homepage orbit animation
Source
public/js/dn/gameLoop.js