No Time To Play

Image preloader in HTML5

by on Oct.30, 2010, under Gamedev

Vector graphics are convenient in games, especially for a programmer with little artistic skill such as myself. But there is only so much you can do with them. Sooner or later, you’re going to need raster images, and those have an interesting characteristic: being external to the code, they have to be loaded explicitly; we call them assets.

Now, in the general case, that’s not an issue; you simply load the assets before starting the game. But web browsers load images asynchronously. And so it happens that the tech demo for Ballistic: Snowballz was only displaying a blank background on first page load.

The solution was obvious: write a preloader.

The loader proper turned out to be easy to write. Worked out of the box, too. No, I can’t believe it either, but it did. Then again, we’re talking 24 lines of code:

var Utils = {};
Utils.ImgLoader = function () {
    this.onprogress = function () {};
    this.oncompletion = function (media) {};

    this.loaded = this.total = 0;

    this.load = function (media) {
        var loader = this;
        for (i in media) {
            if (typeof media[i] != "string") continue;
            this.total++;
            var fn = media[i];
            media[i] = new Image();
            media[i].src = fn;
            media[i].onload = function () {
                loader.loaded++;
                loader.onprogress();
                if (loader.loaded == loader.total)
                    loader.oncompletion(media);
            }
        }
    }
}

Using it turned out to be a little trickier, but worked in the end.

Snowballz.GameScreen = function (model, context, width, height) {

    // ... snip ...


    this.pine_tree = this.snowman = new Image(); // Placeholder object.
    this.loader = null;

    this.load_media = function() {
        var scr = this;
        this.loader = new Utils.ImgLoader();
        this.loader.onprogress = function () {
            if (scr.game_paused) scr.render();
        }
        this.loader.oncompletion = function (media) {
            scr.pine_tree = media.pine_tree;
            scr.snowman = media.snowman;
            scr.loader = null;
            if (scr.game_paused) scr.render();
        }
        this.loader.load({
            snowman: "assets/plastic-snowman.png",
            pine_tree: "assets/plastic-pine-tree.png",
        });
    }

    // ... snip ...
}

Then there is the code that calls load_media() before the game starts, the code that shows progress, and the code that makes sure the media is loaded before trying to use it. This last part is important if you’re going to use the images on a canvas element, like I do: canvases, being native components, don’t check their arguments nearly as thoroughly as you might be used to.

Come to think of it, an even better approach would be to not even instantiate the gamescreen object until all the media is loaded, but I didn’t want to make too many changes; this is only a prototype after all. I’ll do it right the first time around for the next game.

Creative Commons License
Image preloader in HTML5 by Felix Pleșoianu is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.

:, , ,

Comments are closed.

Posts by date

October 2010
M T W T F S S
« Sep   Nov »
 123
45678910
11121314151617
18192021222324
25262728293031

Posts by month