Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a JavaScript animation play at the same speed on all browsers on all systems?

I have a function that calculates the next frame in an animation of various objects moving in both X and Y axis [ I call it frameRender() ] and a function that applies that resulting frame to the objects [ I call that frameDisplay() ]. The objects don't just move from point A to B, they move constantly, always receiving new target coords. I use a setInterval() with a 1000/frameRate interval but that doesn't seem to work at all as browsers don't have accurate timings.

The question is: How can I make sure the animation has a constant frame rate, and will run at the same speed on all browsers, on all systems? I have tried everything and can't seem to get an accurate result even on just different browsers (I test on Firefox and Chrome, Chrome usually displays a lot faster).

The result should be: When it plays slow, the animation interval should decrease at first, and then try to skip some frames [ by skipping frameDisplay() ] if it the DOM displays slow, until it plays correctly. When it plays fast, the animation interval should increase, making the animation play at the correct speed.

But how do you keep consistency in all of this, since you can't always be sure when the browsers will become slow, or when they will perform fast. For example, if there is huge spike of movements, and we decrease the interval to keep the frame rate steady, and then suddenly most of the moving objects stop or don't move much, it will suddenly perform really fast!

Any ideas?

like image 797
stagas Avatar asked Jun 28 '10 22:06

stagas


2 Answers

The question is: How can I make sure the animation has a constant frame rate, and will run at the same speed on all browsers, on all systems?

You can't do anything about the framerate. The only thing you can control is how your application updates based on time passed. This is true outside of browsers as well, and a common topic in game development.

The best thing to do is track the delta (read: time difference) between updates.

(function () {
    function getTime() {
        return new Date().getTime();
    }
    var last = getTime();

    function update(delta) {
        // Update your application state on delta (ms of time passed)
    }

    (function loop() {
        update(last = getTime()-last);
        render();
        setTimeout(loop, 20); // 20 = attempt 50fps
    }());
}());

Notice the use of setTimeout here. This is to avoid the loop() from being called out of sync. setInterval will keep firing it even if a previous call didn't finish.

like image 88
Matt Avatar answered Oct 17 '22 23:10

Matt


The answer is here, a great article by Glenn Fiedler, needs a little tweaking to convert it in Javascript but the principles are the same. Basically, you need to use an accumulator that adds up delta timings, and execute steps based on that. No need to change any physics math or anything, the solution is plug n play. Also has a cool interpolator that removes stuttering and also allows you to do super slow smooth motion (for replays etc.). It's fantastic, works for physics and should work on any step based motion. Basically all you need for accurate timing game motion is there.

like image 3
stagas Avatar answered Oct 18 '22 01:10

stagas