Posted by & filed under Tips.

In the previous post Eric explained how easy it is to create complex animation patterns using the powerful tl.enchant.js plugin. But did you notice that the animation speed sometimes differs depending on the device you are executing it on? This is caused by the fact that the explanation up until now was always relying on the frame based tl.enchant.js animation.
That means, if the machine executing the code is not as powerful as expected by the programmer (e.g. on smartphones or less powerful laptops) enchant.js won’t be able to keep up with the frame rate defined during development. For example, if the game frame rate was set to 60 frames per second

game.fps = 60;

but the executing browser can only handle around 30 frames per second this would result in the animations to be played with only half(!) the speed. This could make the game kind of boring because it gives the player way more time to react to events (for example reacting to enemy fire in shooting games).
You might think now, well if the machine of the user is not powerful enough then there is nothing I can do about that. But that’s not completely true. In the previous example, 30 frames would still be enough for a nice gaming experience. Even less frame rates can be sufficient for minigames to still be playable with just little drawbacks on the part of the visuals.

So, what can we do to keep the game execution speed on the same level independent of the frame rate? To solve this, let’s take a step back and first look at the frame based animation. For this purpose I’m using modified graphics from the presentation of Ryohei Fushimi which can be found here: http://www.slideshare.net/sidestepism/cedec2012-javascript (Japanese)

timebased_tl

As you can see in this image, the distance our bear moves on each frame is fixed. That’s why the distance our bear moved on the left hand side is about twice as much as on the right hand side.

Now, to solve our problem instead of using frames as a unit let’s take a look at a time based approach.

With the time based approach, the distance our bear moves is calculated using the elapsed time between the frames. This is also what is used in the real world when looking at moving bodies using physics (e.g. s(t) = v*t + s0, with s := displacement, s0 := initial displacement, v := speed and t := time). So this time based approach is exactly the solution for our problem. If we can apply this to our animation it will always be played at the same speed. But how can we apply this time based animation to enchant.js?

In enchant.js it is possible to get the elapsed time between two successive ENTERFRAME events using the elapsed property of the ENTERFRAME event. For example:

var sprite = new Sprite(32,32);
sprite.addEventListener(enchant.Event.ENTER_FRAME, function(e) {
    var elapsedTime = e.elapsed;
    … 
});

But this seems a bit complicated right?
However, as of the enchant.js version 0.5.2 release this is not necessary anymore because a new feature was introduced to the already mighty tl.enchant.js plugin, which allows us to directly use time based animations. Let’s take look at the usage of this feature.
The tl property of the Sprites (object of type enchant.tl.Timeline) has now two new methods:
setTimeBased()
setFrameBased()
These methods are the only thing you need to switch between the two animation modes, whereas the default is the frame based animation.

Now, when creating an animation sequence the duration defined for each single animation will either be counted in frames for the frame based animation as it used to be in milliseconds when the time based animation has been activated.
To show you the difference, let’s take a look at the following small program:

enchant();

var BearSprite = enchant.Class.create(enchant.Sprite,{
    initialize: function(y,imageOffset) {
        enchant.Sprite.call(this,32,32);
        var game = enchant.Game.instance;
        this.x = 0;
        this.y = y;
        this.imageOffset = imageOffset;
        this.ageDivisor = game.fps/15;
        this.image = game.assets["chara1.png"];
        game.rootScene.addChild(this);
    },
    onenterframe: function(e) {
        this.frame = (this.age/this.ageDivisor) % 2 + this.imageOffset;
    }
});

window.onload = function(){
    var game = new Game(320, 320);
    game.fps = 60;
    game.preload("chara1.png");
    game.onload = function(){
        var frameBasedBear = new BearSprite(0,6);
        var timeBasedBear = new BearSprite(40,11);

        frameBasedBear.tl.moveTo(200,frameBasedBear.y,200).scaleTo(-1,1,1).moveTo(0,frameBasedBear.y,200).scaleTo(1,1,1).loop();

        timeBasedBear.tl.setTimeBased();
        timeBasedBear.tl.moveTo(200,timeBasedBear.y,(200/game.fps)*1000).scaleTo(-1,1,1).moveTo(0,timeBasedBear.y,(200/game.fps)*1000).scaleTo(1,1,1).loop();
    };
    game.start();
};

With this small program two bears will be displayed. These two bears will run at the same speed from the left to the right. The upper one is animated using the frame based tl:
frameBasedBear.tl.moveTo(200,frameBasedBear.y,200).scaleTo(-1,1,1).moveTo(0,frameBasedBear.y,200).scaleTo(1,1,1).loop();

So this bear will run from the left to the right within 200 frames, then switch the direction by scaling it to (-1,1) and after that run back to the left which will again take 200 frames. This motion is then repeated.

On the other hand, the lower bear is animated using the time based tl:

timeBasedBear.tl.setTimeBased();
timeBasedBear.tl.moveTo(200,timeBasedBear.y,(200/game.fps)*1000).scaleTo(-1,1,1).moveTo(0,timeBasedBear.y,(200/game.fps)*1000).scaleTo(1,1,1).loop();

First, the setTimeBased method of the tl property is called to change the Timeline to a time based version. To let the time based and frame based bear run at the same speed, the previous duration of 200 frames is divided by the fps rate of the game which results in the animation speed in seconds so to convert it to milliseconds its multiplied by 1000.
By this, at least in theory, the two bears should run back and forth at the same speed.

You can even adjust the game.fps to change the speed at which the bears are moving, the two bears should always – in theory – run at the same speed.

But they are not running at the same speed. Depending on your machine the results will differ but in my case I was able to observe the following behavior:

using 15 frames per second the upper bear is slightly faster than the lower one
using 60 frames per second the upper bear is slightly slower than the lower one
using 120 frames per second or more the upper bear will get slower and slower compared to the time based bear

Note: Please note that 120 frames sure is a high frame rate but using such a high frame rate it’s possible to simulate a game where the performance drops due to many sprites or complicated calculations.

From time to time I could also experience some changes in the movement speed of the upper bear because of changing frame rates (maybe induced by background processes on the host system). The movement of the lower bear looks much smoother.

So, even with a low frame rate the behavior differs. The reason for that is that it’s not possible for enchant.js to ensure the desired frame rate even if there are no performance issues. That’s just normal behavior for any application on any device. But using the time based animation the effects of these influences are minimized.

Pretty nice, right?

I’ve extended the previous stated example a bit and uploaded it to 9leap, so you can play around with different frame rates on different devices. Just click on the frame rate text to change the frame rate and let our two bears run!

http://9leap.net/games/2554

This post is also available in: Japanese