Understanding FixedUpdate, FixedTimeStep and Maximum Allowed Timestep in Unity

This post is for everybody who needs a longer and more detailed explanation on this concepts in Unity, and for those who think they know but want to check if they are right...
Cover Image

Introduction: Are you sure you understand it?

Everybody thinks they understand the difference and how it works, but the truth is that when people have serious problems with syncronization, physics, animation, inaccuracy of physics and such, they are forced to finally understand deeply what FixedUpdate(), Update(), Maximum Time Step, Time Step size and such concepts truly mean.

And sadly, it is a very important concept that everybody should understand in order to make games. You need to know exactly how all these concepts work.

Even when I thought I completely understood it, I had to come back and study it again after trying to explain it to my colleagues. It's common to talk with somebody who says "Oh yes, FixedUpdate(), I understand how it works", it doesn't take that much time to find out they don't. It needs quite a bit of brainpower to get it and most of the programmers I know don't spend much time understanding this. 

Will you be like them? Hopefully I grabbed your attention.

YouTube Video

I made a video out of this blog post if you are interested in listening instead of reading. This blog post is more accurate and more carefully written, and the english is probably much better, but please feel free to visit the video instead:

https://youtu.be/4Z360l1pC_4

A frame in Unity

This is probably the most important and one of my top visited pages on the Unity manual: https://docs.unity3d.com/Manual/ExecutionOrder.html

This is the simplified version of a frame in Unity. 

As the arrows depict, this cycle is repeated all the time. Once every frame. I guess you understand that if your app runs at 60fps it means it executes this cycle 60 times...

Well. In fact, the previous image is not true. The truth is that it runs this way:

Sometimes the physics step is not run at all in a frame and sometimes one or more times!. How many, why?. Let's first see in detail what each section does:

As you can see, with the asterik symbol, that the physics part is equivalent basically to running FixedUpdate() method for all components and everything related to them. And it is executed from 0 to N times.

Then goes the game logic where Update() is executed just once and always once. At the end of the game logic LateUpdate() is called (after all Updates() are called for all components and more stuff), then we move on to rendering all the parts of the image, then the end of frame is executed, then we come back to physics again.

There are many other things happening inbetween, but these are the ones that matter to us right now.

How long is each frame?

If you open the Stats window on the Game View, the time that your frame takes is 0.8ms to execute and draw completely and your game runs at 1260.8 frames per second.

That is the sum of all the steps in the frame, including the N physics steps done that frame.

The time spent on executing a frame is NEVER the same. That is why the profiler is not a perfect line, every frame takes a different time to execute.

The duration in ms of each physics part depends on the complexity of the physics calculations in Unity as well as your code inside FixedUpdate() functions in all enabled MonoBehaviours (components).

So why are physics executed 0 times to N times instead of just one? Here's the key concept. Probably the most difficult question to answer.

Basic concept : Game Time vs Wall Clock Time

This is absolutely key to understand these concepts and allows you to understand the rest of the concepts.

"Game time" is the time passed inside the game world. It is different from the time passing for us, the human players, people using the computer, which is called "wall clock time".

An app is said to be "realtime" when time in the game world passes at the same speed as in the real world. 10 seconds inside the game will be 10 seconds for us too aproximately.

If the game slows down because of lag in the network, a slow computer, or the physics complexity at a certain moment, the game time will not catch up with time in the real world.

What are FixedDeltaTime and DeltaTime?

Have you ever used Time.fixedDeltaTime and Time.deltaTime to access the amount of time passed?. 

DeltaTime should be called inside Update() or related functions, but it is rarely used inside FixedUpdate(). It is used to get the game time from the previous Update(). Careful with this: Not the real time passing for us, the humans playing the game. 

This missunderstanding is the origin of the top one question asked by beginners: Why is my procedural animation, calculation, not executing smoothly?. Every calculation you do in your Update() function needs to be scaled by Time.deltaTime, so that the movement is relative to the time passed in-game, from the last frame. If the last frame was executed very fast, your animation should advance very little too. Always multiply your values by Time.deltaTime to get a really smooth and consistent movement.

On the other hand, Time.fixedDeltaTime always returns the same value. And it is the same as the value set in the Time Settings (unless you call it from the Update() function, which returns deltaTime instead, something absolutely confusing and that they should change asap).

Let's first open the Time settings, something very important that you have to understand. (Edit -> Project Settings -> Time).

These are the default values. The ones that are important to us are Fixed Timestep and Maximum Allowed Timestep. I think most of the people play with these numbers without knowing what they are doing. But these can absolutely break physics, destroy the efficiency of your game or even stall it to its death if you don't know what you are achieveing with them.

What value should we set Fixed Timestep to?

The value is set in seconds. 0.02 means 20 ms. We will find out which values are the best.

First, these are the rules:

  • It has to be over 0
  • The smaller the value, the more accurate and stable the physics will be, but the efficiency of your game will decrease, sometimes enough to stall or even break the game.
  • A bigger value improves efficiency in your game, but increases the chances of physics being more and more unstable.

This is the key to understand everything: 

The fixed timestep doesn't represent the "wall clock time" we give it to execute physics, as most people think. It represents the amount of "game time" that the physics have to calculate on each step. The "wall clock time" it takes to execute a physics step is unrelated to the amount of "game time" simulated by that step.

So remember this:

Fixed Time Step = Amount of game world time advanced in one physics step (one call to FixedUpdate)

Example

Frame 1 took 10ms from start to end to execute and render in our screen.

To keep the simulation realtime, in frame 2 we need to advance the state of the game world as much "game time" as "wall clock time" it took to execute the previous frame.

Our FixedTimeStep is set to 0.004 (4ms). That means, each physics step calculates only 4ms worth of "wall clock time" out of those 10ms. We will need to run 2 physics steps in order to reach 8ms from the previous frame. The remaining 2ms are not enough to take a third step, so it will be accumulated for the next frame.

Suppose that executing one physics step takes 1ms of "wall clock time" (calculations are generally similar on all physics steps on similar situations), so our physics step will take 2x1ms = 2ms of "wall clock time" to execute. The rest of execution (Update(), rendering...) takes 1ms of "wall clock time" for whatever reason in this frame. So the entire frame takes 2+1 = 3ms of "wall clock time", instead of the 10ms we had before.

Now we move on to the next frame. We start with physics. 

To keep game time in sync with wall clock time, again, we need to calculate 3ms of game time plus 2ms of the previous gametime that we couldn't take. We can calculate 4 our of those 5 doing one step of 4ms. The other 1ms is left for the next step. The rest of the execution takes 1ms of "wall clock time" again. This frame took 1ms of one physics step + 1ms of the rest = 2ms of "wall clock time".

Now our fourth frame will have to calculate 2ms from the previous frame plus 1ms left that we didn't calculate from frame 2. That makes 3ms, not enough for our 4ms timestep!. This time there will be no physics steps at all until we accumulate enough gametime to calculate on subsequent frames.

I hope you get how this works after this detailed example.

Key concept to remember: A physics step with a timestep set to 1 will take the same wall clock time to execute as a physics step with a timestep set to 0.01. But it will have to execute 100 times more to calculate the same amount of gametime physics. More accurate, less unstable... but tremendously slower. A wise and adjusted selection of that value will be important to ensure equilibrium.

What happens with the accumulated time? How does it affect the simulation?

As we saw in the previous example, we need to keep track of the amount of unsimulated time. We consume that accumulated time in fixed time step sized chunks until the accumulated time left is less than the size of one chunk.

This is how it is implemented:

float accumulated = 0;

(...)

// At the start of each frame
accumulated += Time.deltaTime;

while (accumulated >= Time.fixedDeltaTime)
{
    FixedUpdate();
    accumulated -= Time.fixedDeltaTime;
}

How does this accumulation affects the look of my game?

The truth is that the state of the game world as it is rendered at the end of each frame is never accurate. Game time always lags behind wall clock time an amount between 0 and Time.fixedDeltaTime seconds.

Moreover, when game time runs in slow motion, you can clearly see objects popping from one step to the next because there are lots of frames that are not executing any physics steps.

To help hide this lag, game engines apply some interpolation / extrapolation strategies to make it less distracting.

What is MaximumTimeStep for?

Ok. Now enters the maximum time step value in the Time Settings.

As you have seen, the number of physics steps needed for each case can be reduced and increased depending on many variables. What happens if physics takes forever to calculate for whatever reason? what happens if the rendering is extremely slow for a certain frame but game time is passing anyway?

Our last frame was very slow and took 40 ms to render. In the next frame we need to calculate the physics for 40 ms, and it means having 10 steps minimum if our timestep was set to 0.04. If this setting was incorrectly set, that could make the frame take even longer and longer eventually hanging the game. If the accumulated time gets bigger and bigger, this phenomena is called "death spiral", and you can either recover from it or get the game to crash.

To put a limit to this madness, physics engines add the maximumTimeStep setting, which allows us to tell the engine: If you have to calculate more than X time from the previous frame, clamp it to the maximum I tell you, then calculate the rest of the time in the next frame.

So if we have 20ms of timestep and maximum timestep is 40ms, you can only execute 0, 1 (20ms) or 2 (40ms) steps each frame. The rest will be accumulated too. If too much time is accumulated, it will not be accurate or will give the impression of slow motion. If it only happens in certain moments, that will not be as problematic as destroying the fps of the game.

So, try not to accumulate too much time. If that happens, we have a serious problem, so we need to make the fixed timestep bigger so we execute less physics steps, or make our physics code more efficient inside FixedUpdate(), or make our game more efficient in general.

What are good values for fixed timestep and maximum fixed timestep?

I suggest that you leave it as it is. If you are really worried about it, your game has a lot of lag, your simulation is not accurate, your frame time needs to be improved and you see many fixedUpdates being executed which slows down your game... these are some ideas to decide:

  • Know your target platform: By default, the value is set to 0.02. That means 0.02 seconds or 20 ms. It is bigger than the typical time of a frame for games. The normal goal is 60fps for a game, that means 1/60-> 0.01666... Around 16ms per frame, if it is less time is added to make it run at that frequency. For a 90fps VR headset, you need 1/90 -> 0.011 seconds or 11 ms, which is also covered by that value. That means, we are executing 0 or 1 physics steps by frame in general. If the value is less than 11ms, there will be more executions of fixedUpdate. If your physics step takes a lot to execute there is a risk that the VR headset will cause you motion sickness due to rendering at less than 90fps.
  • Calculate more in less steps: Make fixed timestep as big as you can, testing stability of simulation until it breaks, it is sometimes subtle so take the time to test it.
  • Clamp number of steps to a maximum: Make maximumTimeStep the same or a multiple of fixed timestep value by 2, 3 or 4... The smallest the better to avoid having very variable fps in case your physics are slow to calculate.
    Example: If you have 0.02 on timestep, set the maximum to 0.02 to force it to execute only 0 to 1 fixed update each frame. If that's a problem in your case and makes the physics on your game run in slow motion at times, make it 0.04 to allow 0, 1 or 2 steps. For 0 to 3 steps, set it to 0.06. Etc.
  • Help others: Explain this to everyone around you. They will say they know. But they don't and it will be easy to find out. After that, send them a link to this post.

Hope it was useful for you. Don't hesitate to comment and send me any errors you find. My wish is that this article is useful for as many people as possible.

Until the next post.