Unity: Update Versus FixedUpdate

Yet another article on when to use the Update and FixedUpdated methods.

Image for post
Image for post

TD;LR: Having, fairly easily, recreated the problem of mixing and matching timesteps, I have convinced myself that I should put all game state in FixedUpdate methods.

Before getting into the substance of this article, wanted to clarify why I am interested in Unity in the first place:

  • I DO NOT have much interest in either playing or creating video games
  • I DO have an interest in building useful tools (been a web developer for MANY years)
  • I am NOT an early adopter
  • Unity is a WELL-ESTABLISHED solution for creating multi-platform 3D experiences

With all this in mind, building practical web-powered Augmented Reality (AR) solutions with Unity is something that I need to learn.

As for learning Unity, I DID NOT particularly find the official Unity tutorials useful. I DID find the Udemy course Learn Unity 3D for Absolute Beginners to be excellent.

I was cruising through the materials and found myself hung up on the lesson Difference between Update and FixedUpdate. Researching a bit more, the crux of the problem was that I did not understand the following rationale.

UnityUpdate and FixedUpdate — Unity Official Tutorials

A little bit more research turned up:

KinematicSoupTimesteps and Acheiving Smooth Motion in Unity

A video clip in the article illustrates the problem of mixing and matching timesteps.

Image for post
Image for post

Before following this advice I wanted to recreate the problem of mixing and matching timesteps on my own.

The final version of the project that I used in writing this article is available for download.

Update Versus FixedUpdate

We need to start with a basic understanding of the difference between the Update and FixedUpdate methods. To illustrate, we create an empty GameObject called Setup and add the following script component:

Assets/Setup.cs (incomplete)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Setup : MonoBehaviour
{
void Update()
{
Debug.Log("Update Called");
}
void FixedUpdate()
{
Debug.Log("FixedUpdate Called");
}
}

Our console output after 3 seconds looked like:

Image for post
Image for post

Observations:

  • Update is called before each render; the frequency (frame rate) of which varies based on the complexity of the rendering and the host device. Powerful computers can achieve frame rates of excess of 150fps; my development computer was running about 50fps. Below 30 fps, is considered to be a poor experience.
  • FixedUpdate is called before each internal physics update (moving things due to physics, e.g., gravity). Unity’s fixed timestep defaults to 0.02; leads to FixedUpdate being called 50 times per second.

Simulate Slow Frame Rate

In order to simulate a slow frame rate (10fps), we update the Setup.cs script as follows:

Assets/Setup.cs (incomplete)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Setup : MonoBehaviour
{
static int TARGET_FRAME_RATE = 10;
void Awake()
{
QualitySettings.vSyncCount = 0;
Application.targetFrameRate = TARGET_FRAME_RATE;
}
void Update()
{
Debug.Log("Update Called");
}
void FixedUpdate()
{
Debug.Log("FixedUpdate Called");
}
}

Our console output after 3 seconds looked like:

Image for post
Image for post

Observations:

  • Setting vSyncCount to 0 disables Unity from synchronizing renders and screen refresh rates.
  • The actual frame rate can be lower than the TARGET_FRAME_RATE due to the limitations of the host device and the complexity of the rendering.

Manual Animation

In order to observe the effect of various animations, we begin by placing a fixed cube for reference.

We add our first animated GameObject (Sphere) in front of it with the following script component.

Assets/Sphere.cs (incomplete)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sphere : MonoBehaviour {
static float SPEED = 0.1f;

void Update () {
Vector3 position = transform.position;
position.x += SPEED;
transform.position = position;
}
}

Running it with the normal frame rate:

Image for post
Image for post

Running it with 10fps frame rate:

Image for post
Image for post

Observations:

  • Obviously, we have a problem. We don’t want the animation speed to be dependent on the frame rate.
  • The problem is because we are setting the SPEED to be 0.1 units / frame; we want the speed to be measured in units / second.

The fix is to provide the SPEED in the units of units / second; 0.1 units / frame * 50 frames / second = 5 units / second. Then we use Time.deltaTime to know the time since the last call to Update. Then the distance traveled is SPEED * deltaTime.

Assets/Sphere.cs (incomplete)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sphere : MonoBehaviour {
static float SPEED = 5.0f;

void Update () {
float deltaTime = Time.deltaTime;
Vector3 position = transform.position;
position.x += SPEED * deltaTime;
transform.position = position;
}
}

With this fix in place, we get the same animation irregardless of the frame rate (but with 10fps, it is jerky as expected).

Image for post
Image for post

Having used the reduced frame rate to illustrate the need to provide speed in units / second, we can comment out the lines in Setup.cs that simulated a slow frame rate.

Animation in Physics

Instead of manually animating a GameObject, we can animate it by applying physics to it. We can animate a cylinder (moving right by 5 units / second) by:

  • Creating a Plane (called Plane)
  • Creating a Cylinder (called Cylinder)
  • Add a Rigidbody component to Cylinder (and freezing the rotation in all directions)
  • Create a physics material, Slippery, with no friction and apply it to both Cylinder and Plane
  • Start Cylinder with an initial velocity using a script component

Assets/Cylinder.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Cylinder : MonoBehaviour {
static float SPEED = 5.0f;
void Start () {
Rigidbody rb = GetComponent<Rigidbody>();
Vector3 velocity = new Vector3(SPEED, 0, 0);
rb.velocity = velocity;
}
}

With this in place, we can see that the sphere and cylinder move to the right at the same rate.

Image for post
Image for post

Observations:

  • The Sphere’s position is updated immediately prior to the render (manually in the Update method)
  • The Cylinder’s position is updated in the internal physics update.

Animation with Animation

A third way of animating a GameObject is with an animation (obviously). We can animate a capsule (attempting to move right by 5 units / second) by:

  • Creating a capsule (called Capsule)
  • Creating an animation controller (also Capsule) and adding as a component to the Capsule GameObject.
  • Creating an animation (also Capsule).
  • In the animation controller create a state (Start) with its motion to be the Capsule animation.
  • Finally, we animate the position so that the capsule’s horizontal position is 5 units in 1 second.

With this in place, we can see that the sphere, cylinder, capsule (almost) move to the right at the same rate.

Image for post
Image for post

Observations:

  • Not sure why, but the Capsule moved slightly faster than expected; trouble shot for awhile and did not figure out why.
  • The Capsule’s position can be configured to update in prior to rendering (default) or during the physics update.

Implication’s of a Fast Frame Rate

On powerful computers, one can achieve frame rates up to 150fps. On these computers with the default physics updates 50 times a second (0.02 seconds between updates), those elements that are updated before each render are updated more frequently than those updated in the physics updates. This discrepancy is the source of trouble of mixing and matching timesteps.

While I cannot increase the frame rate of my development machine (limited to about 50fps), I can artificially slow down the physics updates to 10 updates per second (0.1 seconds between updates) using the project’s settings.

Image for post
Image for post

As you can see, by mixing and matching timesteps we have recreated the problem (inconsistent movement between GameElements).

To correct, we can change the Capsule’s animation to update on physics updates, and likewise update the Sphere’s script component as follows:

Assets/Sphere.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sphere : MonoBehaviour {
static float SPEED = 5.0f;

/*
void Update () {
float deltaTime = Time.deltaTime;
Vector3 position = transform.position;
position.x += SPEED * deltaTime;
transform.position = position;
}
*/
void FixedUpdate()
{
float deltaTime = Time.deltaTime;
Vector3 position = transform.position;
position.x += SPEED * deltaTime;
transform.position = position;
}

}

With this, all the animations are consistently updated before each physics update.

Image for post
Image for post

Finally, we return our physics update to be 50fps (or every 0.02 seconds); achieving both consistent and timely updates.

Image for post
Image for post

Conclusions

Having, fairly easily, recreated the problem of mixing and matching timesteps, I have convinced myself that I should put all game state in FixedUpdate methods.

Written by

Broad infrastructure, development, and soft-skill background

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store