Canvas Timers

Timers can be used to call a javascript function at set intervals. There are two ways to call a timer function:

setTimeout(functionName, milliseconds)
This will cause a function to be called once. The function will be called after waiting a specified number of milliseconds.
setInterval(functionName, milliseconds)
This will cause a function to be called repeatedly at specified time intervals.

A timer that has been set by setInterval() can be stopped by calling:

clearInterval(timerVariable)
This will cause timerVariable to stop calling its associated timer function.

In order to use clearInterval(), a timer variable needs to be associated with a call to setInterval. This is done below:

let myTimer = setInterval(myFunction, 100);
clearInterval(myTimer);

 

Example using setInterval (Run Example)

<!-- Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. -->

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>GENIUS worked example</title>
        <link rel="shortcut icon" type="image/png" href="images/genius_icon.png"/>
        <style>
            #gameCanvas
            {
                /* the canvas styling usually does not change */
                outline:1px solid darkgrey;
                width:500px;
                height:500px;
            }
        </style>
    </head>

    <body>
        <canvas id = "gameCanvas"></canvas>

        <script>
            let mapImage = new Image();
            mapImage.src = "images/map.png";

            let carImage = new Image();
            carImage.src = "images/car.png";

            window.onload = function ()
            {
                let canvas = document.getElementById("gameCanvas");
                canvas.width = canvas.clientWidth;
                canvas.height = canvas.clientHeight;
                let ctx = canvas.getContext("2d");

                let x = 0;

                animationInterval = setInterval(renderCanvas, 25); // call renderCanvas function every 25 milliseconds

                function renderCanvas()
                {
                    ctx.drawImage(mapImage, 0, 0, canvas.width, canvas.height); // clear any previous drawing

                    if (x > (canvas.width + 1))
                    {
                        x = 0;
                    }
                    else
                    {
                        ctx.drawImage(carImage, x, 240, 40, 20);
                        x++;
                    }
                }
            };
        </script>
    </body>
</html>

RequestAnimationFrame

In the above example, the rendering code is tied to the moving image (gameObject) code. This solution is fine when there is only one gameObject. It is not practical when there are many gameObjects. Ideally, we should seperate the rendering code from the gameObject code.

In order to ensure smooth animation display, the rendering code should be called as often as possible. Javascript has an additional timer, called requestAnimationFrame(). This timer will run as fast as the device allows. Faster devices will call this timer more frequently that slower devices when running the same program. Using requestAnimationFrame will always result in the best game rendering. The example below separates the gameObject update code from the rendering code.

Example of separate update and render code (Run Example)

<!-- Author: Derek O Reilly, Dundalk Institute of Technology, Ireland. -->

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>GENIUS worked example</title>
        <link rel="shortcut icon" type="image/png" href="images/genius_icon.png"/>
        <style>
            #gameCanvas
            {
                /* the canvas styling usually does not change */
                outline:1px solid darkgrey;
                width:500px;
                height:500px;
            }
        </style>

    </head>

    <body>
        <canvas id = "gameCanvas"></canvas>

        <script>
            let imgImage = new Image();
            imgImage.src = "images/map.png";

            let carImage = new Image();
            carImage.src = "images/car.png";

            window.onload = function ()
            {
                let canvas = document.getElementById("gameCanvas");
                canvas.width = canvas.clientWidth;
                canvas.height = canvas.clientHeight;
                let ctx = canvas.getContext("2d");

                let x = 0;

                animationInterval = setInterval(updateCarState, 25); // call renderCanvas function every 25 milliseconds

                renderCanvas(); // first call to renderCanvas

                function updateCarState()
                {
                    if (x > (canvas.width + 1))
                    {
                        x = 0;
                    }
                    else
                    {
                        x++;
                    }
                }

                function renderCanvas()
                {
                    ctx.drawImage(imgImage, 0, 0, canvas.width, canvas.height); // clear any previous drawing
                    ctx.drawImage(carImage, x, 240, 40, 20);

                    requestAnimationFrame(renderCanvas); // call renderCanvas again as soon as possible
                }
            };
        </script>  
    </body>
</html>