views:

168

answers:

3

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?

+4  A: 

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.

Matt
So basically you mean I should change the frame rendering math to include a delta variable, so I can move for example the object more or less X Y pixels based on the previous time passed?
stagas
@stagas - exactly. That way if one update is within 50ms and the other is at 450ms, your application should still be at the "500ms mark" if you get what I mean.
Matt
@Matt: Cool, will try that right away thank you
stagas
Instead of calling update() directly, I would fire a custom event like "heartbeat" with the delta as a parameter. This would let you bind the heartbeat to a key, to debug stepping through one frame at a time, among other things.
ironfroggy
@Matt: It almost works, what I need now is to rewrite almost all of the math to include the delta multiplier. Some where plug n play but most don't work quite well. What I'm doing basically is `(delta/(1000/frameRate))*someValue` to compensate for the time difference, but it's not that easy always.
stagas
+1  A: 

You can synhronize your animation with system time.

Save current system time in variable. On the all of frames then you want to redraw picture check if current time - your variable equal some delta time. then redrow your animation. else wait this difference

Falcon
A: 

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.

stagas