HTML5 Canvas: The Game Loop and Animation
HTML5 Canvas: The Game Loop and Animation
Drawing shapes on a canvas is just the beginning. To make a game, those shapes need to move! This is where the Game Loop comes in. It's the beating heart of every video game ever made.
A Game Loop does three things repeatedly, usually 60 times a second (60 FPS):
- Clear the old drawings off the canvas.
- Update the positions and logic of your game objects.
- Draw the objects in their new positions.
1. Why requestAnimationFrame?
In the early days of the web, developers used setInterval or setTimeout for animations. Today, we use window.requestAnimationFrame. It's significantly better because:
- It's optimized by the browser to match your screen's refresh rate (usually 60Hz or 144Hz for buttery smooth animations).
- It pauses when the user switches to another browser tab, saving battery and CPU.
2. Clearing the Frame (clearRect)
If you move an object without clearing the canvas first, it will leave a permanent "trail" behind it, like a paintbrush dragging across a page. You must erase the entire canvas at the start of every frame using clearRect.
ctx.clearRect(0, 0, canvas.width, canvas.height); // Erases everything
3. Building a Simple Bouncing Ball
Let's put it all together into a working Game Loop. We'll make a ball that bounces off the left and right walls of the canvas.
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// 1. Define our object state
let ball = {
x: 50,
y: 150,
radius: 20,
speedX: 5 // How much X changes per frame (velocity)
};
// 2. The Game Loop Function
function update() {
// Step A: Clear the Canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Step B: Update Logic (Move the ball)
ball.x += ball.speedX;
// Bounce logic: If ball hits right or left edge, reverse speed
if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
ball.speedX = -ball.speedX; // Reverse direction
}
// Step C: Draw the new frame
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, 2 * Math.PI);
ctx.fillStyle = 'red';
ctx.fill();
// Step D: Loop it! Call update again before the next screen repaint
requestAnimationFrame(update);
}
// 3. Start the loop
update();
And that’s it! The requestAnimationFrame(update) at the end creates an infinite loop that smoothly animates the ball back and forth across your screen. Once you understand this loop, you are officially making a game!