Pong - The Game Runner

Sat, May 14, 2011

Game Runner Loop

The GameRunner is very generic. It provides some javascript pre-requisites (see below) and a rudimentary game loop:

  • Initialize the runner
  • Construct canvas front and back buffers
  • Construct a game instance
  • Start a 60fps loop

On each iteration of the loop:

  • call game.update() - providing dt timer interval since last frame
  • call game.draw() - providing back buffer canvas context for drawing on
  • flip back and front buffers
  • update frame rate statistics

And thats really all it does. You can find the demo here

Javascript Pre-Requisites

I want to build a framework that does not require any 3rd party libraries. Since these games are going to be based on the HTML <canvas> and only supported in modern browsers there is no real need for including a full library like jQuery or prototype.js.

However, there are a few pre-requisites we are going to need:

  • Canvas
  • Function.bind
  • Object.create
  • Object.extend
  • addEventListener
  • DOMContentLoaded
  • Image Loader

Canvas

We are building a game using the HTML5 <canvas> element, so duh! we’re going to need an HTML5 <canvas> element! This is supported in all modern browsers, so should be no problem.

Older versions of IE usually require a 3rd party library (excanvas.js), but since IE9 has a native canvas I am going to simply drop support for older versions of IE.

Function.bind

This method is standard in ECMAScript 5. It is one of the most important methods in javascript development and is used to ensure that instance methods used as callbacks (e.g. event handlers) have the correct this set. Its also used to curry arguments when compositing methods.

This method is provided by most modern browsers, but is easy enough to provide for older browsers, a sample implementation is provided by mozilla

if (!Function.prototype.bind) {
  Function.prototype.bind = function(obj) {
    var slice = [].slice,
        args  = slice.call(arguments, 1),
        self  = this,
        nop   = function () {},
        bound = function () {
          return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));   
        };
    nop.prototype   = self.prototype;
    bound.prototype = new nop();
    return bound;
  };
}

Object.create

Another ECMAScript5 standard encapsulates the construction of an object with a specific prototype.

Many attempts have been made to mimic OO class construction patterns in javascript, but in many cases it can be simpler to avoid these entirely and embrace javascripts prototypical nature.

Again, modern browsers will provide this method, but its easy enough to implement it ourselves when necessary:

if (!Object.create) {
  Object.create = function(base) {
    function F() {};
    F.prototype = base;
    return new F();
  }
}

What’s missing from Object.create is the ability to pass arguments to some kind of constructor function. I like to add a wrapper Object.construct that provides this additional behavior on top of the standard Object.create

if (!Object.construct) {
  Object.construct = function(base) {
    var instance = Object.create(base);
    if (instance.initialize)
      instance.initialize.apply(instance, [].slice.call(arguments, 1));
    return instance;
  }
}

Object.extend

Not a standard, but typically provided by libraries such as jQuery or prototype. The ability to copy all of the properties of one object to another can be very useful on occasions.

if (!Object.extend) {
  Object.extend = function(destination, source) {
    for (var property in source) {
      if (source.hasOwnProperty(property))
        destination[property] = source[property];
    }
    return destination;
  };
}

addEventListener

Of course, we need to be able to respond to DOM events. There are a number of established methods for supporting older browsers, but since we are only supporting modern browsers with the <canvas> we can be fairly sure that these browsers support the standard addEventListener (yes, even IE supports it in IE9)

DOMContentLoaded

Knowing when the page is ready to load is also a solved problem with 3rd party libraries such as jQuery and prototype.js, but again, since we are only supporting modern browsers we can be fairly sure that these browsers support the DOMContentLoaded event (yup. IE9 supports this)

Image Loader

One issue <canvas> based games will run into is that they cannot use images until those images are loaded. To ensure we dont try to use an image until it has completed loading we need a helper method that will load multiple images and make a callback when the last image has completed loading.

loadImages: function(sources, callback) { /* load multiple images and callback when ALL have finished loading */
  var images = {};
  var count = sources ? sources.length : 0;
  if (count == 0) {
    callback(images);
  }
  else {
    for(var n = 0 ; n < sources.length ; n++) {
      var source = sources[n];
      var image = document.createElement('img');
      images[source] = image;
      Game.addEvent(image, 'load', function() { if (--count == 0) callback(images); });
      image.src = source;
    }
  }
},

More…

You can find the final game here and the code is here