Resource Manager

This was a class which I realised I needed pretty soon into development. All of the assets (graphics, sounds, level text files) needed to be totally loaded before I tried to access them programmatically, or it would invoke error’s! So I wrote this class, which you call load a bunch of times with all your required files url’s, and it would work down the list starting a download of each asset, and track the loadComplete events to report back to the game once everything was completed.

The core of it is simply 3 arrays, all of which are linked. For each item you add to the load stack, an element is added to each array, one holds the url, another the handle (a string identifier you can later use to reference the asset) and the actual HTMLElement which contains the data.

To add elements to the load stack, there are three seperate Add methods, one for Image, Sound and Text- this is because the method for loading, and detected completion of the loading varies between the three.

AddImage
This simply creates a new HTML Image element, and hooks completion onto the .onload event of the image

AddSound
This creates an HTML5 Audio element, and hooks into the ‘canplaythrough’ event, which indicates the sound is loaded enough to be used safely.

AddText
This uses the jQuery ajax method, and hooks into the success method to indicate loading complete.

When a new resource is added, the loadcount is incremented, and upon completion of each load it’s decremented again. The calling script just needs to wait until the load count reaches 0 to know everything is loaded and ready.

Once everything is loaded, you can pull the loaded instances of the assets from the resource manager used GetObject() or GetObjectByHandle().

The Source

/*!
* Generic Game Resource Loader and Manager Class
* http://8weekgame.shawson.co.uk/
*
* Copyright 2010, Shaw Young
* Released under the MIT, BSD and GPL Licenses.
* http://www.opensource.org/licenses/bsd-license.php
* http://www.opensource.org/licenses/mit-license.php
* http://www.opensource.org/licenses/gpl-2.0.php
*
* Date: Mon Jul 17 17:00:00 2010 
*/

function ResourceLoader() {
    this.loadcount = 0;
    this.objects = new Array();
    this.urls = new Array();
	this.handles = new Array();
}
ResourceLoader.prototype.AddImage = function (url, handle) {
    this.loadcount++;
    var i = this.objects.length;
    this.urls[i] = url;
	this.handles[i] = '' + handle;

    loader = this;
    
    this.objects[i] = new Image();
    this.objects[i].onload = function () {
        loader.loadcount--;
    }
    this.objects[i].src = url;
}
ResourceLoader.prototype.AddSound = function (url, handle) {
    this.loadcount++;
    var i = this.objects.length;
    this.urls[i] = url;
	this.handles[i] = '' + handle;

    loader = this;
	
	// http://www.whatwg.org/specs/web-apps/current-work/#mediaevents
	// http://api.jquery.com/bind/
	
	this.objects[i] = new Audio();
	$(this.objects[i]).bind('canplaythrough', function() { // totally loaded

	  loader.loadcount--;
	});

	this.objects[i].src = url;
	this.objects[i].load();	
}
ResourceLoader.prototype.AddText = function (url, handle) {
    this.loadcount++;
    var i = this.objects.length;
    this.urls[i] = url;
	this.handles[i] = '' + handle;

    loader = this;
    this.objects[i] = url;
    $.ajax({
        url: url,
        success: function (data, textStatus, XMLHttpRequest) {
            loader.SetObject(this.url, data);
            loader.loadcount--;
        },
        async: true,
        type: 'GET'
    });
}
ResourceLoader.prototype.FindObject = function (url) {
    //find the index in the url's array
    for (var i = 0; i < this.urls.length; i++)
        if (this.urls[i] == url)
            return i;

    return -1;

}
ResourceLoader.prototype.FindObjectByHandle = function (handle) {
    //find the index in the url's array
    for (var i = 0; i < this.handles.length; i++)
        if (this.handles[i] == handle)
            return i;

    return -1;

}
ResourceLoader.prototype.GetObject = function (url) {
    var index = this.FindObject(url);

    if (index > -1)
        return this.objects[index];

    alert(url + ' not loaded');
    return null;
}
ResourceLoader.prototype.GetObjectByHandle = function (handle) {
    var index = this.FindObjectByHandle(handle);

    if (index > -1)
        return this.objects[index];

    alert(handle + ' not found');
    return null;
}
ResourceLoader.prototype.SetObject = function (url, o) {
    var index = this.FindObject(url);

    if (index > -1) {
        this.objects[index] = o;
        return true;
    }

    return false;
}

Improvements

I would like to add an event to be raised on load complete of all assets which scripts could hook into, and another to indicate when each individual item is downloaded (for progress bars). Looking back on this, while I’m pleased with the way assets are loaded, the mechanism for checking if everything is loaded and ready is a bit crewd (I basically check the load count is > 0, if it is a setTimeout to try the check again in a second!).

  1. No comments yet.
(will not be published)