Making HTML5 Canvas Canvas

Sunday, September 22, 2013

Appendix 3. RequestAnimationFrame: Consistent time among devices.

Due different capabilities on devices, requestAnimationFrame is not consistent among them, it's update time varies to lower intervals on lower power devices, which will make games slower on some devices than on other. To avoid this problem, is necessary to regulate the time among these devices.

There are many ways to do this. Next, I will show some of the most popular known:

1. Wrap requestAnimationFrame on setTimeout.

As simple as read. When I look up at the Internet for information on consistent time with requestAnimationFrame, this was the first answer to appear. I would be done this way:
    setTimeout(function(){requestAnimationFrame(run)},50);
This is practically making a setTimeout, with the advantage of requestAnimationFrame's optimization. Or at least that was what the site where I read it said.

Effective? Barely. After testing at 50 milliseconds, the resulting test gave me 15 frames per second instead of the 20 desired, which tells me this method is little-effective. At least, it makes a regular time among devices.

Advantages:
  • Easy to implement.

Disadvantages:
  • Doesn't fulfil the expected time on high interval.
  • Little effective on lower intervals.

See the example and code of this method.

2. requestAnimationFrame for paint, setTimeout for act.

An alternative to regulate time, is making asynchronous the paint and act functions. This is, to make the both update each one at it's own interval, optimizing this way the times for both actions. The disadvantage is that some times you would like to use values interact among act and paint functions, which could be a more complex task than usual.

The most simple way to make an asynchronous method, is (as the title says), using a requestAnimationFrame for the paint function, and a setTimeout for the act function. For this, two different functions are created to call themselves continually:
function run(){
    setTimeout(run,50);  
    act();
}

function repaint(){
    requestAnimationFrame(repaint)
    paint(ctx);
}
You now must call both functions (run and repaint) at the ending of the init function, and the game will run as usual.

At the example, I have added besides the frames per second, a second variable called cycles per second (CPS), which shows that, effectively, both functions fulfil their objective.

Advantages:
  • Easy to implement.
  • Effective on high intervals.

Disadvantages:
  • Is asynchronous.
  • Little effective on lower intervals.
  • Still consumes CPU if the games falls into background, through on a lesser way than when not using requestAnimationFrame for painting.

See the example and code of this method.

3. Using the delta time.

The most effective and popular method! And implementing is quite easy, as the hardest part you have done it before, when we implemented the frames per second.

Basically is taking the code to calculate the deltaTime, and send this value when you call the act function. With this value, you simply multiply it for the object displacement, having the guarantee that the object will move always the same amount of pixels per second, beyond the frames per second on each device.

Which value you must use to make this multiplication? This depends on your needs. For the current example, we are making a displacement of two pixels per cycle, on an optimal time of 60 frames per second... This means that we are moving 120 pixels per second. If we want the same speed, we just divide 120/1000, and we get that we must multiply the delta time with 0.12:
function act(deltaTime){
    x+=0.12*deltaTime;
    if(x>canvas.width)
        x=0;
}
For this example, this method has been easy to apply, but when we notice that this multiplication must be done for every movement and animation on our game, to make it truly consistent, we find out that this could be a little tricky to keep at this way. Nevertheless, it is still the most effective among all the options.

Advantages:
  • Always reliable and consistent

Disadvantages:
  • Tricky to maintain.
  • Freezes the game when it falls into background.

See the example and code of this method.

Conclusion: Which method to use?


Every method has advantages and disadvantages among them. At the end, the decision on which method to use, depends on the needs of your game. Just I won't recommend the first one, but the third is the best option, and the second one is an easy way to implement this, which usually works good on most cases.

You are encouraged to experiment with them, and see which one fits better on your needs.

No comments:

Post a Comment