Lesson 16 +10 XP

Lifecycle Event Functions

Lifecycle Event Functions

Unity scripts do not execute like standard C# programs with a Main() entry point. Instead, the Unity engine controls execution by calling special, built-in methods (known as Event Functions) at precise moments in a GameObject's lifespan.

1. The Execution Lifecycle Flow

Understanding the exact order of these events is critical to avoiding null references and game loop glitches. Here is the chronological order:

[Object Instantiated / Loaded]
         │
         ▼
     Awake()           <-- Runs once when object is initialized (even if script is disabled)
         │
         ▼
    OnEnable()         <-- Runs every time the script or GameObject is turned ON
         │
         ▼
     Start()           <-- Runs once before the first frame update (only if script is enabled)
         │
  [Gameplay Loop] <───┐
         │            │
         ├─► FixedUpdate() <-- Runs on a fixed physical timer (0.02s default) for physics
         │            │
         ├─► Update()      <-- Runs once per frame (variable time) for inputs/logic
         │            │
         └─► LateUpdate()  <-- Runs once per frame, AFTER all Updates (useful for cameras)
         │
    OnDisable()        <-- Runs every time the script or GameObject is turned OFF
         │
         ▼
    OnDestroy()        <-- Runs once when the object is deleted or scene unloaded

2. Initialization Events: Awake vs. Start

  • Awake(): Executed immediately when the scene loads or when a prefab is instantiated. Use this to configure self-references (e.g., getting a Rigidbody component on the same object). It runs even if the script is disabled.
  • OnEnable(): Triggered immediately after Awake (or whenever the object goes from inactive to active). Excellent for registering event listeners.
  • Start(): Executed right before the script's first frame update. Use this to reference other GameObjects or query external scripts (since their Awake methods are already guaranteed to have finished running).

> [!WARNING] > Race Conditions: If Script A tries to read a variable in its Start method that Script B initializes in its own Start method, the outcome depends on random execution order. Initialize variables in Awake, and read/connect them in Start to completely eliminate this issue.

3. Update Events: Physics vs. Rendering

  • Update(): Runs once every frame. Because frame rates fluctuate depending on the hardware performance and scene complexity, the time between frames is variable. Never calculate physics forces here.
  • FixedUpdate(): Runs on a reliable, fixed timer (default is 0.02 seconds, adjustable in Project Settings). Because it does not fluctuate with frame rate, all physical forces, velocity calculations, and Rigidbody interactions must occur inside FixedUpdate.
  • LateUpdate(): Executes after all scripts have finished their Update loop. Commonly used for camera follow scripts: if your player moves in Update, moving the camera in LateUpdate ensures the player has completed their movement first, eliminating jittery camera motion.

4. Decommissioning Events

  • OnDisable(): Executed when the component is unchecked or the GameObject is deactivated. Use this to unregister event listeners and clean up connections.
  • OnDestroy(): Executed when the GameObject is deleted via code or the scene changes. Ideal for freeing up custom resources.

TL;DR

  • Lifecycle events execute in a rigid, predetermined sequence controlled by Unity.
  • Use Awake for internal setup, and Start for cross-object references.
  • Perform physics code strictly inside FixedUpdate to maintain physical consistency.
  • Use Update for inputs, and LateUpdate for camera adjustments.