Unity Term Book
Scripting & Lifecycle

Update & Lifecycle

Unity's main game loop: Update runs every frame, FixedUpdate on a fixed Physics timestep, and LateUpdate after every Update — pick the right hook for each job.

Imagine...

Update is an analog clock that ticks with FPS — for anything the eye sees: movement, input, AI. FixedUpdate is a digital clock with a steady beat (0.02s) — for physics so motion does not jitter. LateUpdate runs last — the Camera waits until everything has moved, then follows, avoiding a one-frame hitch.

The concept in detail

Update() runs every frame — frequency follows FPS (30, 60, 120…). Multiply movement/speeds by Time.deltaTime so results stay consistent across frame rates.

FixedUpdate() runs on Time.fixedDeltaTime (default 0.02s = 50/sec). Independent of FPS. Use it for Rigidbody.AddForce(), Rigidbody.velocity, Physics queries. One render frame may map to 0, 1, or many FixedUpdates.

LateUpdate() runs after every script’s Update() in that frame. Ideal for Camera follow (player already moved), IK, and any logic that must “read” post-Update results.

OnGUI() is legacy. Update vs coroutine: one-shot or delayed logic → prefer a Coroutine over polling every frame in Update.

Diagram: Order inside one frame

⏰ Physics Timestep Accumulation

FixedUpdate() × N

N = accumulated timesteps from the previous frame — usually 0 or 1, more if lagging

📥 Input Processing

Update() — all scripts

Input, AI, game logic, animation triggers

LateUpdate() — all scripts

Camera follow, IK, post-Update logic

🎨 Rendering (Culling → Drawing → PostFX)

Hands-on steps

1

Always multiply by Time.deltaTime in Update

transform.position += speed * Time.deltaTime * direction — units per second, FPS-independent.

2

Physics forces → FixedUpdate

Put AddForce() and velocity in FixedUpdate. Read Input in Update, apply in FixedUpdate.

3

Camera follow → LateUpdate

Camera scripts use LateUpdate so the player has already moved — no one-frame lag.

4

Delete unused Updates

Even an empty Update has overhead. Prefer Events or Coroutines when you do not need every frame.

Interactive simulator

Press Run to step through the frame loop. Adjust FPS and Physics rate.

FixedUpdate

0

calls

Update

0

calls

LateUpdate

0

calls

Render

0

frames

Current step: Idle
Frame: 0|Time: 0.00s|Phase: Stopped

Code example

Basic

Split logic correctly across Update, FixedUpdate, and LateUpdate.

public class PlayerMovement : MonoBehaviour
{
  [SerializeField] private float speed      = 5f;
  [SerializeField] private float jumpForce  = 8f;
  private Rigidbody _rb;
  private Vector3   _moveDir;
  private bool      _jumpRequest;

  void Awake() => _rb = GetComponent<Rigidbody>();

  void Update()
  {
      // Input — every frame, store for FixedUpdate
      float h = Input.GetAxisRaw("Horizontal");
      float v = Input.GetAxisRaw("Vertical");
      _moveDir = new Vector3(h, 0, v).normalized;

      if (Input.GetButtonDown("Jump")) _jumpRequest = true;
  }

  void FixedUpdate()
  {
      // Apply physics — do not use Time.deltaTime here
      _rb.velocity = new Vector3(_moveDir.x * speed, _rb.velocity.y, _moveDir.z * speed);

      if (_jumpRequest)
      {
          _rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
          _jumpRequest = false;
      }
  }
}

public class CameraFollow : MonoBehaviour
{
  [SerializeField] private Transform target;
  [SerializeField] private Vector3   offset = new Vector3(0, 5, -8);

  void LateUpdate()
  {
      // After target.Update() — target pose is final
      transform.position = Vector3.Lerp(transform.position,
          target.position + offset, Time.deltaTime * 5f);
  }
}

Code example

Advanced

Prefer Coroutines over Update for logic that should not run every frame.

public class EnemyAI : MonoBehaviour
{
  private Transform _player;
  private float _attackCooldown = 2f;

  void Start()
  {
      _player = GameObject.FindWithTag("Player").transform;
      // AI tick every 0.2s instead of every frame → saves CPU
      StartCoroutine(AIUpdateLoop());
      StartCoroutine(AttackLoop());
  }

  // Run AI logic 5×/sec instead of 60×/sec
  private IEnumerator AIUpdateLoop()
  {
      var wait = new WaitForSeconds(0.2f);
      while (true)
      {
          UpdatePathfinding();
          yield return wait;
      }
  }

  private IEnumerator AttackLoop()
  {
      while (true)
      {
          yield return new WaitForSeconds(_attackCooldown);
          if (Vector3.Distance(transform.position, _player.position) < 3f)
              Attack();
      }
  }
}

📌 Quick recap

  • * Time.deltaTime for all movement in Update
  • Physics force/velocity → FixedUpdate (no deltaTime needed)
  • Camera follow → LateUpdate (wait for player movement)
  • Sparser logic → Coroutine + WaitForSeconds

⚠️ Common mistakes

  • ❌ Moving transform in FixedUpdate without Time.fixedDeltaTime

    Speed depends on physics rate — inconsistent

    ✅ Multiply by Time.fixedDeltaTime or use MovePosition()

  • ❌ Reading Input inside FixedUpdate

    GetKeyDown can be missed on fast frames

    ✅ Read Input in Update, store a flag, apply in FixedUpdate