framerate independent 2D animations

Hello,

My 2D animations are running much faster on high framerate compared to 60 FPS, even worse at 30 FPS.
I am using 2D animation class based on this blog post:
http://rbwhitaker.wikidot.com/monogame-texture-atlases-2
The responsible code for setting the frames of my animations is the following:

            if (currentDelay >= delay)
            {
                CurrentFrame++;
                currentDelay = 0;
            }
            else
            {
                currentDelay += gameTime.ElapsedGameTime.TotalMilliseconds;
            }

The problem is the following:

Let’s say I have an animation that is running at 24 FPS, meaning that the value of the ‘delay’ is 41.6 ms. When my game is running on very high (unlimited) FPS mode, the ‘elapsedTime’ in very very small, meaning that the animation will change to the next frame accurately roughly at 41 ms.
But when my game is running 60 FPS (30 FPS is even worse), the increments of the ‘currentDelay’ will equal the elapsedTime, which is at first 16 ms, then 32, then 49ms, and that’s when the animation will change frames, resulting in much slower animations on 60 FPS compared to uncapped gameplay.
Is there any trick to do this better? I would not like to cap my game to 60 FPS, but the difference is very visible and it fail to see how to improve this code and avoid this.

Thanks

How about implementing your framecounter as a float.

Then each frame add the frame counter delay (eg 1 x elapsedtime)

Then when it comes time to draw just round the framecounter to the nearest int.

This should stop the effect your frame counter increasing at uneven times.

currentDelay += gameTime.ElapsedGameTime.TotalMilliseconds;
if (currentDelay >= delay)
{
    CurrentFrame++;
    currentDelay = 0;
}

I’d say moving your delay counter before you increment the animation frame may be part of the problem. Every animation frame will lag by one update frame with your current setup, and at lower FPS will be more noticeable.

I just reread your initial post… The change I cited in my previous post is probably not gonna change a whole lot, although I would recommend still doing it.

However, I do have a suggestion:

currentDelay += gameTime.ElapsedGameTime.TotalMilliseconds;
if (currentDelay >= delay)
{
    CurrentFrame++;
    currentDelay -= delay; //save remainder

    //just in case of a lag spike, but may not be necessary
    if (currentDelay >= delay)
    {
        currentDelay = 0;
    }
}

This will save the leftover time in your currentDelay, so regardless of your frame pacing, your animation should still run at the same speed.

The way I do my animations is that I have a float variable m_frameTime on each game object and I set it to the amount of time I want before it moves to the next frame. I subtract out the GameTime.Elapsed on each Update loop and when m_frameTime <= 0 then I move to the next frame. So my animation speed is dependent upon time and not the number of frames.

But then you can get uneven animation.

You will skip to the next animation when m_frametime < 0. But there will be some left over frame. That leftover frametime will change depending on fps and the time for each frame jump.

Unless you add the leftover animation into the next m_frametime

You only get uneven animation if your game is running slower than your frame time.

Not necessarily.

m_frametime = 4
If on each frame at a constant fps (for simplicity’s sake) your taking m_frametime - 0.6f.

On the 6th frame, frame time would be down to 0.4f (7 * 0.6f) still more than zero)

On the 7th frame it would equal -0.2f. Which is less than zero. Now if you reset your m_frametime back to 4. On a fixed fps you wouldn’t notice as your getting a new animation every 7 frames.

On a variable fps, because your not using the remainder -0.2f, your frametime will not update consistently.

On a high fps it won’t be noticeable. On a low fps you will get a jitter every now and then.

The way to fix that would be to use that remainder 0.2f and add it back (edit: subtract it from) on the m_frametime. So the next m_frametime will be 4.2f (edit 3.8f)

Just quickly read your answer. So not sure, but wouldn’t you need to subtract it from m_frametime? Since you want to account for the already passed time?

Yes you would actually my bad

I realised some code I use for FPS calculation seems to have that issue too.

You need this.

and this
Monofoxe/TimeKeeper.cs at develop · Martenfur/Monofoxe · GitHub (just don’t forget to set _elapsedTime)

1 Like

Thanks, I’ll check this! I was looking at your engine, and man, I have to say our way of thinking is just ridiculously similar! :smiley: The engine you’re working is very similar to mine, they way you’re handling your layers, your animations (apart from my bug), having actions when your animation ends, etc. even our naming is very similar.
Keep up the good work!

So the problem is that you’re doing very discrete operations on continuous data.

You have a few options with different considerations.

  1. Maintain the “advance frame when boundary crossed” approach and try and finagle exact times. You’ve got some good options already in the thread for this.

  2. Use modulus arithmetic. Works IFF all frames are the same length, and the number of milliseconds isn’t well, at least until the TotalMilliseconds’ mantissa loses ones digit precision, after the game’s been running for 70 thousand years.

CurrentFrame=((int)(gameTime.TotalGameTime.TotalMilliseconds-this.AnimationStartTime)%delay)%framecount
1 Like

thank you!