GameMaker: Loading bar + animated image in HTML5


Mouseover to view animation (note: mild color cycling)

A year and some ago, I published an extension that allows to use custom logos for HTML5 games made with GameMaker: Studio. Since some functionality has been added since then, I made an updated version with more options.

Setting up

The process of setting up the extension is much as with the original (see linked post), but with a few changes:

First, the extension' JS code is expanded a little,

var inst = { };
function ImageLoadBar_hook(ctx, width, height, total, current, image) {
    function getv(s) {
        if (window.gml_Script_gmcallback_imgloadbar) {
            return window.gml_Script_gmcallback_imgloadbar(inst, null,
                s, current, total,
                width, height, image ? image.width : 0, image ? image.height : 0)
        } else return undefined;
    }
    function getf(s, d) {
        var r = getv(s);
        return typeof(r) == "number" ? r : d;
    }
    function getw(s, d) {
        var r = getv(s);
        return r && r.constructor == Array ? r : d;
    }
    function getc(s, d) {
        var r = getv(s);
        if (typeof(r) == "number") {
            r = r.toString(16);
            while (r.length < 6) r = "0" + r;
            return "#" + r;
        } else if (typeof(r) == "string") {
            return r;
        } else return d;
    }
    // get parameters:
    var backgroundColor = getc("background_color", "#FFFFFF");
    var barBackgroundColor = getc("bar_background_color", "#FFFFFF");
    var barForegroundColor = getc("bar_foreground_color", "#242238");
    var barBorderColor = getc("bar_border_color", "#242238");
    var barWidth = getf("bar_width", Math.round(width * 0.6));
    var barHeight = getf("bar_height", 20);
    var barBorderWidth = getf("bar_border_width", 2);
    var barOffset = getf("bar_offset", 10);
    // background:
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, width, height);
    // image:
    var totalHeight, barTop;
    if (image != null) {
        var rect = getw("image_rect");
        if (!rect) rect = [0, 0, image.width, image.height];
        totalHeight = rect[3] + barOffset + barHeight;
        var image_y = (height - totalHeight) >> 1;
        ctx.drawImage(image, rect[0], rect[1], rect[2], rect[3],
            (width - rect[2]) >> 1, image_y, rect[2], rect[3]);
        barTop = image_y + rect[3] + barOffset;
    } else barTop = (height - barHeight) >> 1;
    // bar border:
    var barLeft = (width - barWidth) >> 1;
    ctx.fillStyle = barBorderColor;
    ctx.fillRect(barLeft, barTop, barWidth, barHeight);
    //
    var barInnerLeft = barLeft + barBorderWidth;
    var barInnerTop = barTop + barBorderWidth;
    var barInnerWidth = barWidth - barBorderWidth * 2;
    var barInnerHeight = barHeight - barBorderWidth * 2;
    // bar background:
    ctx.fillStyle = barBackgroundColor;
    ctx.fillRect(barInnerLeft, barInnerTop, barInnerWidth, barInnerHeight);
    // bar foreground:
    var barLoadedWidth = Math.round(barInnerWidth * current / total);
    ctx.fillStyle = barForegroundColor;
    ctx.fillRect(barInnerLeft, barInnerTop, barLoadedWidth, barInnerHeight);
}

The interesting part here is window.gml_Script_gmcallback_imgloadbar,

Scripts prefixed with gmcallback_ are not obfuscated when compiling to HTML5.
This is originally intended for use with clickable_add function, but is also handy for any other situations where you want a particular script exposed, including this one.

And, since the game' code is fully loaded before the loading bar extension fires, this allows to execute non-game-specific GML code before the game even starts.

So, the next step would be to define a gmcallback_imgloadbar script that would contain something like the following:

/// gmcallback_imgloadbar(context, current, total, width, height, img_width, img_height)
var r;
var pc = argument1; // progress current
var pt = argument2; // progress total
var cw = argument3; // canvas width
var ch = argument4; // canvas height
var iw = argument5; // image width
var ih = argument6; // image height
switch (argument0) {
    case "image_rect": // ([left, top, width, height] in pixels)
        r[0] = (current_time div 500) mod 4 * (iw div 4);
        r[1] = 0;
        r[2] = iw div 4;
        r[3] = ih;
        return r;
    case "background_color": return c_white;
    case "bar_background_color": return c_white;
    case "bar_foreground_color": return $242238;
    case "bar_border_color": return $242238;
    case "bar_width": return round(cw * 0.6); // (px)
    case "bar_height": return 20; // (px)
    case "bar_border_width": return 2; // (px)
    case "bar_offset": return 10; // (px from image)
}
return undefined;

The script receives the name of requested parameter as the first argument, and returns the value for it. This allows to both configure parameters without editing the extension, and to have them change dynamically.

Here, as an example, the image' sub-coordinates are adjusted based on current_time, as result animating the loading screen' logo at rate of 2 frames/second if you've imported a 4-frame strip for it.

Pre-assembled example and extension are available for download via itch.io:

Download

Alternatively, mirrors for both the extension and the example are hosted on this site too.

Have fun!

Related posts:

2 thoughts on “GameMaker: Loading bar + animated image in HTML5

  1. Awesome extension, man, thank you very much for the time you spent working on it and for share it for free. You should publish it into YoYo’s marketplace.

  2. Pingback: A summary of my GameMaker assets

Leave a Reply

Your email address will not be published. Required fields are marked *