Spicy Yoghurt | Last updated: 2 Februari 2019 | HTML5 game

Create a proper game loop

In this HTML5 game development tutorial you will learn about the use of game loops, how to set-up a proper one with requestAnimationFrame and how they are connected to the fps of a game.


This tutorial requires the HTML5 file with the canvas, you have created in the previous tutorial. If you skipped that step, you can download the HTML5 file with canvas here.

Why do you need a game loop?

In the previous game development tutorial, you drew a rectangle on the HTML5 canvas. This is super nice and all, but the drawing operation is only performed once. If you want make it appear as if the rectangle is moving, and eventually create an actual game, you need to draw more. A lot more.

As you might know, with games, people always talk about how many fps they can get out of a game with their hardware. Fps means, frames per second. For a smooth experience you want to get around 60fps. That means each second, 60 drawing operations are performed.

If you want to reach 60fps, you need a loop. This is where the game loop comes in!

Set-up a game loop

Ok, so you need a game loop? Why not just use this one?

                
                    while (true) {
                        draw();
                    }
                
            
The loop just starts up and draws, until infinity. So, if your hardware allows it, you will reach 60fps and more. But there is a small problem. When running this code, it will completely stall the browser. There are no CPU cycles left to perform other tasks then drawing. This will hang your browser, and in the worst case even your OS. How to fix this?

The proper game loop

You need a way to give the browser some air. Luckily there is a solution. You can use window.requestAnimationFrame() to tell the browser you want to request a repaint for an animation, or in this case a game.

The browser will perform a callback function on its own time. Meaning it won't hang the system. Also, when a browser tab is no longer focused, the browser might reduce the number of callbacks, to reduce system load and improve battery life of the device it is run on.

How to use requestAnimationFrame()?

The function window.requestAnimationFrame() accepts a function as argument. So you will have to start the game loop by calling window.requestAnimationFrame() once, and then keep on calling it inside the game loop. It's easier to understand in the next example:

                    
                        <script>
                            "use strict";

                            // Declare as variable
                            var canvas;
                            var context;
                            
                            // Listen to the onLoad event
                            window.onload = init;

                            // Trigger init function when the page has loaded
                            function init(){
                                canvas = document.getElementById('canvas');
                                context = canvas.getContext('2d');

                                // Request an animation frame for the first time
                                // The gameLoop() function will be called as a callback of this request
                                window.requestAnimationFrame(gameLoop);
                            }

                            function gameLoop(){
                                // Perform the drawing operation
                                draw();

                                // The loop function has reached it's end
                                // Keep requesting new frames
                                window.requestAnimationFrame(gameLoop);
                            }

                            function draw(){
                                // Get a random color, red or blue
                                context.fillStyle = Math.random() > 0.5? '#ff8080' : '#0099b0';

                                // Draw a rectangle on the canvas
                                context.fillRect(25, 25, 100, 75);
                            }
                        </script>
                    
                    

The running game loop

When running this code, you see a big difference. The rectangle is redrawn roughly 60 times per second. The color of the rectangle is still random, just like in the previous tutorial. This makes it easier to see the game loop is actually working.

60 times per second, a new random color is picked. That's why you now see a flashy rectangle that is switching very fast between red and blue. Well done, your game loop is working!

Final code

Your game loop is in place and the rectangle gets redrawn now. The total code looks like this:

                    
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">

    <title>HTML5 Game Development Tutorial | Spicy Yoghurt</title>
    <meta name="description" content="HTML5 game development tutorial">
    <meta name="author" content="Spicy Yoghurt">
</head>

<body>
    <canvas id="canvas" style="border:1px solid lightgrey;">
        Your browser does not support the HTML5 canvas tag.
    </canvas>
    <script>
        "use strict";

        // Declare as variable
        var canvas;
        var context;

        // Listen to the onLoad event
        window.onload = init;

        // Trigger init function when the page has loaded
        function init() {
            canvas = document.getElementById('canvas');
            context = canvas.getContext('2d');

            // Request an animation frame for the first time
            // The gameLoop() function will be called as a callback of this request
            window.requestAnimationFrame(gameLoop);
        }

        function gameLoop() {
            // Perform the drawing operation
            draw();

            // The loop function has reached it's end
            // Keep requesting new frames
            window.requestAnimationFrame(gameLoop);
        }

        function draw() {
            // Get a random color, red or blue
            context.fillStyle = Math.random() > 0.5? '#ff8080' : '#0099b0';

            // Draw a rectangle on the canvas
            context.fillRect(25, 25, 100, 75);
        }
    </script>
</body>
</html>

                    
                    
You can copy and store this code in a file, or download the complete file here. Feel free to ask questions in the comments.

In the next step of the tutorial, the rectangle will come more alive. You will be learning how to make smooth canvas animations.

Leave a comment