requestAnimationFrame() – 60 frames/second animation (best practice)!
INTRODUCTION: ADVANTAGES OVER PREVIOUS METHODS
The new requestAnimationFrame(animationLoop) is very similar to setTimeout:
- It targets 60 frames/s: requestAnimationFrame asks the browser to schedule a call to the animationLoop function passed as parameter in 1/60th of a second (equivalent to 16.6ms). Keep in mind that most monitors cannot display more than 60 frames per second (FPS). Note that whether humans can tell the difference among high frame rates depends on the application, most games are acceptable above 30 FPS, and virtual reality might require 75 FPS to achieve a natural feel. Some gaming monitors go up to 144 FPS (pro players in e-sport train themselves at Counter Strike with a 150 frames/s rate).
- It calls the function only ONCE, so if you want a continuous animation, like with setTimeout, you need to call again requestAnimationFrame at the end of the animationLoop function.
It has, however, several advantages over setInterval and setTimeout:
- The scheduling is much more accurate: if the code inside the function can be executed in less than 16.6ms, then the average error between the scheduled time and the real time will be much smaller than with the old functions.
- High resolution timer: even if this difference is small, the function that is called after 16.6ms has an extra parameter that is a high resolution time, very useful for writing games that do time-based animation. Time-based animation will be studied in detail in the HTML5 Part 2 course at W3Cx. It is a technique that comprises measuring the amount of time elapsed between two frames, then computing the distance in pixels to move objects on screen so that the visible speed for a human eye remains constant, even if the frame rate is not.
- Multiple animations are merged: browsers can bundle animations happening at the same time into a single paint redraw (thus happening faster/with less CPU cycles), solving the problems that can occur with simultaneous setInterval calls.
You will note that requestAnimationFrame(function) is used like setTimeout(function, delay). A call to requestAnimationFrame just asks the browser to call the function passed as a parameter ONCE, and the target delay is fixed, and corresponds to a 60 frames/s frame rate (16.6ms). Notice that an id is used for stopping an animation with cancelAnimationFrame(id).
EXAMPLE: ANIMATE THE MONSTER WITH REQUESTANIMATIONFRAME
IS THE 16.6MS DELAY REALLY ACCURATE? CAN WE TRUST IT?
This target may be hard to reach if:
- The animation loop content is too complex,
- The target device that runs the animation is a low end phone or an old computer,
- The scheduler may be a bit late or a bit in advance (even if this kind of error is much smaller withrequestAnimationFrame than with setInterval or setTimeout).
Many HTML5 games perform what we call a “time-based animation”. For this, we need an accurate timer that will tell us the elapsed time between each animation frame.
Depending on this time, we can compute the distances that must be achieved by each object on the screen in order to move at a constant speed (for a human eye), independently of the CPU or GPU of the computer or mobile device that is running the game.
The timeStamp parameter of the animationLoop function (line 1 in the above code) is useful for exactly that: it gives a high resolution time. By measuring deltas between two consecutive calls of the animationLoop, we will know exactly, with a sub-millisecond accuracy, the elapsed time between two frames.
Using time-based animation, and more generally, using the canvas element for writing HTML5 games, will be a chapter of the HTML5 Part-2 course to come.
Current support (as of June 2016) is really good and all modern browsers support this API.