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
FixedUpdate() × N
N = accumulated timesteps from the previous frame — usually 0 or 1, more if lagging
Update() — all scripts
Input, AI, game logic, animation triggers
LateUpdate() — all scripts
Camera follow, IK, post-Update logic
Hands-on steps
Always multiply by Time.deltaTime in Update
transform.position += speed * Time.deltaTime * direction — units per second, FPS-independent.
Physics forces → FixedUpdate
Put AddForce() and velocity in FixedUpdate. Read Input in Update, apply in FixedUpdate.
Camera follow → LateUpdate
Camera scripts use LateUpdate so the player has already moved — no one-frame lag.
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
Code example
BasicSplit 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
AdvancedPrefer 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.deltaTimefor 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