# Unity Fundamentals ## MonoBehaviour Lifecycle Every gameplay script in Unity derives from `MonoBehaviour`. The engine calls a fixed sequence of messages; understanding the order is the difference between code that runs smoothly and code that stutters or races. ``` Awake() -> OnEnable() -> Start() | v FixedUpdate() (physics, fixed timestep) --+ | Update() (input, gameplay) --+ | LateUpdate() (camera follow, post-sim) --+ | OnDisable() -> OnDestroy() ``` | Message | When it runs | Typical use | |----------------|-----------------------------------------------|-----------------------------------------------| | `Awake` | Once, when the script instance is loaded | Cache components, set up singletons | | `OnEnable` | Every time the component is enabled | Subscribe to events | | `Start` | Once, before the first Update | Cross-object references (other objects' Awake have run) | | `FixedUpdate` | Fixed timestep (default 0.02 s = 50 Hz) | Rigidbody physics forces | | `Update` | Every rendered frame | Input polling, gameplay logic | | `LateUpdate` | After all Update calls have finished | Camera follow, post-processing | | `OnDisable` | When the component is disabled | Unsubscribe from events | | `OnDestroy` | When the GameObject is destroyed | Cleanup native resources | > **Gotcha:** `Camera.main` searches the scene by tag every call in 2022.3. > Cache it in `Awake` if you call it more than once per frame. ## GameObjects and Components A `GameObject` is an empty container. Behaviour is added through **components**: ```csharp var go = new GameObject("Enemy"); go.transform.position = Vector3.zero; go.AddComponent(); go.AddComponent(); var ai = go.AddComponent(); ai.player = GameObject.FindGameObjectWithTag("Player").transform; ``` * Every GameObject always has a `Transform` (or `RectTransform` under a Canvas). You cannot remove it. * Use `GetComponent()` / `GetComponentInChildren()` / `GetComponentInParent()` to reach related components. Cache the result in `Awake` instead of calling it every frame. * `RequireComponent(typeof(T))` makes Unity auto-add the required component when the script is added in the inspector. ## The Component pattern in practice ```csharp [RequireComponent(typeof(Rigidbody))] public class PlayerController : MonoBehaviour { private Rigidbody _rb; private void Awake() { _rb = GetComponent(); // safe: RequireComponent guarantees it } } ``` ## Coroutines Coroutines let you write asynchronous-looking code that runs across multiple frames: ```csharp private IEnumerator RespawnAfterDelay(float seconds) { yield return new WaitForSeconds(seconds); transform.position = _spawnPoint; } private void OnDeath() => StartCoroutine(RespawnAfterDelay(2f)); ``` * `yield return null;` waits one frame. * `yield return new WaitForFixedUpdate();` waits until the next physics step. * `yield return new WaitUntil(() => _isGrounded);` waits for a condition. ## Inspector best practices * Use `[Header]`, `[Tooltip]`, `[Range]`, `[SerializeField]` to keep the inspector tidy. * Prefer `private` + `[SerializeField]` over `public` for fields that should not be touched by other scripts but should be editable in the inspector. * Use `[System.Serializable]` on structs/classes to make them expandable in the inspector.