Fixed Time Step

I am suspecting that IsFixedTimeStep is not working properly. My understanding is that, when true, the Game is supposed to run at the specified “framerate”. So, for example, my TargetElapsedTime is set to 0.0166666f (that is, 1/60 second), so as to achieve an update/draw rate of 60Hz. Is this the correct assumption?

However, the results I’m observing are - at least, to my comprehension - counterintuitive. It seems to be running the DoUpdate method several times (while (_accumulatedElapsedTime >= TargetElapsedTime)), each with a _gameTime of exactly .0166666 seconds. In other words, it’s performing as many fixed-increment updates as possible so that it “catches up” with the amount of real world time that has passed. In the event that it has time to spare, it will Sleep it off until the next fixed time interval.

If I set IsFixedTimeStep to false, then it simply updates once based on how much real world time has passed, and passes in that amount as the GameTime parameter. That is, I’m not seeing exactly .0166666, which is what I would expect. However, this gets called as rapidly as possible, without Sleeping; it does not honour the TargetElapsedTime in any context in which IsFixedTimeStep is false.

What I had expected - what I hope to achieve - is the following. (And, again, I hope I’m presenting logic that makes sense). Here is some pseudocode:

if (_accumulatedElapsedTime >= TargetElapsedTime)
{
    DoUpdate(accumulatedElapsedTime); // so I know how much to advance - this is like what happens when IsFixedTimeStep is false.
}
else
{
    DoUpdate(TargetElapsedTime); // this is sort of the minimum amount of time that will pass per update
    Sleep(howeverMuchTimeRemains); // ease the load of the CPU, much as seen when IsFixedTimeStep is true.
}

Does that make sense? Are there any flaws in my observations or reasoning?

1 Like

There’s also the opposite problem - if the game rendering is slow and cannot achieve the fixed framerate, the game will slow down. I don’t know if it’s supposed to behave like that, but IMO that makes fixed time step pretty much unusable.
I thought IsFixedTimeStep = false, SynchronizeWithVerticalRetrace = true would be the ideal combination, until I encountered this issue :frowning:

I also can’t figure out how to make the game run smooth with 60 UPS/FPS…

Here is some slightly more elaborate pseudocode of what I would expect this behaviour to be. (Also, thanks, Jjagg, for demonstrating how to cite code here.)

if(IsFixedTimeStep)
{
    if (_accumulatedElapsedTime >= TargetElapsedTime)
    {
        DoUpdate(_accumulatedElapsedTime); // so I know how much to advance - this is like what happens when IsFixedTimeStep is false.
    }
    else
    {
        DoUpdate(TargetElapsedTime); // this is sort of the minimum amount of time that will pass per update
        Sleep(howeverMuchTimeRemains); // ease the load of the CPU, much as seen when IsFixedTimeStep is true.
    }
}
else
{
    DoUpdate(_accumulatedElapsedTime); //Just increment by whatever amount of real time has passed, and don't try to sleep or otherwise compensate for a potentially erratic time step. After all, IsFixedTimeStep is false here. I think this is consistent with the current behaviour.
}

I would make these changes in a subclass of Game, but the necessary methods are private and not protected. I wonder if perhaps that should be altered, so as to allow this change but simultaneously maintain backwards compatibility?

I am suspecting that IsFixedTimeStep is not working properly. My understanding is that, when true, the Game is supposed to run at the specified “framerate”. So, for example, my TargetElapsedTime is set to 0.0166666f (that is, 1/60 second), so as to achieve an update/draw rate of 60Hz. Is this the correct assumption?

No, that’s not the correct assumption. It locks the update integral into an accumulation mode - as time passes an accumulator is incremented, for as long as that accumulator excedes the update rate update will be called.

Yes, if your game is running too slow it’ll descend into a lock hell.

Read the classic Fix Your Timestep article.

Fixed timesteps are questionable in a system-dependent JIT’ed language like C#, but that’s a whole different debacle about multiple-machine determinism.

Yes, if your game is running too slow it’ll descend into a lock hell.

Yeah, see, that’s part of the problem with the current implementation.

Consider a scenario in which poor performance arises, such that Update takes the time of two fixed-time intervals instead of <1. (Firstly, this is a sign someone should revise their code, but that’s not the point here…) During the next cycle, the current implementation will run Update twice to make up for that time, but each of those Update calls will likely cause it to fall behind even further, such that the next cycle will try to run Update four times, etc. Lock hell, indeed.

If you use the approach I outlined above, rather than calling upon Update multiple times per Tick to catch up, it would run once, passing in a larger value of ElapsedTime. That is, after all, the purpose of ElapsedTime, so that Update knows how much action to advance in a single call.

1 Like

Consider a scenario in which poor performance arises, such that Update takes the time of two fixed-time intervals instead of <1. (Firstly, this is a sign someone should revise their code, but that’s not the point here…) During the next cycle, the current implementation will run Update twice to make up for that time, but each of those Update calls will likely cause it to fall behind even further, such that the next cycle will try to run Update four times, etc. Lock hell, indeed.

Which is what it should do. If you’re depending on a fixed timestep then you’re depending on that exact interval, not a larger one every so often.

If you don’t care what the timestep is then turn off fixed-timestep and write a frame-limiter into your main loop.

A frame-limiter and fixed-timestep are not the same thing.

Again, https://gafferongames.com/post/fix_your_timestep/

3 Likes

For my purposes I don’t care about the timing stuff at the moment, since I have not been doing anything like physics simulation. Just wanted to say that I enjoyed reading the article. Very well written :slight_smile:

A frame-limiter and fixed-timestep are not the same thing.

Now that makes sense. This was the comprehension that I was missing.

That said, I’m not sure how best to implement a frame-limiter in Monogame. As illustrated in my earlier posts, I would like to have some sort of Sleep between updates, but the Tick method is not accessible in subclasses. @Jjagg, would it be beneficial to mark it as protected in the Game class to allow such alterations?