How to fix stuttering in scrolling animations
As I started working on our next game, I noticed a very strange and unpleasant behaviour: when scrolling the viewport, the animation was stuttering. Here’s how I fixed it.
The first impression that this behaviour gave me was that my computer wasn’t powerful enough to run the game, but having a constant 50fps (The refresh rate of some laptop monitors is 50Hz), and a maximum 30% CPU usage demonstrated that my computer can handle the game just fine, so there must be an elegant solution to this.
Now, anyone willing to implement a game engine should read the excellent article Fix Your Timestep! by Glenn Fiedler. In fact, if you follow (and understand) that article until the end, you’ll see that this problem has been addressed there.
Another thing to mention is that I’m also the author of the friGame library, that is used by our next game.
The problem is: I did not fully understand Glenn Fiedler’s article, so, until recently, the update/draw loop in friGame looked something like this:
friGame.draw = function (timestamp) {
var
newTime = timestamp,
frameTime = newTime - currentTime
;
requestAnimationFrame(friGame.draw);
currentTime = newTime;
accumulator += frameTime;
if (accumulator >= dt) {
while (accumulator >= dt) {
playground.update();
accumulator -= dt;
}
}
playground.draw();
};
Which is based on the second to last code block from Glenn Fiedler’s article.
For years I thought that this code was good enough, it had a fixed time step of 16.67ms, and on 60Hz monitors it looked good.
Moreover I was confused by the last part of Glenn Fiedler’s article when he talks about interpolating between the previous and current physics state.
What does it mean that I have to store the previous physics state? Does it mean that I have to keep track of accelerations, speeds, and so on for every object in my game?
Moreover, if I have to keep track of the physics of the game, I can no longer use the same API in friGame, or be free to choose a different physics engine on a game by game basis.
It turns out that none of this is true, I was simply confused by the choice of words.
You see, in the last part of Glenn Fiedler’s article, the interpolation is done in order to render an intermediate state, so, in theory, the only states to keep track of are the ones that affect rendering, and these are:
- Position
- Size
- Rotating angle
- Scaling factor
- Opacity
In pratice, there is a computational cost for keeping track and interpolating all these values, so smooth scrolling can be achieved simply by keeping track and interpolating only the position of all the sprites.
So, in the latest development version of friGame the update/draw loop looks something like this:
friGame.draw = function (timestamp) {
var
newTime = timestamp,
frameTime = newTime - currentTime
;
requestAnimationFrame(friGame.draw);
currentTime = newTime;
accumulator += frameTime;
if (accumulator >= dt) {
while (accumulator >= dt) {
// Keep track of all the sprite positions
for (sprite in friGame.sprites) {
sprite.prevLeft = sprite.left;
sprite.prevTop = sprite.top;
}
playground.update();
accumulator -= dt;
}
}
playground.draw(accumulator / dt);
};
sprite.draw = function (interp) {
var
left = (this.left * interp) + (this.prevLeft * (1 - interp)),
top = (this.top * interp) + (this.prevTop * (1 - interp))
;
ctx.drawImage(this.img, left, top);
};
After implementing the interpolation of only the sprite positions, I was impressed by how smooth the animations have become.
I’m planning to release an update to friGame in the next few weeks, so stay tuned.
There are comments.
About framesets in friGame
tags: technical frank the dillo frigame cocoonjs
Framesets are the cool new feature in the latest development version of friGame, and in this blog post we will see what they are and the motivation behind their implementation.
Read MoreThere are comments.
What to do when your HTML5 game runs slow on mobile devices
tags: technical frank the dillo, frigame cocoonjs
In the first installment of the technical series, we talked about the main disadvantage of the HTML5 technology, that is its performance can be poor compared to a native app.
When testing Frank the Dillo a Kindle Fire HD it was so slow that it was unplayable.
Should Frank the Dillo be rewritten in Haxe, or is there a solution to make HTML5 games run faster?
Read MoreThere are comments.
Analyzing the building blocks of a friGame based game
In the previous installment of the technical series, we looked at the various technologies needed to make a game based on friGame, and the 3 major blocks that compose friGame itself; now let’s take a look at the details of these blocks by analyzing the arkanoid demo bundled with friGame.
Read MoreThere are comments.
Structure and basic concepts of a friGame based game
In the previous installment of the technical series, we discussed about why friGame was the chosen technology for developing Frank the Dillo; today we will be talking about the concepts behind friGame and the basic structure of a game based on it.
Read MoreThere are comments.