Photo of my face David Thomas Bernal

Writing your my our first game using html5 and canvas

published 9 jun 2012

I recently decided to write an HTML5 game using the canvas tag. I’d made some little animated toys using canvas with my particle systems, but now I wanted to do something bigger and more interactive. Even on the small projects before, the code had a habit of turning into a horrible fucking mess of procedural crap that was too hard to follow. I couldn’t imagine building something more ambitious in that same ad-hoc style.

Like everything that can be accomplished with programming, I’ve always assumed I know how to write a game. After all, I know to program. The rest is just filling in the details. With this game, I decided to put that theory to the test.

Choosing my first game

For my first game, I wanted to write something simple, but still with the key components of a game, like animation, collision detection, and player input. I picked a game I remembered played on my TI-83 calculator in high school:

game concept

In the game, you control the blue circle. As the platforms move up, you have to steer yourself into the gaps to avoid getting crushed to a poorly-rendered red pulp by the spikes.

Structuring a game

The structure of a game in pseudo-code is as follows. In reality, we want to split the game up into some nice objects, so that it’s clearer who plays what role, but this is the basic skeleton.

function game() {
    initialize();

    // do the following in a loop that executes at 60 frames per 
    // second
    window.setInterval(function() {
        //receive input 
        handleInput();

        //update the state and position of objects
        update();

        // handle collisions
        collide();

        // draw the scene
        draw();
    }, 1000/60);
}

Getting started

Now, we want to fill in some of the objects we’ll use to structure our game. If you’d like more detail, check out the annotated source.

Much of the skeleton we saw before is reflected in the Game object. The Game object is the boss that handles coordinating the objects and running the animation loop.

// _.inherits sets up the prototype chain, so that the first argument 
// is the prototype for the object in the second argument.
var Game = _.inherits(function() { }, {
    'constructor': function() {
        // initialize canvases
        // create drawable objects
        // prepare for drawing
    }, 
    'draw': function() {
        // calculate time since last draw
        // loop over and draw each of our drawable objects
    }
});

Like any good leader, the Game object delegates the detail work to various specialists that know exactly how to do their jobs. The Drawable object specializes in—surprise!—drawing. The Game can draw all the objects in our world without caring about the specific way that happens. Drawable also forms the prototype for more-specialized drawing objects.

var Drawable = _.inherits(function() { }, {
    'state': { x: 0, y: 0, vX: 0, vY: 0 },
    'constructor': function(initialState) {
        // initialize state object with initial given state
    },
    'draw': function(dT, game) {
        // multiply the velocity by the time to get a new position

        // draw -- this function will be replaced in descendant classes
        this.doDraw(centroid, dT, game);

        // save state
    },
    'doDraw': function(centroid, dT, game) {
        // draw the actual object
    }
});

An example of a specialized Drawable is the Background object, which handles drawing the scrolling background for the game.

// Background's prototype is the Drawable class
var Background = _.inherits(Drawable, {
    'image': null,
    'ready': false,
    'constructor': function(initialState) {
        // call the parent constructor
        this.constructor.__super__.constructor.call(this, initialState);

        // fetch the image, and track when it loads
        this.image = new Image();
        this.image.onload = _.bind(function() {
            this.ready = true;
        }, this);
        this.image.src = '/posts/game/game-bg.jpg';
    },
    'doDraw': function(centroid, dT, game) {
        if(!this.ready) return;
        if(centroid.y <= 0) 
            centroid.y = game.height;

        // draw the image in two slices

        // first the top slice
        game.backbufferContext.drawImage(
            this.image, 
            /* sx */ 0, 
            /* sy */ this.image.naturalHeight - centroid.y, 
            /* sw */ this.image.naturalWidth, 
            /* sh */ centroid.y, 
            /* dx */ 0, 
            /* dy */ 0, 
            /* dw */ game.width, 
            /* dh */ centroid.y);

        // and second the bottom slice 
        game.backbufferContext.drawImage(
            this.image, 
            /* sx */ 0, /* sy */ 0, 
            /* sw */ this.image.naturalWidth,
            /* sh */ this.image.naturalHeight - centroid.y, 
            /* dx */ 0,
            /* dy */ centroid.y,
            /* dw */ game.width,
            /* dh */ this.image.naturalHeight - centroid.y
        );
    }
});

At this point, we have a nice structure for a game, and an animating background to boot. If you’d like, you can read the full, annotated source for the game, and here it is in action:

Click to start

Next steps

At this point, if I told you this was a game, you’d call me a goddamn liar. Next we’ll add input handling, so the player can move, and then obstacles and collision detection.

Resources

Here’s the best of the million tabs I had open while I was doing this first part of the game.

codeartnotebookinternetworldwidecompass 05 link 72