Working with Update & FixedUpdate

Unity runs on two clocks: Update runs once per rendered frame (a variable rate), and FixedUpdate runs at a fixed rate for physics. Most jitter, missed inputs and "physics feels different on my friend's PC" bugs come from mixing them up. This guide explains how they relate and what belongs where.

A film crew with two people. The camera operator (Update) takes a photo whenever they're ready: sometimes 30 per second, sometimes 144. The drummer (FixedUpdate) keeps a strict beat of exactly 50 per second no matter what. Physics dances to the drummer's beat. If you tell the dancer to move on camera clicks instead, the dance speeds up and slows down with the camera.

How the two loops line up

With the default fixed timestep of 0.02 s (50 steps per second):

Physics clockevery 20 ms30 FPS33 ms frames2 FixedUpdates1 FixedUpdate2 FixedUpdates144 FPS7 ms frames0 ms20 ms40 ms60 ms80 ms100 msFixedUpdate + physics stepUpdate, LateUpdate, render
The same 100 ms at two frame rates. Physics always gets 5 steps (one per 20 ms), but they're spread over whatever frames happen: several per frame at 30 FPS, and zero in most frames at 144 FPS. Anything that must happen every frame belongs in Update.

So FixedUpdate may run several times in one frame, or not at all.

What Unity does each frame

  1. Adds the real time since the last frame to an internal "accumulator".
  2. While the accumulator holds at least one fixedDeltaTime: run every FixedUpdate, step the physics simulation, send collision/trigger messages, then subtract one fixedDeltaTime.
  3. Run every Update, then coroutines, animations and LateUpdate.
  4. Render the frame.

If a frame takes very long (a loading hitch), the number of catch-up physics steps is capped by Project Settings > Time > Maximum Allowed Timestep (default ⅓ s). Without that cap, a slow frame would cause many physics steps, making the next frame slow too: a "spiral of death".

What goes where

TaskWhereWhy
Reading inputUpdate"Pressed this frame" is only true for one frame; FixedUpdate might skip it
AddForce, setting linearVelocity, MovePositionFixedUpdatePhysics steps at a fixed rate; applying forces per frame makes them frame-rate dependent
One-off impulse (jump, explosion)Either, but buffer it into FixedUpdateConsistent timing with the physics step
Moving objects without a RigidbodyUpdate with Time.deltaTimeSmooth on every frame
Timers, cooldowns, UI, game logicUpdateRuns every frame
Camera followLateUpdateEverything else has moved already
Raycasts for gameplay (shooting)UpdateReact immediately
Raycasts that drive physics (suspension, hover)FixedUpdateMust match physics steps

Pattern: read in Update, apply in FixedUpdate

using UnityEngine;

public class RollingBall : MonoBehaviour
{
    [SerializeField] private float moveForce = 20f;
    [SerializeField] private float jumpImpulse = 6f;

    private Rigidbody rb;
    private Vector3 moveInput;   // continuous input: just overwrite each frame
    private bool jumpQueued;     // one-off input: set in Update, consume in FixedUpdate

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

    void Update()
    {
        moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")).normalized;
        if (Input.GetButtonDown("Jump")) jumpQueued = true; // never set back to false here
    }

    void FixedUpdate()
    {
        rb.AddForce(moveInput * moveForce, ForceMode.Force); // continuous: every step

        if (jumpQueued)
        {
            rb.AddForce(Vector3.up * jumpImpulse, ForceMode.Impulse); // once
            jumpQueued = false; // consumed
        }
    }
}

Why a flag instead of calling AddForce directly in Update? At 144 FPS, most frames have no physics step, so the force would sit waiting anyway. At 20 FPS, several physics steps happen per frame, and a force added in Update only affects the first of them. Buffering makes behavior identical at any frame rate.

deltaTime in each method

InsideTime.deltaTime returns
Update / LateUpdateTime since the last frame (varies)
FixedUpdateTime.fixedDeltaTime (e.g. 0.02), automatically

So a function using Time.deltaTime works correctly in either. Remember that forces and velocities are already "per second": don't multiply AddForce or linearVelocity by deltaTime.

Fixing jitter: interpolation

At 144 FPS with 50 physics steps, a Rigidbody only moves on ~1 in 3 frames. The camera moves every frame. The result: the object looks like it stutters.

Interpolation is a flipbook artist drawing extra in-between pages. Physics only gives you a few key drawings per second; interpolation fills in the frames between them so the motion looks smooth.

Changing the fixed timestep

Project Settings > Time > Fixed Timestep (or Time.fixedDeltaTime in code).

ValueSteps/sEffect
0.02 (default)50Good for most games
0.01100More precise (racing, fast collisions), double the physics CPU cost
0.033330Cheaper; OK for slow-paced games and mobile

For slow motion, scale both: Time.timeScale = 0.25f; Time.fixedDeltaTime = 0.02f * Time.timeScale;. Reset both afterwards.

Advanced: many objects, one Update

Every MonoBehaviour Update is a call from Unity's engine (C++) into your C# code. With thousands of objects, that overhead adds up. A common industry pattern is a single update manager that loops over plain C# objects:

using System.Collections.Generic;
using UnityEngine;

public interface ITickable { void Tick(float dt); }

public class TickManager : MonoBehaviour
{
    private static readonly List<ITickable> tickables = new List<ITickable>();

    public static void Register(ITickable t)   => tickables.Add(t);
    public static void Unregister(ITickable t) => tickables.Remove(t);

    void Update()
    {
        float dt = Time.deltaTime;
        for (int i = tickables.Count - 1; i >= 0; i--) // backwards: safe if one unregisters
            tickables[i].Tick(dt);
    }
}

public class Drone : MonoBehaviour, ITickable
{
    void OnEnable()  { TickManager.Register(this); }
    void OnDisable() { TickManager.Unregister(this); }

    public void Tick(float dt) { transform.Rotate(0f, 90f * dt, 0f); }
}

Only worth it for large numbers (hundreds to thousands) of per-frame objects. Measure with the Profiler before and after.

Staggering expensive work

// Each enemy thinks every 5th frame, spread out so they don't all think on the same frame.
private int slot;
void Awake() { slot = Random.Range(0, 5); }

void Update()
{
    Move();                                   // cheap: every frame
    if (Time.frameCount % 5 == slot) Think(); // expensive: 1 in 5 frames
}

Common Mistakes

See also