Getting moving with HTML5 Canvas

Initialise a canvas

<canvas id="c" width="640" height="480"></canvas>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');

Note:

  • Width and height determine the canvas size.
  • CSS width and height will stretch the canvas.
  • 2d refers to the rendering context (API). Other options include webgl.

Basic drawing with Canvas

There are several ways of drawing on the 2d drawing context.

  • Rects (rectangles)
  • Paths
  • Text
  • Images

Drawing Rectangles

Rectangles can fill, stroke, or clear an area.

var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');

// Black rectangle
ctx.fillRect(0,0,200,200);

// Black outline
ctx.strokeRect(200,0,200,200);

// White rectangle (cleared area)
ctx.clearRect(50,50,100,100);

See the Pen Canvas Rectangles by Ashley Kyd (@AshKyd) on CodePen.

Drawing Paths

A bit like Logo without the turtle graphic.

var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');


// Draw a triangle
ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(50,0);
ctx.lineTo(100,100);
ctx.closePath();
ctx.stroke();

// Draw a circle
ctx.beginPath();
ctx.arc(200,50,50,0,Math.PI*2);
ctx.fill();

See the Pen Canvas Paths by Ashley Kyd (@AshKyd) on CodePen.

Path Methods

You can use these methods to draw and fill lines onscreen.

Drawing Text

  • The most basic use is ctx.fillText(text, x, y, [maxWidth])
  • Use textAlign=center and textBaseline=middle to center on the specified point.
  • var canvas = document.getElementById('c');
    var ctx = canvas.getContext('2d');
    
    // Default text
    ctx.strokeRect(0,0,100,100);
    ctx.fillText('#brisjs',50,50);
    
    // Centered Text
    ctx.strokeRect(100,0,100,100);
    
    ctx.font = '12px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle'
    ctx.fillText('#brisjs',150,50);

    See the Pen Canvas Text by Ashley Kyd (@AshKyd) on CodePen.

    Drawing Images

    Use drawImage(img, x, y) to splat any image or canvas element down into your current context.

    var canvas = document.getElementById('c');
    var ctx = canvas.getContext('2d');
    
    // load an image and draw it in!
    var img = document.createElement('img');
    img.onload = function(){
        // Draw the image
        ctx.drawImage(img,0,0);
    
        // and some text
        ctx.font = 'bold 40px Impact';
        ctx.textAlign = 'center';
        ctx.strokeStyle = '#fff';
        ctx.lineWidth = 2;
        ctx.fillText('MEMES AT #brisjs',200,40);
        ctx.strokeText('MEMES AT #brisjs',200,40);
    }
    img.src = 'http://lorempixel.com/400/400/animals/&#39;;

    See the Pen Canvas Images by Ashley Kyd (@AshKyd) on CodePen.

    Using Transforms

    Transforms adjust the coordinate system your drawing tools use.

    var canvas = document.getElementById('c');
    var ctx = canvas.getContext('2d');
    
    // Example translate
    ctx.strokeStyle = 'darkgreen';
    ctx.strokeRect(0,0,100,100);
    
    ctx.strokeStyle = 'limegreen';
    ctx.translate(100,100);
    ctx.strokeRect(0,0,100,100);
    
    ctx.strokeStyle = 'black';
    ctx.rotate(Math.PI/4);
    ctx.strokeRect(0,0,100,100);
    
    // Make some isometric tiles with setTransform
    // ash.ms/blog/2012-07-08/isometric-tile-transforms
    ctx.strokeStyle = 'purple';
    ctx.setTransform(1,-.5,1,.5,0,0);
    ctx.strokeRect(0,200,100,100);
    ctx.strokeRect(100,200,100,100);
    ctx.strokeRect(0,300,100,100);
    ctx.strokeRect(100,300,100,100);

    See the Pen Canvas Transforms by Ashley Kyd (@AshKyd) on CodePen.

    • Transforms are useful for when you have a self-contained item and want it to be able to move.
    • For more information, I've previously written on transforms for isometric games.

    Animation

    setInterval is so 1995. Use the requestAnimationFrame method to call back before the next screen repaint.

    var gameLoop = function(){
        // Do stuff
        requestAnimationFrame(gameLoop);
    }
    requestAnimationFrame(gameLoop);
    
    • requestAnimationFrame won't fire if the browser isn't painting, for instance in another tab or minimised.
    • Unit movement should be calculable as a vector, otherwise everything will stop or slow down with the render process.

    Let's get moving

    This demo shows the basics of animation. The sine wave is calculable based on the current time.

    var canvas = document.getElementById('c');
    var ctx = canvas.getContext('2d');
    
    function sineWave(){
        var yPos = Math.sin(Date.now() / 500 )  100;
        ctx.fillRect(0, yPos, 10, 10);
    }
    
    var gameLoop = function(){
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.save();
        ctx.translate(150, 150);
    
        // Let's draw some sine waves
        for(var i=0; i<10; i++){
            ctx.save();
    
            // pi2 radians == 360°
            ctx.rotate((i/10)Math.PI2);
            sineWave();
            ctx.restore();
        }
    
        ctx.restore();
        requestAnimationFrame(gameLoop);
    }
    requestAnimationFrame(gameLoop);

    See the Pen Canvas Animation by Ashley Kyd (@AshKyd) on CodePen.

    Particles

    Particles are one of the most useful things you can have in a 2D game.

    See the Pen Canvas Particle Generator by Ashley Kyd (@AshKyd) on CodePen.

    • Particles can be anything you want, but gradients are slow to draw so you'll need to cache them.
    • You can plug in one of many physics engines from NPM, but it's easier to accelerate out from a center point.
    • Polar Defender (my entry into the 2014 #js13k)

      js13k is a month-long game competition to make a game in under 13 kb.

      • Polar coordinates & .rotate() make it east to do a radial game.
      • SVG sprites: scalable, re-colourable assets.
      • "Everything's a particle" approach simplifies collision detection.
      • jsfxr for 8-bit sounds.
      • Using a bunch of Unicode emoji as game assets (gotta save space).
      • Code on GitHub
      • Play Polar Defender.

        Where to go from here

        There's a bunch of stuff already out there to make your life easier. Here's some of my favourites:

        • Pick a game engine (or do it by hand)
        • NPM is a treasure trove of amazing things
        • freenode/#bbg - browser based games
        • Learn about Juice in a talk by Martin Jonasson and Petri Purho