Resource Management

We have been using resources for some time now, in the form of image resources, i.e.:

var img = new Image(); img.src = '/some_image.png';

But there are a couple of concerns that we probably should address with these resources:

  1. First is an issue of organization; as we add more and more images, this approach gets harder to keep organized.
  2. Second, images (and other resources) tend to be sizable files. Ideally we only want to load them once, and re-use the previously loaded version.
  3. Third is an issue specific to JavaScript. When we add a resource like an image, a sound, or even a video to a webpage either directly in the html (i.e. <img src='/some_image.png'>) or programmatically (as we do above), the image is loaded asynchronously.

Thinking Asynchronously

This last point means that the browser sends a request to our web server to download the resource, then continues processing our JavaScript code. What if our code tries to execute this line before that image has finished downloading?

ctx.drawImage(img, 0, 0);

If you guessed an error, you're right. And that error can crash our game! You probably haven't experienced this yet because you've been running your games locally, where the resource files are typically immediately available. But move to a network-supplied approach, and you're almost guaranteed it will happen.

So how can we prevent this issue? Think about asynchronous JavaScript functions for a moment... what do they do when they finish their work? They call a callback function! The 'onload' callback is built into the Image() and other resource objects. It will execute arbitrary code once the resource has loaded.

img.onload = function() { // Some code here }

But what code might we want to implement? Something that would keep us from entering our main game loop until all the resources had loaded, thus preventing the aforementioned errors. If we had only one resource, our img, we might write:

img.onload = function() { masterLoop(; }

This delays the start of the game until the image finishes loading. But what if we have multiple images? We might use a counter initialized to the number of resources, i.e.:

var resourceCount = 3; function resourceLoaded() { resourceCount--; if(resourceCount == 0) { masterLoop(; } } var img1 = new Image(); img1.onload = resourceLoaded(); img1.src = '/image_1.png'; var img2 = new Image(); img2.onload = resourceLoaded(); img1.src = '/image_2.png'; var img3 = new Image(); img3.onload = resourceLoaded(); img3.src = '/image_1.png';

This will only trigger the game loop if all three images successfully load.

Defining a Resource Manager

Of course, when we look at the above code, a clear pattern emerges. We could abstract this pattern into its own class, a ResourceManager, which could address all three issues we brought up before.

module.exports = exports = ResourceManager; function ResourceManager(callback) { this.callback = callback; this.resourceLoadCount = 0; this.images = {} } /** * @function resourceLoaded * is a helper function to trigger each time a new * resource is loaded. Once all have been loaded, * it triggers the saved callback. */ function resourceLoaded() { this.resourceLoadCount--; if(this.resourceLoadCount == 0) this.callback(); } /** * @function addImage * @param {url} path - the relative or absolute url * to the image resource to load. * @returns {Image} the (unloaded) image object. * ResourceManager.prototype.loadAll() should be * called before using the image. */ ResourceManager.prototype.addImage = function(path) { // Only load an image once if(this.images[path]) return this.images[path]; this.resourceLoadCount++; this.images[path] = new Image(); this.images[path].onload = resourceLoaded; return this.images[path]; } ResourceManager.prototype.getImage = function(path) { // Return the image if it exists if(this.images[path]) return this.images[path]; throw 'Resource ' + path + ' not loaded!'; } /** * @function loadAll() * Load all resources currently in the resource manager */ ResourceManager.prototype.loadAll = function() { var self = this; // Iterate over all images that have been added Object.keys(this.images).forEach(function(path){ self.images[path].url = path; }); }

In creating our game, we would want to create a resource manager, add our images with addImage(), then call loadAll(). We can store a reference to the image returned from addImage(), or call getImage() at any future point with the image url. If the image doesn't exist, it throws an exception, calling our attention to the missing file.

Audio Resources

Another resource we may want to consider is audio - which can be used for music and sound effects. Audio is created much like our images are:

var sound = new Audio(); sound.url = 'somesound.wav';

This creates the sound as a HTMLAudioElement, the same class underlying an audio tag in the DOM, i.e. <audio src="somesound.wav"></audio>. The source of an audio element is typically a wav, mp3, or ogg file. Different browsers may support other formats.

Audio elements also have helpful functions for playing and pausing, i.e.; sound.pause();

One final note - if you call more than once, especially if you do it every pass through your game loop, the multiple playings will blend together into one horrible sound. You probably don't want to do this.


One good way to generate sounds for games is the BFXR tool, available at This tool generates random sounds and allows you to tweak the characteristics of that sound with lots of sliders, as seen below: