Booty5 HTML5 Game Engine Update out – Facebook Instant Games Support Added

It’s been a long long while since I put an update to Booty5 out so I thought it time. I have been playing around with Facebook Instant Games over the last few months so I added support for Facebook Instant Games to the Booty5 engine. You will find a new utility class called Instants that wraps up the Facebook Instants SDK. This has been tightly integrated into the loader for the Booty5 game editor. I will be releasing the updated version of the Booty5 editor with direct Facebook Instant Games export support very soon. Along with that I will be releasing the source to some of my games to help developers learn how to use the new features more easily. The complete list of Booty5 engine changes (v1.5.5) include:

  • New hit property added to Actors. If true then will be included in hit testing
  • New dock_screen property added to Actors. If true then docking will be to screen edge instead of scene edge
  • New padding property added to Actors. Text padding (used when caching)
  • New scale_method property added to Actors. Scale method used to fit actor to screen
  • New draw_reverse property added to Actors. If set to true children are drawn in reverse order
  • New _av property added to Actors. This will set active and visible states at the same time
  • New method removeAllActors added to Actor which removes all actors from the actors child list
  • New getSlot and moveToSlot methods added to Actor which allows you to query a child sort index and modify it
  • New overlapsRect method added to Actors which checks for a rect area overlapping the Actors rect area
  • New circleOverlaps method added to Actors which checks for a circular area overlapping the Actors circular area
  • New circleOverlapsRect method added to Actors which checks for a rect area overlapping the Actors circular area
  • New fullCircleOverlapTest method added to Actors which checks for a circular area overlapping the Actors circular area (taking into account transforms)
  • New stroke_filled property added to all Actor types which if true will cause stroke will be drawn
  • New line_height property added to LabelActor which specifies the height of a line of text
  • New _text property added to LabelActor which sets the labels text and updates its cached version if cached
  • New deactivate property added to Animations. When set to true deactivates and hides target actor when its done (default false), should only be used with actors
  • Many new easinng funnctions added to the animation system
  • App canvas_width and canvas_height now known as design_width and design_width
  • Fonts now added to the app as resources, the underlying font loaded uses the FontObserver lib to load fonts
  • Raw JSON resource type now added to the App
  • New started property added to the App which is a callback that will be called when the app starts
  • All App resource containers are now objecsts instead of arrays
  • App waitForResources now calls a supplied callback to alert the user of progress during loading
  • App main logic loop is now ran on requestAnimationFrame
  • New draw_reverse property added to Scenes. If set to true children are drawn in reverse order
  • New _av property added to Scenes. This will set active and visible states at the same time
  • Added new Task type called TaskQ which is a collection of tasks that are ran serial. Only the first task in the queue is ran, once that tasks is complete the next task in the queue is ran.
  • Resources now checked for load failure and attempt to reload a number of times before giving up
  • Value passed to Actor _atlas can be an atlas object or the name of an image atlas brush
  • Calling playAnim or playTimeline on an inactive or invisible Actor will make activate it and make it visible
  • Hit tests are no longer carried out on inactive Actors
  • Fixed Actor _scale property so that it now updates the main transform
  • Fixed virtual Actor margins
  • Action lists are now optional component and not included by default
  • Support for Facebook Instant Games added

Please note that this version of Booty5 may not be completely compatible with your existing code so back up before trying it!

The complete source to Booty5 is available on Github here.

Simple Web Audio Wrapper

Seen this question asked numerous times, how to set up and use the Web Audio API, so I ripped some code out of my engine Booty5 and slimmed it down a bit and here it is, I have also pushed it to Github here.

/**
 * A Sound represents a sound effect object and can be used to play back audio
 *
 * Generally a sound should be added to either a {@link b5.Scene} or the global {@link b5.App}'s resources so that it can be managed by them.
 *
 * Example showing how to load and play a sound effect
 *
 *      var sound = new b5.Sound("explosion", "sounds/explosion.mp3", true);
 *      var instance = sound.play();
 *
 * For a complete overview of Resources see {@link http://booty5.com/html5-game-engine/booty5-html5-game-engine-introduction/resources-the-stuff-that-games-are-made-of/ Booty5 Resources Overview}
 *
 * @class b5.Sound
 * @constructor
 * @returns {b5.Sound}                      The created sound
 * @param name {string}                     Name of sound resource
 * @param location {string}                 The sound file location
 *
 * @property {b5.App|b5.Scene}          parent          - Parent resource manager (internal)
 * @property {object}                   snd             - Sound instance (re-usable sound only) (internal). For Web Audio stores a {source:AudioBufferSourceNode, gain:GainNode} object for auto play sounds
 * @property {object}                   buffer          - AudioBufferSourceNode containing decoded audio data (Web Audio only)
 * @property {string}                   name            - Name of this sound resource
 * @property {string}                   location        - The location of the sound file that is used to create the audio object
 * @property {boolean}                  loop            - If set to true then sound will be looped
 * @property {boolean}                  preload         - If set to true then this sound will be preloaded
 * @property {boolean}                  auto_play         - If set to true then this sound will be preloaded
 * @property {boolean}                  loaded          - If true then this resource has finished loading
 */

var loadFile = function(filename, blocking, callback, binary)
{
    var req = new XMLHttpRequest();
    req.open("GET", filename, !blocking);
    req.overrideMimeType("application/json");
    if (binary)
        req.responseType = "arraybuffer";
    if (!blocking)
    {
        req.onreadystatechange = function()
        {
            if (req.readyState === 4)
            {
                if (req.status === 200 || req.status === 0) // 0 for node-webkit
                {
                    if (binary)
                        callback(req.response);
                    else
                        callback(req.responseText);
                }
                else
                    callback(null);
            }
        };
    }
    try
    {
        req.send();
    }
    catch(e)
    {
        return false;
    }

    if (blocking)
    {
        if (req.status === 200)
        {
            if (binary)
                callback(req.response);
            else
                callback(req.responseText);
        }
        else
            callback(null);
    }

    return true;
};

b5.Sound = function(name, location)
{
    // internal variables
    this.parent = null;                 // Parent container
    this.snd = null;                    // Sound instance (re-usable sound only). For Web Audio stores a {AudioBufferSourceNode, GainNode } object for auto play sounds
    this.buffer = null;                 // AudioBufferSourceNode containing decoded audio data (Web Audio only)

    // Public variables
    this.name = name;					// The sound name
    this.location = location;			// Location of the sound
    this.loop = false;                  // If set to true the this sound will replay continuously
    this.preload = false;               // Set to true to preload sound
    this.loaded = false;                // Set to true once audio cam be played
    this.auto_play = false;             // Set to true to auto play sound when loaded
    this.load_retry = 0;
};

/**
 * AudioContext used by Web Audio API
 * @type {object}
 */
b5.Sound.context = null;
b5.Sound.muted = false;

/**
 * Initialises the sound system
 * @parm app {b5.App}   The App that will manage the audio engine
 * @returns {boolean}   true for success or false if error
 */
b5.Sound.init = function(app)
{
    if (app.use_web_audio)
    {
        try
        {
            window.AudioContext = window.AudioContext || window.webkitAudioContext;
            if (window.AudioContext === undefined)
                return false;
            b5.Sound.context = new AudioContext();
        }
        catch(e)
        {
            return false;
        }
        return true;
    }
    return false;
};

/**
 * Loads the sound
 */
b5.Sound.prototype.load = function(force)
{
    var debug = b5.app.debug;
    //var snd;
    var that = this;
    var filename = this.location;
    var auto_play = this.auto_play;
    if (!loadFile(filename, false, function(data) {
        if (data !== null)
        {
            b5.Sound.context.decodeAudioData(data, function(buffer) {
                that.buffer = buffer;
                if (auto_play)
                    that.play(force);
            }, function(e)
            {
                console.log(e)
            });
        }
        else
        {
            that.load_retry++;
            if (that.load_retry < 3)
                that.load();
        }
    }, true))
    {
        that.load_retry++;
        if (that.load_retry < 3)
            that.load();
    }
};

/**
 * Starts playback of the sound
 * @returns {object} An Audio object representing the playing sound or a {source, gain} object if using Web Audio API
 */
b5.Sound.prototype.play = function(force)
{
    if (force != true && b5.Sound.muted)
        return null;
    if (this.buffer === null)
        return null;
    var context = b5.Sound.context;
    var source = context.createBufferSource();
    var gain = context.createGain();
    source.buffer = this.buffer;
    source.loop = this.loop;
    source.connect(gain);
    gain.connect(context.destination);
    gain.gain.value = 1;
    source.start(0);
    if (this.auto_play)
        this.snd = { source: source, gain: gain };
    return { source: source, gain: gain };
};

/**
 * Stops playback of thr sound (re-usable sound only)
 */
b5.Sound.prototype.stop = function()
{
    var snd = this.snd;
    if (snd === null || snd === undefined)
        return;
    snd = snd.source;
    snd.stop();
};

Happy coding!

Simple Messaging System with Redis and Node.js

Hey all, been a while since I posted anything constructive, I’ve been so busy wasting my time creating games for Facebook Instant Games Messenger (I will do a proper write up with my analysis and final findings / thoughts on this very soon). Not all has been lost working on Instant Games however. Two of my games required an instant messaging system that enables me to send real-time messages between players which ironically the Instant Games SDK doesn’t cater for. So I created one using Node.js and Redis (these two bad boy pieces of tech together are like sweet music). You can grab the code from Github here.

Note that you will need to install this to your own server, I like to run most of my node modules using PM2. So to get the messaging system up and running just run pm2 msys. The server looks to the /msys endpoint, but you can change this in msys.js if you need it to go elsewhere. No, I don’t answer questions on how to set up servers and mess with Apache config files because I hate all that junk, it gets in the way of my actual coding which I do enjoy :) . If you cannot do this stuff yourself then you probably should be paying someone else do this for you.

Oh word of warning, any messages sent will time out after 7 days (this is to keep Redis memory usage down), but you can extend this to whatever time limit you like. Messages are queued, when you collect the pending messages it collects them all and deletes them from the database.

Ok, how to use client side? Here is a simple class (erm I mean collection of functions) with an awesome original name that I ripped out of one of my games for you guys to use:

var Backend = {};

Backend.SendMessage = function(data, done_callback)
{
    var url = "https://yourdomain.com/msys?c=s&t=<your token>";
    url += "&g=1";
    url += "&u=" + data.to_id;
    url += "&d=" + encodeURIComponent(JSON.stringify(data));
    b5.Utils.SendGetRequest(url, function(response) {
        if (done_callback !== undefined)
            done_callback(response);
    })
}

Backend.SendMessageMulti = function(recipients, data, done_callback)
{
    var users = "";
    var len = recipients.length;
    for (var t = 0; t < len; t++)
    {
        users += recipients[t];
        if (t < (len - 1))
            users += "_";
    }
    var url = "https://yourdomain.com/msys?c=s&t=<your token>";
    url += "&g=1";
    url += "&m=" + users;
    url += "&d=" + encodeURIComponent(JSON.stringify(data));
    b5.Utils.SendGetRequest(url, function(response) {
        if (done_callback !== undefined)
            done_callback(response);
    })
}

Backend.GetMessages = function(done_callback)
{
    var url = "https://yourdomain.com/msys?c=g&t=<your token>";
    url += "&g=1";
    url += "&u=" + Social.GetPlayerID();
    b5.Utils.SendGetRequest(url, function(response) {
        if (response.status == 200)
        {
            var data = decodeURIComponent(response.responseText);
            var obj = JSON.parse("[" + data + "]");

            if (done_callback !== undefined)
                done_callback(obj);
        }
        else
        {
            if (done_callback !== undefined)
                done_callback();
        }
    })
}

There are a few functions in here that you will need to implement yourself:

  • Social.GetPlayerID() – Replaced with your players user ID, if you are using Facebook Instants SDK then use FBInstant.player.getID()
  • b5.Utils.SendGetRequest() – Performs a GET request, e.g:
b5.Utils.SendGetRequest = function(url, callback)
{
    var req = new XMLHttpRequest();
    req.onreadystatechange = function()
    {
        if (callback != undefined && req.readyState == 4)
            callback(req);
    }
    req.open("GET", url, true);
    req.send();
}

Anyway, that’s it, hope you find more useful than I did. Happy coding :) .

Installing Redis to Windows / Linux

I recently began adding support for a global leaderboard system to my latest Unity game and decided that instead of the huge overhead related to going the RDBMS SQL route that i would have a crack at implementing back-end storage using a NoSQL database instead, which whilst much faster than traditional RDBMS is much more restrictive in terms of query. In fact Redis is for all intents and purposes almost impossible to query in any kind of depth. That said, I am not particularly interested in its relational query features but more in its ability to store and run basic queries on data very quickly, which Redis does extremely well.

Note that I am writing this article with a view to using Redis from Node.js, I will cover using Redis from .NET Core in a later article. If you missed my article on installing node.js then look here.

What is Redis

Redis is a fast in memory key/value store that can be used like a database. It differs aainly to SQL in that complex queries cannot be ran on the data, but if you do not need to carry out complex queries on the data (for example a persistent game world map or a leaderboard) then something like redis is ideal for storing the data.

Installing Redis

Windows

For Windows download the MSI release from here then install it. Redis will be installed as a service. You can take a look in Task Manager to ensure that Redis is running. To confirm the install open up command prompt and run Redis command line interface redis-cli.

Linux

Installing redis on Linux is not so easy because you need to build the latest stable release, firstly lets get the tools you are going to need to build Redis:


sudo apt-get update
sudo apt-get install build-essential
sudo apt-get install tcl8.5

Download and untar the latest stable build:


wget http://download.redis.io/releases/redis-stable.tar.gz
tar xzf redis-stable.tar.gz

Now lets build Redis:


cd redis-stable
make
make test
sudo make install

Run Redis as a background daemon (a script has been provided to do this), note that you will be asked to set some options, just choose the defaults for the moment:


cd utils
sudo ./install_server.sh

The above script creates a script in etc\init.d called redis_6379 (the numbers represent the port that you selected during install).

To get Redis to run automatically on boot:


sudo update-rc.d redis_6379 defaults

Installing Redis client library for Node.js

This is actually very simple, run the following:


npm install redis

We can now reference Redis from Node.js by importing Redis in our Node.js code:


var redis = require("redis");

Testing Redis with Node.js

Create a new file called redis_test.js and add the following code:


var redis = require("redis");

// Create the redis client
var client = redis.createClient();
client.on("error", function (err)
{
console.log("Redis error: " + err);
});

// Try out a simple command
client.set("my_key", "some value");

For more information on Redis see the Redis website

The all new IndieDeveloper a social community for game developers

Do you love to make games?  Are you passionate about making games?  Do you want to find other developers just like yourself?  Well, I recently came across a new social community and resource for developers of all professional skill levels. You can join a community of independent game developers and find a collaborator, a team, a project, or just a new friend. Well what are you waiting for, see you over at IndieDeveloper, If you want to friend me, I’m user mrmop,.

 

Booty5 HTML5 Game Maker 1.9.2b out now – Web Audio API Support Added

Support for the Web Audio API has been added offering better control over audio playback. Using it is s simple case of ticking support for it in the projects properties (on by default).

Full list of changes include:

Game Editor v1.9.2b:

  • Added new use web audio export option to project settings
  • Added new auto play property to sounds which cause sound to automatically start playing once loaded
  • Added new export option force_round which will force all exported actors to use pixel rounding
  • Fix: Project property smoothing is now applied in exported code
  • Fix: Canvas centering on some mobile devices

Game Engine v1.4.8 and 1.4.9:

  • b5.Xoml.loadJSON now accepts 4th parameter which can be used to stipulate loaded data should be returned as binary buffer
  • b5.App.use_web_audio property added which can be used to switch on support for Web Audio if it is supported
  • b5.Xoml.loadJSON moved to b5.Utils.loadJSON
  • b5.Xoml.loadJS moved to b5.Utils.loadJS
  • Added support for web audio API to sound (default is enabled). To disable Web Audio set b5.App.use_web_audio to false. If web audio is not supported then it will fallback to HTML5 Audio
  • b5.App constructor now accepts a second parameter which enables / disables web audio support
  • Added b5.Sound.auto_play property to enable auto playback of sounds after they are loaded
  • JSDoc documentation added
  • b5.App.canvas_fill_window removed
  • Modified how the render scaling and canvas resizing works to make it easier to use.

Download the latest version of Booty5 HTML5 Gama Maker.

Booty5 HTML5 Game Maker 1.9.1b Available – Text preview and collision flags

Booty5 the HTML5 Game Maker v1.9.1b is now available for free download.

Editor Changes:

  • Scale and angle are now affected in multiple actor selections
  • Editor export properties now supports smoothing property that will enable / disable anti-aliasing during rendering
  • Added support for rounding pixels to actors, if disabled then pixel coordinates will be rounded to integer values, can improve performance but at a cost of lower precision rendering
  • Removed some currently unused options from sprite and label
  • Font size and face separated in labels
  • Font weight added to label
  • Editor now shows text preview
  • Exported collision flags are now used by engine
  • Added vertices snap to shape editor
  • Added new Collision Flags example
  • Fix: Convex shapes were not exporting correctly
  • Fix: Some properties such as actor scale were not exporting correctly with an export precision of 0

Engine Changes:

  • Added new property to Actor called round_pixels, when set to true vertices will be rounded to integer which can speed up rendering significantly
  • Added support for collision flags to physics fixtures (category, mask and group index)

The Booty5 HTML5 game manual ebook has also been updated.

Booty5 HTML5 Game Maker 1.9 Available – Tiled Maps

Booty5 the HTML5 Game Maker v1.9.0b is now available for free download. Support for tile map rendering has been added to the engine, whilst support for tile map editing has been added to the game maker. A quick screen shot of the new tile map editor is shown below:

Booty5 HTML5 tile map editorBooty5 HTML5 tile map editor

Full list of changes include:

Game Engine v1.4.6:

  • Added new actor type called MapActor which can render tiled maps
  • Support added to Xoml for loading Booty5 game editor exported tile maps
  • Fix: Actor.vr wasn’t updating transform

Game Editor v1.9.0b:

  • Added support for tile maps (any sprite actor can now be changed to a tile map by changing RenderAs type to Tile Map)
  • Added pretty print export options that will export JSON in a tidy readable format

The Booty5 HTML5 game manual ebook has also been updated.

You will also need to replace all examples which can be downloaded from Github.

Free Booty5 HTML5 Game Maker Manual e-book now available

The first version of the Booty5 HTML5 Game Maker Manual e-book is now available for free download. Find out more on the Booty5 free e-book page.