UPDATE VS FIXEDUPDATE VS LATEUPDATE IN UNITY

A complete engineering comparison of Unity's three core update loops, execution timing, input polling rules, and physics synchronization.

1. High-Level Comparison Summary

Update() — Render Frame
Frequency: Variable (Runs once per rendered visual frame).
Primary Use: Polling player inputs (Input.GetKeyDown), updating non-physics game timers, UI animations, and mesh rotations.
Delta Time: Time.deltaTime
FixedUpdate() — Physics Step
Frequency: Constant (Fixed 50Hz / 0.02s by default).
Primary Use: Applying Rigidbody.AddForce(), setting physical velocity, torque, wheel colliders, and Raycast sweeps.
Delta Time: Time.fixedDeltaTime
LateUpdate() — Post Processing
Frequency: Variable (Runs immediately after all Update() calls finish).
Primary Use: Follow cameras, third-person tracking rigs, head-look IK, and screen-space overlay clamping.
Delta Time: Time.deltaTime

2. The Critical Pitfall: Polling Inputs in FixedUpdate

One of the most common bugs in Unity is reading Input.GetKeyDown(KeyCode.Space) inside FixedUpdate().

Because Update() runs with every screen refresh (e.g. 120 FPS = 8.3ms per frame) while FixedUpdate() runs at 50 FPS (20ms), multiple render frames can pass between physics steps. If a player taps the jump button during a frame where FixedUpdate does not tick, Unity resets the one-frame keydown flag and the jump is completely eaten!

The Solution: Always capture input flags in Update(), and consume them inside FixedUpdate():

using UnityEngine;

/// <summary>
/// Correctly synchronizes instantaneous player jump input with Rigidbody physics.
/// </summary>
public class CorrectJumpController : MonoBehaviour
{
    [SerializeField] private Rigidbody rb;
    [SerializeField] private float jumpForce = 8f;

    private bool jumpRequested;
    private float horizontalInput;

    private void Awake()
    {
        if (rb == null) rb = GetComponent<Rigidbody>();
    }

    // 1. Capture inputs every frame in Update
    private void Update()
    {
        horizontalInput = Input.GetAxisRaw("Horizontal");

        if (Input.GetButtonDown("Jump"))
        {
            jumpRequested = true; // Store request until next physics tick
        }
    }

    // 2. Apply physical impulses in FixedUpdate
    private void FixedUpdate()
    {
        // Continuous movement force
        rb.AddForce(new Vector3(horizontalInput * 15f, 0f, 0f), ForceMode.Force);

        // Instantaneous jump impulse
        if (jumpRequested)
        {
            rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
            jumpRequested = false; // Reset request flag
        }
    }
}

3. Why Follow Cameras Must Use LateUpdate()

If your player moves in Update() and your camera also moves in Update(), Unity does not guarantee script execution order. In some frames, the camera will read the player's position before the player moves; in other frames, it will read it after. This creates noticeable micro-jitter and screen tearing.

Placing camera tracking in LateUpdate() guarantees the target character has completely finished moving for that frame before the camera calculates its target interpolation.

Related Topics & Troubleshooting

Frequently Asked Questions

Yes. Navigate to Edit > Project Settings > Time and adjust Fixed Timestep. The default is 0.02 (50 Hz). For high-precision simulation games or esports combat, setting it to 0.016666 (60 Hz) or 0.01 (100 Hz) improves collision accuracy at the cost of higher CPU consumption.
Yes. When a script defines void Update() { }, Unity adds that MonoBehaviour to the engine's native update loop list. If you have 5,000 enemy or projectile objects with empty Update() methods, traversing the C++ to C# boundary causes unnecessary CPU overhead. Always delete unused default MonoBehaviour templates!