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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With