Animation and events

Use spritesheet animations and their events

With WADE, adding animation to your sprites is extremely easy. To demonstrate this, we're going to start a new App, deleting what we have in test.js at the moment. Alternatively, you could create a different app file, and reference it from your index.html.

Instead of loading clubs.png, we'll now load a file called 'symbols.png' (download it here), and we'll create a sprite and a scene object for it.

    App = function()
    {
        this.load = function()
        {
            wade.loadImage('data/symbols.png');
        };

        this.init = function()
        {
            // create a sprite
            var sprite = new Sprite('data/symbols.png');
            this.symbolObject = new SceneObject(sprite);
            wade.addSceneObject(this.symbolObject);
        };
    };

 

As you can see, it's a sprite that contains 4 images that are equally spaced. In fact it's called a sprite sheet. We can easily create animations out of sprite sheets:

 

    this.init = function()
    {
        // create a sprite
        var sprite = new Sprite();
        sprite.setSize(80, 80)
        var animation = new Animation('data/symbols.png', 4, 1, 1.5);
        sprite.addAnimation('test animation', animation);
        this.symbolObject = new SceneObject(sprite);
        wade.addSceneObject(this.symbolObject);
        sprite.playAnimation('test animation');
    };

Instead of creating a sprite from an image, we create a sprite with no parameters. We then set its size, and proceed to create an Animation object. We are passing a few arguments to the Animation constructor: first of all, the image to use. Then, the number of horizontal cells in that image (4), the number of vertical cells (1), and an animation speed (1.5 frames per second).

At line 7 we are adding the animation to the sprite object (giving it a name), and at line 10 we're telling the sprite to play the animation that we just added.

WADE provides animation events that your scene objects can listen to, namely onAnimationStart and onAnimationEnd. Let's get the object to move when the animation is over by adding these lines at the end of our init function:

        // handle onAnimationEnd event
        this.symbolObject.onAnimationEnd = function()
        {
            var posX = (Math.random() - 0.5) * wade.getScreenWidth();
            var posY = (Math.random() - 0.5) * wade.getScreenHeight();
            this.moveTo(posX, posY, 400);
        };

Note that onAnimationEnd is a member of the scene object, not the sprite. At the end of any animation of any sprite that belongs to the scene object, that function will be executed. In this case we have only a single sprite, so it doesn't make any difference, but it's an important point to keep in mind when you have scene objects with multiple sprites.

So in this function we're picking a random position anywhere on the screen, and as soon as the animation is over, we send our symbols object there.

Try the app as it is, and then we're going to make some changes. Let's have a look at the other arguments that we can pass to the Animation constructor, after the number of cells and speed:

    var animation = new Animation('data/symbols.png', 4, 1, 1.5, true, 0, 2);

There is a boolean value, that we're now setting to true, that indicates whether the animation should be looping. The final 2 parameters are the start frame and the end frame. By setting them to 0 and 2, we're effectively looping over 3 of the 4 frames that we have in our sprite sheet.

Sometimes it may be useful to set the start and end frames to the same value - technically it wouldn't be an animation anymore, since you would be displaying only one frame. This would be a nice trick, however, to optimise the loading time of your app: you could put as many static sprite images as you want on a single sprite sheet (as long as they're all the same size), then create one-frame animations for each of them. It's exactly the same thing as loading many separate images, but much quicker, because it takes a fraction of the time to download a single image.

Anyway, now that our animation is looping, you'll notice that the onAnimationEnd event is not firing anymore. This is correct, because our animation is never-ending. But for the purpose of this tutorial, let's set the looping option back to false.

Note that WADE accept any falsy values for things that should be false, null, undefined, etc. So, if you're feeling particularly lazy, you could pass 0 to the Animation constructor rather than false for its 5th argument, and it would still work in the same way:

    var animation = new Animation('data/symbols.png', 4, 1, 1.5, 0, 0, 2);

Try it right here

As an exercise, consider creating 4 objects out of the same sprite sheet, each one of them displaying a single symbol.

(Hint: the last 2 parameters in the Animation constructor will be equal).

App = function() { this.load = function() { wade.loadImage('/assets/tutorial/symbols.png'); }; this.init = function() { // create a sprite var sprite = new Sprite(); sprite.setSize(80, 80) var animation = new Animation('/assets/tutorial/symbols.png', 4, 1, 1.5, 0, 0, 2); sprite.addAnimation('test animation', animation); this.symbolObject = new SceneObject(sprite); wade.addSceneObject(this.symbolObject); sprite.playAnimation('test animation'); // handle onAnimationEnd event this.symbolObject.onAnimationEnd = function() { var posX = (Math.random() - 0.5) * wade.getScreenWidth(); var posY = (Math.random() - 0.5) * wade.getScreenHeight(); this.moveTo(posX, posY, 400); }; }; };