When the first video games were created, computers were simple – at least compared to modern machines. A properly written program running on a C64 or a Gameboy could rely on a rather consistent computation power. And a game would have its calculations designed in a way that worked for the resulting framerate.
Today, computers, consoles and even phones are powerful machines that have the capability to compute many things at once. PCs usually have dozens of programs running in addition to background tasks and a programmer cannot make any assumptions about the actual computation power available to the program.
As a result, framerates cannot be predicted, and games have to be able to run properly with 30, 60 or 144 frames per second (“fps”) – and anything inbetween. Games ported from consoles where this isn’t an issue quite as much stand out every now and then for having varied player experience depending on computation power.
This article sheds some light on FixedUpdate
, which is a concept that allows you to build framerate-independent game simulation. It’s beneficial to fully understand what it is… and what it isn’t.
About Time.deltaTime
Probably the most basic event Unity beginners get to know is “Update
“. Update
is called once every frame on every active component in the scene. It can be used for pretty much anything in a game. Moving or rotating an object, changing a light color, noticing a button being pressed and reacting accordingly… everything.
If we were to move an object by one meter in Update
, it would move one meter with every frame the game renders. If we had 30 frames per second, we’d move 30 meters per second. With 60 fps, we’d move 60 meters in the same time. This is obviously unacceptable, as the gameplay drastically changes with a value neither the programmer nor the player usually has any control over.
When someone first gets into game development with Unity, one of the first things they learn is that there is this thing called “Time.deltaTime
” telling them how much time it took the machine to compute the most recent picture on the display. This includes simulating the game world as well as rendering the image.
Multiplying a value with Time.deltaTime
basically means adding a “per second” to it. If we have 30 fps, Time.deltaTime
‘s value is 1/30, and moving 1/30m 30 times means moving 1m within one second. With twice the fps, Time.deltaTime
is half as high, so we move twice as often, but each time we move only half as far. This means that after a second, we always have moved one meter.
However, this concept is limited to linear processes. A continuous motion, be it movement, rotation or anything else, works fine with this approach. But if we add another dimension, like an object being thrown into the air and gravity pulling it down, this doesn’t work anymore.
To visualize this, consider this ball jumping forward.
With a high framerate, the ball will update its direction very often. With a low framerate, gravity can only be applied a few times during the flight. And even if Time.deltaTime
is used for both the movement and the applied gravity, the frequency of updates to a non-linear process matters. Time.deltaTime
cannot solve this problem.
FixedUpdate to the rescue
Sooner or later, one stumbles upon the FixedUpdate
event. Unity’s scripting reference says:
0.02 seconds (50 calls per second) is the default time between calls.
Unity Scripting Reference about FixedUpdate
And this can be dangerously misleading. It might sound as if Unity manages to magically enforce a call every 0.02 Seconds (or whatever the fixed timestep is set to), but this is not the case. The scripting reference uses this terminology because it’s okay to assume this would be how it works… for now.
In reality, FixedUpdate
works like this.
Unity has a stopwatch running in the background that measures time as it passes. Before every Update
, that stopwatch is checked. If the passed time is higher than the fixed timestep (e.g. 0.02 seconds), a FixedUpdate
is triggered, and the stopwatch’s timer is reduced be the fixed timestep.
In other words: Unity checks the time before every Update
, and if it notices that it actually should have triggered a FixedUpdate
by now, it does so. This goes even further as Unity might notice that multiple FixedUpdates
would have already been in order. In this case, it triggers multiple FixedUpdates
in a row without doing anything else inbetween – like redrawing the game or calling Update.
Through this, we get a cycle that will try to run every 0.02 seconds by catching up to the amount of FixedUpdate
s we should have had by now.
In addition to this, within FixedUpdate
, Time.deltaTime
switches to return nothing but the fixed timestep value. So if we handle FixedUpdate
just like we handle Update, we can run something with a seemingly constant framerate and let our objects behave like it was real.
Thus, FixedUpdate
should be used for all non-linear processes that are relevant to gameplay, in order to ensure that every player has the same gameplay regardless of their hardware power.
Issues with FixedUpdate
What may seem like a reason to never use Update
again comes with some drawbacks… which we can handle.
First off, the game still draws itself onto the player’s screen with every Update. If there’s multiple Updates between two FixedUpdate
s because the framerate is high, the player will be able to see that an object didn’t get (fixed)updated between two frames. This means a visible stutter effect.
This issue can be solved with a script I wrote some time ago and used and maintained ever since: FixedUpdateInterpolation. You can add it to your project and add it to any GameObject
that is moved or rotated in FixedUpdate
. What it does is to identify where between two FixedUpdate
s the time is in Update, and to interpolate between the two. An object moving in FixedUpdate
will move between its previous and its current position with every rendered frame. Rigidbody
and Rigidbody2D
components offer the same functionality with their Interpolate property.
Secondly, input happens each Update
. And whether there’s multiple Update
s between two FixedUpdate
s due to a high framerate, or multiple FixedUpdate
s between two Update
s due to low fps, checking input within FixedUpdate
will lead to lost button presses or a button press counting multiple times.
This problem can be solved by adding some additional code for buffering button presses:
private bool jump; private void Update() { if (Input.GetButtonDown("Jump")) { jump = true; } } private void FixedUpdate() { if (jump) { Jump(); jump = false; } }
Note that this is only necessary for button presses and releases. When you ask whether a button has just been pressed, you will only get back a “yes” in the first Update
after the button press. If there is another Update
after that, the button will not count as “freshly pressed” anymore, and if your FixedUpdate
call comes after that, you won’t even notice that a button was pressed inbetween.
If a button is held over a time, or if you check a joystick’s analog output, this isn’t needed, as the state of that input doesn’t change after an update.
A small update: The InputSystem package has a built-in solution for polling button presses in FixedUpdate, so using that is a good idea.
Implementing your own FixedUpdate
To get a better understanding, or even for actual uses in your project, you can rather easily create your own FixedUpdate
cycle with code like this:
public float fixedTimestep = 0.02f; private float timeSinceLastFixedUpdate = 0f; private void Update() { timeSinceLastFixedUpdate += Time.deltaTime; // Call MyFixedUpdate as often as needed to catch up while (timeSinceLastFixedUpdate >= fixedTimestep) { MyFixedUpdate(); timeSinceLastFixedUpdate -= fixedTimestep; } } private void MyFixedUpdate() { // For example: transform.Translate(Vector3.forward * fixedTimestep); }
Note how “fixedTimestep
” is used instead of Time.deltaTime
in “MyFixedUpdate
“.
Conclusion
FixedUpdate
allows you to create games that offer the same gameplay experience for any reasonable framerate. This is not possible with Update and Time.deltaTime
– unless all your gameplay processes are linear. And they never are.
But it’s important to understand how FixedUpdate
really works and that certain aspects of it can lead to undesirable effects or hard-to-reproduce bugs. Learning how to work with FixedUpdate
is an essential part of making a good game, so make sure you know it in and out!
A small update on this article…
After having stumbled upon this thread in the Unity forums, it sounded like there’s advice given to not use FixedUpdate
for anything but physics. The first post contains what I would call at least very badly worded, if not just incorrect information, and the second post agrees, although the argument of that user is a different one later on.
Long story short: FixedUpdate
, as described in this article, is a concept. When I recommend to use it for everything deterministic, that doesn’t mean you have to use Unity’s builtin FixedUpdate
method. Just like a changing framerate can change the game experience, so can changing the fixed timestep at some point in development. And if you do different things in a “FixedUpdate
-like structure”, it might be a good idea to have multiple fixed timesteps. Using only the builtin FixedUpdate
doesn’t directly allow you to do that. In the long run, with sufficient project complexity (!), it is a useful idea to roll your own FixedUpdate
(like described above) and keep only the physics-related code in Unity’s builtin FixedUpdate
event.