Analyzing the building blocks of a friGame based game

In the previous installment of the technical series, we looked at the various technologies needed to make a game based on friGame, and the 3 major blocks that compose friGame itself; now let's take a look at the details of these blocks by analyzing the arkanoid demo bundled with friGame.

Let's start with some boilerplate code:

(function ($, fg) {
    'use strict';

    $(function () {
        // All the code will go here
    });
}(jQuery, friGame));

Nothing fancy here, just the jQuery object is aliased to the variable named $ and the friGame object is aliased to the variable named fg.

The $(function () { part means that we wait for the DOM Ready event. This has also the advantage of guaranteeing that all the JavaScript files have been loaded, and all the DOM nodes required for initializing the game have been created.

If you remember from the previous post, we have 3 steps required for making a game, and 3 building blocks of friGame.

So now, after the DOM Ready event has been fired, let's do step 1: load some resources using the resource manager:

fg.resourceManager
    .addGradient('top_gradient', {r: 127, g: 191, b: 255})
    .addGradient('middle_gradient', {r: 127, g: 191, b: 255}, {r: 191, g: 255, b: 255})
    .addGradient('bottom_gradient', {r: 191, g: 255, b: 255}, {r: 63, g: 255, b: 95})
    .addAnimation('blue_brick', 'bricks.png', {type: fg.ANIMATION_VERTICAL, offsety: 0 * G.BRICK_HEIGHT, frameWidth: G.BRICK_WIDTH, frameHeight: G.BRICK_HEIGHT})
    .addAnimation('green_brick', 'bricks.png', {type: fg.ANIMATION_VERTICAL, offsety: 1 * G.BRICK_HEIGHT, frameWidth: G.BRICK_WIDTH, frameHeight: G.BRICK_HEIGHT})
    .addAnimation('brick', 'bricks.png', {type: fg.ANIMATION_VERTICAL, offsety: 2 * G.BRICK_HEIGHT, frameWidth: G.BRICK_WIDTH, frameHeight: G.BRICK_HEIGHT})
    .addAnimation('red_brick', 'bricks.png', {type: fg.ANIMATION_VERTICAL, offsety: 3 * G.BRICK_HEIGHT, frameWidth: G.BRICK_WIDTH, frameHeight: G.BRICK_HEIGHT})
    .addAnimation('ball', 'ball_large.png')
    .addAnimation('paddle', 'paddle_middle.png')
;

This does not yet start loading all the resources from the network. Such process must be started manually by calling the startGame function like this:

fg.startGame(function () {
    // Here all the resources have been successfully loaded
});

There are a few things to note here:

First of all, all the resources handled by the resource manager go in the friGame.resources namespace (shortened in fg.r), so for example we will have

friGame.resources.blue_brick

or

fg.r.blue_brick

and so on, as usable objects, once the resources have succesfully been loaded.

Another important thing to note is that on mobile devices the sounds will load only if triggered by user interaction, so the startGame function has to be called inside a click event handler, or similar.

Once everything has been loaded, it is time to do step 2: set up the scene by populating the playground:

fg.playground()
    .addGroup('top_background', {background: 'top_gradient', left: 0, top: (0 * fg.s.playground.height) / 3, width: fg.s.playground.width, height: fg.s.playground.height / 3}).end()
    .addGroup('middle_background', {background: 'middle_gradient', left: 0, top: (1 * fg.s.playground.height) / 3, width: fg.s.playground.width, height: fg.s.playground.height / 3}).end()
    .addGroup('bottom_background', {background: 'bottom_gradient', left: 0, top: (2 * fg.s.playground.height) / 3, width: fg.s.playground.width, height: fg.s.playground.height / 3}).end()
;

// Some more code skipped for simplicity

fg.s.playground
    .addSprite('paddle', {animation: 'paddle', centerx: fg.s.playground.centerx, bottom: fg.s.playground.bottom - fg.r.paddle.height})
    .addSprite('ball', {animation: 'ball', centerx: fg.s.paddle.centerx, bottom: fg.s.paddle.top})
;

The first important thing to notice here is that the playground() function must be called first, in order to correctly initialize the playground.

After that, the playground can be accessed as any other sprite in the friGame.sprites namespace (shortened in fg.s).

Notice that the sprites are immediately accessible and usable after the return of the addSprite and addGroup functions.

Also, this is a simple game, so it is not used here, but sprites can be added inside any sprite group, not only inside the playground.

Finally, once the scene has been populated, it is time to do step 3: the game loop (callbacks) and input handling:

$(document).mousemove(function (e) {
    // Handling of mouse movement
    // (this can be done automatically by the mouse tracker plugin)
    var
        offset = $('#playground').offset()
    ;

    fg.mouseTracker.x = e.pageX - offset.left;
    fg.mouseTracker.y = e.pageY - offset.top;
});

fg.s.paddle.registerCallback(function () {
    this.move({centerx: fg.clamp(fg.mouseTracker.x, this.halfWidth, fg.s.playground.width - this.halfWidth)});

    // More game logic here
}, G.REFRESH_RATE);

fg.s.ball.registerCallback(function () {
    this.move({centerx: this.centerx + this.userData.speed_x, centery: this.centery + this.userData.speed_y});

    // More game logic here
}, G.REFRESH_RATE);

Notice that the input handling is done by jQuery, and the playground DOM offset is used in order to have the mouse position relative to the playground, and not to the document.

Notice also that any sprite can have as many callback function as it needs, it is not limited to 1, but if performance is a concern, it is also possible to build all the game logic inside a single callback function, and register it to the playground.

That's all as far as the basics of friGame are concerned, if you want to build a game you should have no problems now, check out also the reference documentation on the friGame website; but this does not end the series of technical posts, stay tuned for the next episode.

Comments !