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:

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

  1. Hello, it is a good extension, but is it possible to center the loading image? What I am trying to do is to put only an animated gif ( without a bar), but there is a problem. I use your other extension – HDPI support (btw. it’s great and you should be proud of it) and unfortunately, those two extensions aren’t compatible. The loading bar or image is not centered on the screen :( Any idea how to fix this bug?

  2. Hi,

    What does line 4 do exactly? What is it checking for? Is it only checking if the given function exists, and that’s it?

    Thanks

    • Indeed – it verifies that your project contains a “gmcallback_imgloadbar” script before calling it.

  3. “Scripts prefixed with gmcallback_ are not obfuscated when compiling to HTML5.” Wow. That’s a feature they could have done with documenting better, on the page about writing javascript extensions for example! I never thought I had any reason to look at ‘clickable_add’ – who would have thought that was the only page of the manual to document a vital GameMaker feature that isn’t exclusively relevant to that function?

  4. Pingback: A summary of my GameMaker assets

  5. 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.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.