Lesson 54 - Understanding FixedUpdate vs. Update

Tutorial Series: Introduction to Unity with C# Series

Previous Article  |  Next Article


Transcript

In the previous lesson, we looked at the basics of Unity’s physics engine, which pretty much centers around these different aspects. Rigidbodies via the attached Rigidbody component, Colliders via the Collider component, Collision Layers to determine what colliders collide with each other, and controlling physics behavior using FixedUpdate(). Out of all of these concepts, the least intuitive, and the one we spent the least time understanding, was how FixedUpdate() works. Particularly of interest is what code belongs in FixedUpdate() versus in Update(). So in this lesson, I'm going to spend much of the time explaining the important differences between FixedUpdate() and Update() and the simple rules of thumb to follow when choosing which one to use, and how to get them sort of play nice with one another. So what do we know about FixedUpdate()? Once again, it runs just like the normal Update() method. So in a loop-like pattern, except FixedUpdate() runs on a fixed time interval, running every .02 seconds. So basically 50 frames per second. So if the game runs at, say a steady 60 frames per second, we know that we’ll have 60 Update()s, and we’ll have 50 FixedUpdate()s within that second if it runs at 30 frames per second. That will have once again 50 FixedUpdate()s but we’ll have thirty Update()s within the second. Now, to see the progression of how updates in FixedUpdate()s are called, just attach a simple script to a GameObject and in the script, have the Debug.Log() output “Update” in quotes in the Update() method. While the Debug.Log() outputs, “FixedUpdate” in quotes in the FixedUpdate() method. Then run the game and watch the console to see the pattern of Update() versus FixedUpdate() calls. Then simply change the FPS, the framerate within the application settings to see how this changes the pattern, making for more Update()s than FixedUpdate()s at 60 frames per second, or less Update()s than FixedUpdate()s at 30 frames per second, for example.

So let's take a closer look at the resulting pattern that you get when you do this and that you’ll see in the console. How do we think about the sequence of FixedUpdate() and Update()? Intuitively, you might just picture it as a continuous stream that eventually ends up, you know, out of sync, at some point. But what ends up happening when the framerate remains steady, is that you get this looping pattern within the broader loop, rather than a continuous stream where you would probably picture not much of a pattern occurring, due to the ever-changing difference in time interval between Update() and FixedUpdate() calls. I think studying this looping pattern a bit will give you some insight on how Update() versus FixedUpdate() run alongside each other. One of the most obvious features of the pattern that gets produced is that there is an unevenness between the Update() and FixedUpdate() calls. Depending on the frequency of Update() calls, you might get one FixedUpdate() between Update() calls, or you could get a bunch of FixedUpdate()s between Update() calls or you can even get no FixedUpdate() calls between Update() calls, in the case of the game running at 60 frames per second. So running our test script at 60 frames per second, let's then match up what we see output to the console with a visualisation for it. When the game first runs, you'll briefly see a bunch of FixedUpdate()s run, one after the other and then the engine will sort of settle into a looping pattern that we've been talking about. The pattern seen here, when the game is running at a steady 60 frames per second, is particularly demarcated by the point where we have two Update()s run one after the other, and no FixedUpdate() in between. The pattern then starts again once again like a loop within a loop. So put aside the visualization of a continuous stream, where it's kind of hard to imagine the relationship between Update()s and FixedUpdate()s and where it all ends up exactly. And instead visualize the pattern with this sort of loop within the loop behavior, as something like this Note that the precise time intervals between Update() and FixedUpdate() are not really accurately visually represented here. That’s difficult to represent and not really important for the general point being made.

So with this pattern being produced, we see that there is some regularity despite the differences between Update() and FixedUpdate(), even at lower frame rates. In other words, we typically get at least one FixedUpdate() after every Update(), sometimes more if the framerate is lower. So you maybe get the sense that Update()s and FixedUpdate()s aren't wildly out of sync. But nonetheless, you might think that any irregularity between the two is a big problem. In other words, if we can't accurately predict how many FixedUpdate()s run between Update()s if the framerates are changing, how do we create a world that appears predictable and deterministic and running in sync? Well here's why the difference of more or less FixedUpdate()s between Update()s doesn't matter. It doesn't matter as long as FixedUpdate() is only used to make physics calculations. I'm going to repeat this, because the point is crucial. It doesn't matter if you have two FixedUpdate()s between Update() calls, or twenty FixedUpdate()s between Update() calls, as long as you're only putting physics calculations in FixedUpdate(). That's because the way that physics is calculated over time doesn't change with more or less intervals used to make those calculations. It's kind of like, say calculating how far your car has traveled doesn't matter if you use meters or kilometers. Meters offers a more accurate matter measurement because its intervals are more frequent than that of kilometers. But doesn't change the fact of how far the car traveled given a velocity over time. The reason for this is because there's a back drop in the real world, I'm talking now of fixed time progression. Time, in other words, doesn't meaningfully change; relativity notwithstanding for you fellow science geeks out there. But that aside, if the velocity over a set time is all that determines where the car should be and it's all the same, otherwise whether or not using meters or kilometers to measure the exact place of the car would be.

So my analogy may or may not be one to one, but that's kind of how you can think about FixedUpdate(). More FixedUpdate()s only makes for more precise or smoother physics calculation. So this is why we use FixedUpdate()s for calculating physics changes, it offers a fixed time step which models that backdrop of linear time in the real world. So in many ways, FixedUpdate() works in the opposite way then we've come to learn that Update() works. We use tricks like Time.deltaTime in Update() to make the Update() loop appear deterministic. By deterministic I mean, you know, objects following a predictable movement and behavior pattern. Regardless of the amount of Update()s, so there's constant time in the background, the sense of that. And that's basically just a nifty illusion. Whereas in FixedUpdate() and working with physics calculations, we're not just creating the appearance, but actually modeling the underlying forces that create that appearance. Would it make sense in this modeling to use something like Time.deltaTime like we did in Update(), increasing an object’s velocity, for instance when the framerate lowers? Of course not, what force in nature would logically explain that additional velocity? If anything, you'd expect the opposite, that the object would appear to slow down if the timescale were to slow down. So that's why FixedUpdate() operates sort of like a steady beat of a drum in a song. No steady beat, no song. So no fixed time interval, no physics modeling. Science needs fixed intervals, a ruler isn't a ruler unless the spaces between the units of measurement are consistent. OK I think I think I'm probably done beating that point home of why FixedUpdate() needs to be a constant time interval. So actually implicit in all this is that the frequency of that interval, it can be faster or slower and actually that frequency can be set in the Project Settings time dialogue, but it's best to just leave that alone. It's kind of optimal for processing and whatnot, for our purposes every .02 seconds. So anything in code that changes the value of a physics object, velocity, force and such are all that goes into FixedUpdate().

We’ll demonstrate all this a little more later, but just keep in mind as the first rule: physics stuff in FixedUpdate(), non-physics stuff in Update(). I’ll also go into more in-depth and into what constitutes physics stuff vs non-physics stuff in a bit, but sometimes the distinction is a bit blurry. For example, what if you have user input that is used to determine a physics calculation, like pressing a button to make the player move for example? User input is definitely non-physics code, so it should belong in Update(). But the physics stuff that ends up happening due to that user input, for example increasing the Rigidbody velocity, definitely does belong FixedUpdate(). This is probably the trickiest sort of interplay between the two methods that you’ll come across, and thankfully it's not too difficult to bridge this gap. So let's see what happens when we put the user input along with the physics calculation. It sets off all in FixedUpdate(). Here we’re using user input to determine whether or not a force is applied. The trouble is, inputs are pulled in the background at the framerate that the game is running at, not the fixed time step of FixedUpdate(). So in other words, you can think of it as inputs being read at the same rate as Update() cycles. So the game is running at 60 frames per second we’ll get a dropped input, in the case where we saw earlier where there is no FixedUpdate() between the two Update()s. We saw that that's actually pretty often. In fact, at 60 frames per second, roughly between every fifth and sixth Update() call within that looping pattern that we saw earlier. So picture it this way: if your input is read on the fifth Update(), it will only be true for that Update() cycle. Since GetKeyDown() only returns true on that frame that the input was read, and on the next Update() cycle it will become false and then when the next FixedUpdate() runs, it will then catch that input and will read it as false.

Now if the game is running at 30 frames per second, this problem probably won't occur because there should always be a FixedUpdate() run after every Update() since fixed will run more frequently than Update(). But this is still a problem because, as we saw, it's difficult to guarantee a steady framerate because that's platform specific. Framerates ultimately depend on the power of the underlying platform, so that can't always be guaranteed. So to combat this, you might want to set something like a flag, a state in other words, for inputs that were read in Update() and that FixedUpdate() will later act upon, something like this. But here again, we have the same problem as we had before if the game is running at 60 frames per second, then we still have the same issue of dropped inputs because of there being no FixedUpdate() between every fifth and sixth Update() frame. In this case, upForceFlag will be flipped to false after every sixth Update() and will result in FixedUpdate() not applying the force. But now we have a problem even at lower frames per second since we have two FixedUpdate() cycles between some Update() cycles. At 30 frames per second for example, and even more lower frames per second, the force gets applied twice in those instances. This would result in a higher or lower jump depending on how many FixedUpdate()s were called between Update()s. So the solution of this is to use Update() to set the flag to true, and then use FixedUpdate() to set the flag to false as soon as it's been detected by a FixedUpdate(). This has the effect of sort of caching or storing the input state across successive Update() cycles if FixedUpdate() doesn't occur between those cycles. So now that I've shown you the most tricky scenario probably of handling the interplay between Update()and FixedUpdate(), usually when handling user inputs that have an effect on physics, and you now know to keep physics stuff in FixedUpdate() and non-physics stuff and Update().

The obvious question at this point is, what exactly constitutes physics stuff? How do how do you know what is calculated using the physics engine and what's not? Well basically anything to do with affecting a Rigidbody is a physics calculation, particularly if it occurs continuously over a series of frames. There are a few cases where you're not really calculating anything, you're just sort of setting a physics value, such as making an object grind to a halt on a single frame, say by making its velocity 0. In that case it's probably OK to do that in Update(). There isn't anything being calculated or successive frames, so that's probably OK. That was a bit of a mouthful, I don't mean for this lesson to scare you off. The last thing I want is for you to sort of walk away from this thinking all of this just sounds way too over-complicated to bother with. In some ways it probably sounds a lot more difficult than it is in practice. When you actually start to work with the physics engine and see the results on your screen, I find that intuition kind of takes over and should make a lot more sense. So please stick with me in the next few lessons. I think you'll find that the tradeoff is worth it, you'll see that you end up getting a lot of really cool functionality that would otherwise be very complicated without using the physics engine, in exchange for just being a bit more careful with how you use FixedUpdate(), and maybe not always understanding how this magic is happening under the hood. Magic of all these modeled physics calculations occurring in some black box somewhere deep in Unity. And ultimately you can make so many cool things happen with such little code, that it’s just too tempting to ignore the physics stuff.

In the end, this stuff kind of seems like magic, how Unity gets it all working and you don't really have to think of all that much from all these different angles, and just kind of go with your intuition and have fun in the process. And honestly, most the time if you come across a bug, all you have to do is see if your game is working at 60 frames per second and 30 frames per second. If there are bugs or any major differences between these two extremes, you sort of at that point would want to sort out the bug. But otherwise, if it all works, which it often does without it being obvious why it's working. Don't sweat it, Unity does a good job of keeping things running even if you don't understand it all. So that's about it for the primer on physics and FixedUpdate(). For our part, we already looked at probably the biggest “gotchas” with the physics engine. And in the next lesson, we’ll start rapidly developing our game using these new concepts. See you there.


Related Articles in this Tutorial:

Lesson 1 - Who This Course is For

Lesson 2 - What to Expect from this Course

Lesson 3 - Installation and Getting Started

Lesson 4 - Starting the First Project

Lesson 5 - Prototype Workflow

Lesson 6 - Basic Code Review

Lesson 7 - Game Loop Primer

Lesson 8 - Prototyping Continued

Lesson 9 - C# Fundamentals and Hello World

Lesson 10 - Variables and Operations

Lesson 11 - Variables and Operations Continued

Lesson 12 - Floats, Bools and Casting

Lesson 13 - If Statement Conditionals

Lesson 14 - If Statements Continued

Lesson 15 - Complex Evaluations and States

Lesson 16 - Code Syntax vs. Style

Lesson 17 - Variable Scope

Lesson 18 - Object-Oriented Programming Intro

Lesson 19 - OOP, Access Modifiers, Instantiation

Lesson 20 - Object Containment and Method Returns

Lesson 21 - "Has-A" Object Containment

Lesson 22 - "Is-A" Inheritance Containment

Lesson 23 - Static Fields and Methods

Lesson 24 - Method Inputs and Returns

Lesson 25 - Reference vs. Value Types

Lesson 26 - Introduction to Polymorphism

Lesson 27 - Navigating the Unity API

Lesson 28 - Applying What You've Learned and Refactoring

Lesson 29 - Constructors, Local Variables in the Update Method

Lesson 30 - Collecting Collectibles, Items and Powerups

Lesson 31 - Spawning and Managing Prefab Powerups

Lesson 32 - Implementing Powerup State Logic

Lesson 33 - Displaying Text, OnGUI, Method Overloading

Lesson 34 - Referencing Instantiated GameObjects, Parenting

Lesson 35 - Understanding the Lerp Method

Lesson 36 - Creating Pseudo Animations in Code

Lesson 37 - Understanding Generic Classes and Methods

Lesson 38 - Animations Using SpriteSheets and Animator

Lesson 39 - Working with Arrays and Loops

Lesson 40 - Debugging Unity Projects with Visual Studio

Lesson 41 - Camera Movement and LateUpdate

Lesson 42 - Playing Audio Clips

Lesson 43 - Routing Audio, Mixers and Effects

Lesson 44 - Adding Scoring Mechanics and Enhancements

Lesson 45 - Scene Loading and Game Over Manager

Lesson 46 - Understanding Properties

Lesson 47 - Controller Mapping and Input Manager

Lesson 48 - Understanding Enums

Lesson 49 - Dealing with Null References

Lesson 50 - Handling Variable Framerates with time.DeltaTime

Lesson 51 - Preparing the Project for Final Build

Lesson 52 - Final Build and Project Settings

Lesson 53 - Introduction to the Unity Physics Engine

Lesson 54 - Understanding FixedUpdate vs. Update

Lesson 55 - Movement Using Physics

Lesson 56 - Attack Script and Collision Events with OnCollisionEnter2D

Lesson 57 - Projectiles and Stomping Attack

Lesson 58 - Parallax Background and Scrolling Camera

Lesson 59 - Infinitely Tiling Background Sprites

Lesson 60 - OOP Enemy Classes

Lesson 61 - OOP Enemy Classes Continued

Lesson 62 - Trigger Colliders and Causing Damage

Lesson 63 - Multi-Dimensional Arrays and Procedural Platforms

Lesson 64 - Finishing Touches

Lesson 65 - Series Wrap


Comments

Please login or register to add a comment