The truth about FixedUpdate()

I’ve lately come across a few posts and questions about FixedUpdate, more specifically about using FixedUpdate() at very high frequency to have a more responsive game loop / time things more precisely.

This results from a misunderstanding of the docs, which are somewhat ambiguous:

MonoBehaviour.FixedUpdate()
Description
This function is called every fixed framerate frame

The truth is that FixedUpdate does not run at it’s own frequency. It is simply updated many times if needed right before Update, right after Time.fixedTime is, letting code in FixedUpdate pretend it runs at that fixed frequency.

Simply run the following code at a very low fixed time step to see what I mean:

void FixedUpdate()
{
      Debug.Log( "FixedUpdate realTime: "+Time.realtimeSinceStartup);
}

void Update()
{
     Debug.Log( "Update realTime: "+Time.realtimeSinceStartup );
}

You’ll notice FixedUpdate being called a bunch of times in a row right before Update, and then a gap.

Except for the audio thread, everything in unity is done in the main thread if you don’t explicitly start a thread of your own. FixedUpdate runs on the very same thread, at the same interval as Update, except it makes up for lost time and simulates a fixed time step.

Bottom line: using FixedUpdate for anything else than physics is in the vast majority of cases simply misguided. If you need to call a function a bunch of times because it’s late to the party, call it a bunch of times from Update or a Coroutine, don’t let fixedTime fool you into believing it’s called at fixed time steps. Plus increasing fixedStep will increase the cpu load that all your physics code generates, potentially nastily decreasing performance.

The docs for execution order of event functions sum it up nicely:

So in conclusion, this is the execution order for any given script:
All Awake calls
All Start Calls
while (stepping towards variable delta time)
All FixedUpdate functions
Physics simulation
OnEnter/Exit/Stay trigger functions
OnEnter/Exit/Stay collision functions
Rigidbody interpolation applies transform.position and rotation
OnMouseDown/OnMouseUp etc. events
All Update functions

40 Likes

Yeah, I’ve been saying that repeatedly for years…

–Eric

8 Likes

I think the docs on FixedUpdate itself should be more clear about that. If one digs enough, it’s apparent, but just by reading that page one could get the impression that FixedUpdate runs at it’s own frequency. The page for Time.fixedTime doesn’t help much neither…

3 Likes

I think you’re looking at this backwards. FixedUpdate is supposed to happen less often than Update. FixedUpdate tries to happen at 60fps if I recall, while your Update call happens at whatever your actual framerate is. If you turn off VSync and make a simple scene, you’ll see Update gets called many times in between each call to FixedUpdate; that’s the intention. If you’re getting multiple FixedUpdate calls in between each Update, that means your framerate is really low, and FixedUpdate is trying to make up for that by running multiple times in a row to try and fix the physics. This is “bad” though and not supposed to be the normal state of the game. Running multiple fixed updates to fix broken physics is only supposed to happen occassionally when your frame rate dips; it shouldn’t be happening constantly.

6 Likes

To me, the docs were pretty clear about how it works. It sounds like you’re maybe saying that people think if you cram an hour’s worth of computation into FixedUpdate, it will magically make it happen in .016 seconds because it’s supposed to be “fixed” at 60FPS, but I’ve seen enough episodes of Doctor Who to know that time doesn’t work like that. It makes sense that if you force it to do more than .016 seconds worth of work, it’s going to have to play catch-up.

5 Likes

Hi,

I’m reacting specifically to posts I’ve seen where users where setting a very small fixedStep to try to get a higher time precision - fixedStep of .005 to get 200 FixedUpdate() calls a second, for example. For less experienced devs, it’s easy to misunderstand the docs and to believe FixedUpdate will actually run at a 1/fixedStep frequency. In my opinion, the docs should clearly state that FixedUpdate is called just before Update, whatever the fixed step. It is only the number of times FixedUpdate will be called that changes when adjusting fixedStep, not it’s actual real time update rate. Still seeing users getting misled by this, so I figure the docs could be more explicit.

2 Likes

Yeah I guess that makes sense. It would make sense to do that if your framerate is really high and you want physics to be a little more precise, but purposefully trying to make FixedUpdate happen more often than Update kind of defeats the whole point of it.

2 Likes

Agreed. The main point I think should get across to every Unity beginner is that Unity’s game loopp runs on a single thread, and that wherever you place your method calls, wether in Update, LateUpdate, Coroutines or FixedUpdate, they won’t be called at a different frequency - except for OnAudioFilterRead, which runs on a different thread, the rate of which is dependent on audio buffer size and output sampling rate.

1 Like

Well, FixedUpdate does get called at a different frequency as long as your frame rate is higher than the fixed step (60 FPS i think). If you’re running at 180FPS, you will get three Update calls in between each FixedUpdate call.

Yep, FixedUpdate can skip frames, but that doesn’t make it frame rate independent. The point is : same thread, no benefits in using it for anything else than what it’s meant for - Physics. Wether it skips a frame or gets called multiple times during one doesn’t change that it does not run at a frequency independent of that of Update().

My! We’re finicking!

I imagine it’s basically like this:

float timer = 0;
while(true)
{
     while(timer > fixedStep)
    {
         FixedUpdate();
         timer -= fixedStep;
     }
     Update();
     timer += deltaTime;
}
3 Likes

To me, it would make sense to put anything that doesn’t need to be updated quickly in there and set a lower fixed step. So you could do pathfinding or AI in FixedUpdate, and it might improve your framerate since it wouldn’t have to compute as often. But again, this is assuming your framerate is higher than the fixed step. Doing it backwards (making it compute more often than your framerate) doesn’t make any sense; it just slows down your framerate.

  1. The default fixed timestep is .02, and 1/.02 = 50.

No, that’s a bad idea. FixedUpdate is tied specifically to physics and should only be used for physics. There are plenty of other ways to do “update every so often” that are much more appropriate and give you more control…coroutines, InvokeRepeating, threads.

–Eric

3 Likes

Also work the other way around… On a game running at 30 FPS, you get more FixedUpdate than Update.
We found having out control code in there - for our 30-40FPS mobile games - to get better/more responsive control.

We also found that FixedUpdate - if not handled properly - can destroy your framerate. Let’s say FixedUpdate is unable to perform its task under the 0.02s delta, the next frame it will try to put 2 update… and since it fails again, the next will try to push 3, etc. Of course, that should never happened, and we quickly found out why and removed the faulty code.

3 Likes

I do not notice this; I notice the opposite.

While running this test script:

double dspSamplesStart = double.NaN;

void Update()
{
 timerSamplesCheck_Upd();
}

void FixedUpdate()
{
 timerSamplesCheck_Fx_Upd();
}

void timerSamplesCheck_Fx_Upd()
{
 if(double.IsNaN(dspSamplesStart))
   dspSamplesStart = AudioSettings.dspTime;

 double time = Time.time;
 double fTime = Time.fixedTime;
 double realTime = Time.realtimeSinceStartup;
 double sTime = AudioSettings.dspTime - dspSamplesStart;
 Debug.Log("FixedUpdate: t: " + time + ", ft: " + fTime + ", rt: " + realTime + ", st: " + sTime);
}

void timerSamplesCheck_Upd()
{
 if(double.IsNaN(dspSamplesStart))
   dspSamplesStart = AudioSettings.dspTime;

 double time = Time.time;
 double fTime = Time.fixedTime;
 double realTime = Time.realtimeSinceStartup;
 double sTime = AudioSettings.dspTime - dspSamplesStart;
 Debug.LogWarning("Update: t: " + time + ", ft: " + fTime + ", rt: " + realTime + ", st: " + sTime);
}

I get the result:

FixedUpdate: t: 0, ft: 0, rt: 0.041592188179493, st: 0
Update: t: 0, ft: 0, rt: 0.0533649511635304, st: 0
FixedUpdate: t: 0.00499999988824129, ft: 0.00499999988824129, rt: 0.0570647902786732, st: 0
FixedUpdate: t: 0.00999999977648258, ft: 0.00999999977648258, rt: 0.0597184114158154, st: 0.021333333333132
FixedUpdate: t: 0.0149999996647239, ft: 0.0149999996647239, rt: 0.0620354078710079, st: 0.021333333333132
FixedUpdate: t: 0.0199999995529652, ft: 0.0199999995529652, rt: 0.0643015056848526, st: 0.021333333333132
Update: t: 0.0199999995529652, ft: 0.0199999995529652, rt: 0.0666103810071945, st: 0.021333333333132
FixedUpdate: t: 0.0249999985098839, ft: 0.0249999985098839, rt: 0.235997170209885, st: 0.192000000000007
FixedUpdate: t: 0.0299999993294477, ft: 0.0299999993294477, rt: 0.23847071826458, st: 0.192000000000007
FixedUpdate: t: 0.0350000001490116, ft: 0.0350000001490116, rt: 0.240717142820358, st: 0.192000000000007
FixedUpdate: t: 0.0399999991059303, ft: 0.0399999991059303, rt: 0.242956295609474, st: 0.192000000000007
FixedUpdate: t: 0.044999998062849, ft: 0.044999998062849, rt: 0.245275855064392, st: 0.192000000000007
FixedUpdate: t: 0.0499999970197678, ft: 0.0499999970197678, rt: 0.247482508420944, st: 0.192000000000007
FixedUpdate: t: 0.0549999997019768, ft: 0.0549999997019768, rt: 0.249757155776024, st: 0.213333333333139
FixedUpdate: t: 0.0599999986588955, ft: 0.0599999986588955, rt: 0.25208654999733, st: 0.213333333333139
FixedUpdate: t: 0.0649999976158142, ft: 0.0649999976158142, rt: 0.25441637635231, st: 0.213333333333139
...
FixedUpdate: t: 0.194999992847443, ft: 0.194999992847443, rt: 0.312763512134552, st: 0.277333333333218
Update: t: 0.198654785752296, ft: 0.194999992847443, rt: 0.315083056688309, st: 0.277333333333218
FixedUpdate: t: 0.199999988079071, ft: 0.199999988079071, rt: 0.340063631534576, st: 0.298666666666577
FixedUpdate: t: 0.204999998211861, ft: 0.204999998211861, rt: 0.342683017253876, st: 0.298666666666577
...
...
...
Update: t: 2.92386531829834, ft: 2.91999983787537, rt: 2.9623339176178, st: 2.9226666666666
FixedUpdate: t: 2.92499995231628, ft: 2.92499995231628, rt: 2.96535205841064, st: 2.9226666666666
Update: t: 2.92937564849854, ft: 2.92499995231628, rt: 2.96794056892395, st: 2.9226666666666
FixedUpdate: t: 2.92999982833862, ft: 2.92999982833862, rt: 2.97126793861389, st: 2.9226666666666
FixedUpdate: t: 2.93499994277954, ft: 2.93499994277954, rt: 2.97814989089966, st: 2.9226666666666
Update: t: 2.93528437614441, ft: 2.93499994277954, rt: 2.98049831390381, st: 2.94399999999996
FixedUpdate: t: 2.93999981880188, ft: 2.93999981880188, rt: 2.98562502861023, st: 2.94399999999996
FixedUpdate: t: 2.9449999332428, ft: 2.9449999332428, rt: 2.98832273483276, st: 2.94399999999996
Update: t: 2.9496214389801, ft: 2.9449999332428, rt: 2.99067115783691, st: 2.94399999999996

Ellipses represent omissions.
Most of the time, all time variables update, and fixedTime definitely seems to update at regular intervals (mostly).
The only time variable that seems to not be very good at updating every FixedUpdate() is AudioSettings.dpsTime.
Ran in Unity Editor 4.6.1f1, Windows 7 x64, fixed timestep 0.005, Max timestep 0.3333333

Edit:

I removed one line from the result log I posted because I realized it was a duplicate (I’m still looking at the actual log).

Just log a delta of realtimeSinceStartup from FixedUpdate, and you’ll see what I mean. Does it correspond to fixedDeltaTime? Nope…

1 Like

Never heard of a lot of this.
Somewhere I was told when I started that FixedUpdate was for physics so that’s all I ever did inside it lol.
Good info to know regardless.

1 Like

This comes as no surprise to anyone who read the docs.

This is the key reason that FixedUpdate is for physics, and anything that needs to be synced to the physics loop.

As usual for Unity execution is linear. Nothing is ever truest simoltaneous. And very few things use their own thread.

1 Like

This all depends if your game is more dependent on physics or rendering. I’ve built simulations where physics fidelity is far more important then rendering speed. FixedUpdate is meant to run at a constant time step. Speed relitive to rendering is irrelevant.

I want to use FixedUpdate() at very high frequency to have a more responsive game loop and then find this page…I try InvokeRepeating and it’s the same as FixedUpdate. How can I have a more responsive game loop?