# Unity From Zero

> Learn the game engine behind a huge share of the games industry: the editor, GameObjects and Components, the MonoBehaviour script lifecycle, transforms and input and movement, physics and collisions, prefabs and instantiation, UI and audio, and building your game. C# game development, taught mental-model-first.


---

# Unity From Zero

Unity is the engine behind an enormous slice of the games you've played - indie hits, mobile chart-toppers,
and plenty of AA titles - and it's a whole career path of its own, separate from web and backend work. If
you know C# already, Unity is your fastest route into making games: the engine handles rendering, physics,
audio, input, and the platform builds, and you write C# scripts that bring it all to life. This guide takes
you from opening the editor to a small, playable game you built yourself.

The mental model is one pattern repeated everywhere: **composition**. A scene is a collection of
**GameObjects** (every player, enemy, camera, light, and bit of UI is one), and each GameObject is an empty
container that does something only because of the **Components** attached to it - a Transform (position), a
Renderer (how it looks), a Rigidbody (physics), and your own **scripts** (behavior). You don't subclass a
god-object; you *compose* behavior by attaching components. Hold "a GameObject is a bag of Components, and
your scripts are Components," and Unity stops being a sprawling tool and becomes a system you can reason about.

> 📝 This teaches the **engine** - it assumes you know **C#**: classes, methods, fields, and inheritance
> ([C# From Zero](/guides/csharp-from-zero)). It's a different world from the web frameworks
> ([What a Framework Even Is](/guides/what-a-framework-even-is) sets the broad context). Unity runs in its
> own editor and builds native apps, so examples are shown as C# scripts and editor steps rather than run on
> the page.

## How to read this

Read in order - it builds one small game (a top-down **collect-the-pickups** game: a player you move, items
to grab, a score) from an empty scene to a built, playable result. Phases carry difficulty badges.

## The phases

**Part 1 - The engine model (🟢 Basic → 🟡)**
1. **[What Unity Is](01-what-unity-is.md)** 🟢 - the engine, the editor, scenes, and the GameObject/Component idea.
2. **[The Editor](02-the-editor.md)** 🟢 - the Scene/Game/Hierarchy/Inspector/Project windows, and how you build a scene.
3. **[GameObjects & Components](03-gameobjects-and-components.md)** 🟡 - composition over inheritance, the Transform, and attaching components.

**Part 2 - Bringing it to life (🟡 → 🔴)**
4. **[MonoBehaviour & the Game Loop](04-monobehaviour-and-the-game-loop.md)** 🟡 - scripts as components, `Start`/`Update`, and frame-rate-independent movement.
5. **[Transforms, Input & Movement](05-transforms-input-movement.md)** 🟡 - moving objects, reading input, and the new Input System.
6. **[Physics & Collisions](06-physics-and-collisions.md)** 🔴 - Rigidbody, Colliders, triggers, and `OnCollision`/`OnTrigger`.
7. **[Prefabs & Instantiation](07-prefabs-and-instantiation.md)** 🔴 - reusable objects, spawning at runtime, and `Destroy`.

**Part 3 - A real game (🟡 → 🟢)**
8. **[UI, Audio & Building](08-ui-audio-and-building.md)** 🟡 - a score UI, sound, game state, and exporting a build.
9. **[Where to Go Next](09-where-to-go-next.md)** 🟢 - Unity vs Godot/Unreal, ScriptableObjects, and what to build.

> The throughline: a scene is **GameObjects**, each a bag of **Components**, and your **scripts are
> Components** the engine calls every frame. Hold that and Unity is approachable.


---

# What Unity Is

You already know [C#](/guides/csharp-from-zero) - classes, methods, fields, inheritance. That
single fact is the reason Unity is your fastest route into making games. Unity powers an enormous
slice of the games you've actually played: indie darlings, the mobile titles topping the charts,
and plenty of AA productions. It's also a career path of its own, sitting well apart from web and
backend work.

Here's the one idea to hold before any of the windows and menus pile up. An **engine** is a
framework for games - the same "don't call us, we'll call you" relationship you met in
[What a Framework Even Is](/guides/what-a-framework-even-is), pointed at a different problem. The
engine owns the loop, the rendering, the physics, the clock; you fill in the blanks with assets
and scripts, and the engine runs them at the right moments. You are not writing the thing that
draws pixels to the screen sixty times a second. You're writing the thing that decides what those
pixels should *do*.

## The mental model: bags of Components

If you remember nothing else from this phase, remember this sentence:

> **A Scene is a collection of GameObjects; a GameObject is a bag of Components; your scripts are
> Components the engine runs.**

Let's unpack it from the outside in.

📝 **Scene** - one self-contained slice of your game: a level, a menu, a loading screen. You build
your game out of scenes and switch between them. Whatever is "live" right now lives in the current
scene.

📝 **GameObject** - a single thing *in* a scene. The player is a GameObject. So is the camera, the
light, an enemy, a button on your UI, an invisible spawn point. Here's the catch that trips people
up: a GameObject, on its own, **does nothing**. It's an empty container with a name. It has no
shape, no behavior, no physics until you give it some.

📝 **Component** - the part that actually *does* something, attached to a GameObject. Want the
object to be somewhere in space? That's the **Transform** component (every GameObject has one, for
free - position, rotation, scale). Want it to be visible? Add a **Renderer**. Want it to fall and
collide? Add a **Rigidbody** and a **Collider**. Want it to chase the player? Add *your script* -
because a script is a Component too (more on that in Phase 4).

So a "player" isn't a special Player type the engine knows about. It's a plain GameObject with a
Transform, a Renderer so you can see it, a Collider so it bumps into walls, and a movement script
you wrote. Stack different components and you get a different thing. Same container, different
contents.

```mermaid
flowchart TD
  S[Scene] --> P[GameObject: Player]
  S --> C[GameObject: Camera]
  S --> L[GameObject: Light]
  P --> T[Transform]
  P --> R[Renderer]
  P --> Col[Collider]
  P --> Sc[PlayerMovement script]
```

*What just happened:* the scene holds several GameObjects, and the Player GameObject is nothing but
the four components clipped onto it. Pull off the script and the player stops moving but still
exists. Pull off the Renderer and it moves invisibly. The GameObject is the hook; the components
are everything that matters.

### Composition over inheritance - the real shift

This is the single biggest mental adjustment for someone coming from ordinary OOP, so it's worth
saying plainly.

📝 **Composition over inheritance** - instead of building a deep class tree (`Entity` →
`Character` → `Enemy` → `FlyingEnemy`) and inheriting behavior, you keep GameObjects simple and
**attach** behavior as components. A flying enemy isn't a subclass; it's a GameObject with a
Renderer, a Collider, a `Flying` component, and an `Enemy` component. Want a flying *player*?
Attach the same `Flying` component to the player. Nothing to refactor.

💡 Coming from C#, your instinct is to reach for inheritance - make a base class, override methods,
build the hierarchy. Unity gently steers you the other way. You'll still write classes (each script
*is* a class), but you compose a GameObject's abilities by mixing components rather than by
subclassing a god-object. Fight this instinct and Unity feels awkward. Lean into it and the whole
engine clicks.

## What the engine gives you vs. what you write

A clean way to keep your bearings: know which side of the line each thing is on.

**The engine handles** (you configure it, you don't build it):

- **Rendering** - turning your 3D/2D scene into pixels on screen, every frame.
- **Physics** - gravity, collisions, forces, bouncing (via Rigidbody and Collider components).
- **Audio** - playing sounds and music, positioned in space.
- **Input** - reading the keyboard, mouse, gamepad, or touchscreen.
- **Builds** - packaging your project into an actual app for Windows, macOS, Android, iOS,
  consoles, and the web.

**You supply:**

- **Assets** - the raw materials: 3D models, sprites, textures, audio clips, fonts.
- **C# scripts** - the *behavior*. The rules of your game. What happens when the player presses a
  key, touches a pickup, runs out of health.

⚠️ That split is the deal Unity offers, and it's a good one - but it means a chunk of your work
happens in the editor (dragging assets, wiring up components in the Inspector) rather than purely
in code. Unity is not a library you `import` into a C# project; it's an application you work
*inside*. We'll tour that editor in Phase 2.

## A first taste of a script

You won't write much code in this phase - the full script lifecycle is Phase 4 - but seeing one
now makes "a script is a Component" concrete. In the editor you'd create a C# script (an
asset in your Project window), open it, and you'd find something close to this:

```csharp
using UnityEngine;

public class HelloWorld : MonoBehaviour
{
    // Unity calls this once, automatically, when the object comes to life.
    void Start()
    {
        Debug.Log("The pickup game is alive!");
    }
}
```

*What just happened:* you wrote a normal C# class, but it inherits from **`MonoBehaviour`** - the
base class that makes a script attachable to a GameObject as a Component. You never call `Start()`
yourself. The engine does, exactly once, when the GameObject wakes up - that's the framework
relationship in action. `Debug.Log` prints to Unity's Console window (the engine's version of
`Console.WriteLine`). Attach this script to any GameObject, press Play, and the message appears.
That's the entire shape of Unity scripting: write a `MonoBehaviour`, attach it, let the engine call
your methods at the right time. Phase 4 covers `Update` and the rest of the lifecycle.

## The game we'll build

To keep everything grounded, this whole guide builds one small, real game together: a top-down
**collect-the-pickups** game.

- A **player** GameObject you move around with the keyboard.
- A handful of **pickup** GameObjects scattered around to grab.
- A **score** that goes up each time you collect one.

It's deliberately tiny, but it exercises the real machinery: input and movement (Phase 5), physics
and triggers so the player can "touch" a pickup (Phase 6), spawning pickups at runtime (Phase 7),
and a score UI plus a built, playable file you can hand to a friend (Phase 8). Every concept lands
in that one game instead of floating as a disconnected demo.

⚠️ One practical note before we go further: Unity does all of this inside its own **editor**
application, not on a web page - so unlike the runnable snippets elsewhere in this library, the
code here is shown to read and to type into Unity, not to run in your browser. Getting comfortable
in that editor is exactly what Phase 2 is for.

## Recap

1. **Unity is a game engine + editor.** The engine owns rendering, physics, audio, input, and
   cross-platform builds; you supply **assets** and **C# scripts**. It's a framework for games and
   a career path of its own.
2. **The core mental model:** a **Scene** holds **GameObjects**; a **GameObject** is an empty bag
   of **Components**; the components are what give it shape, physics, and behavior.
3. **A GameObject does nothing by itself.** Every one has a free **Transform** (position/rotation/
   scale); you add a Renderer (looks), a Collider/Rigidbody (physics), and your scripts (behavior).
4. 📝 **Composition over inheritance** is the big shift from ordinary OOP: attach components to
   compose behavior instead of subclassing a god-object. A script *is* a Component, via
   `MonoBehaviour`.
5. **You work inside Unity's editor app**, not just in a code file - and the engine calls your
   script methods (like `Start`) for you, the classic "don't call us, we'll call you."
6. We'll build one running example throughout: a **collect-the-pickups** game (move a player, grab
   pickups, raise a score).

## Quick check

Three questions on the ideas that have to stick - what Unity is, how the GameObject/Component model
works, and the composition shift:

```quiz
[
  {
    "q": "In Unity's model, what is a GameObject on its own?",
    "choices": [
      "An empty container that does something only via the Components attached to it",
      "A fully-featured player character with built-in movement and physics",
      "A C# class you must inherit from to make a game",
      "The window where you edit your scene"
    ],
    "answer": 0,
    "explain": "A GameObject is just a named container. It does nothing until you attach Components - every one has a free Transform, and you add a Renderer, Collider/Rigidbody, and scripts to give it looks, physics, and behavior."
  },
  {
    "q": "Which work does the Unity engine handle for you, versus what you supply?",
    "choices": [
      "The engine handles rendering, physics, audio, input, and builds; you supply assets and C# scripts",
      "The engine writes your game logic; you only design the box art",
      "You handle rendering and physics by hand; the engine just stores files",
      "The engine and you both write the rendering loop together each frame"
    ],
    "answer": 0,
    "explain": "Unity's deal: the engine owns rendering, physics, audio, input, and cross-platform builds. You provide the assets (models, sprites, audio) and the C# scripts that define behavior."
  },
  {
    "q": "What does 'composition over inheritance' mean in Unity?",
    "choices": [
      "You attach Components to compose behavior instead of subclassing a deep god-object hierarchy",
      "You must inherit every GameObject from a single base Entity class",
      "Composition means writing music for your game before the code",
      "It means you never write C# classes at all in Unity"
    ],
    "answer": 0,
    "explain": "Rather than a deep inheritance tree, you keep GameObjects simple and mix in behavior by attaching Components. A script is itself a Component (a MonoBehaviour), so you compose abilities instead of subclassing."
  }
]
```


---

# The Editor

**The editor is where you assemble a Scene.** Everything you see on screen is one window doing one job in that assembly. The **Hierarchy** lists the objects in your scene. The **Scene view** is where you place and move them. The **Inspector** configures each one. The **Project window** holds the raw assets on disk. And the **Game view** plus the **Play** button show you what the player will actually experience. Once you know which window does what, the editor stops being a wall of panels and becomes a workshop where each tool has its bench.

> 💡 You don't *program* the layout of a scene - you *arrange* it by hand, visually, and then your scripts (Phase 4 onward) animate that arrangement. The editor is the hands-on half of Unity; C# is the other half.

## Getting in: Unity Hub and a new project

You don't download "Unity" as a single thing. You download **Unity Hub** - a small launcher whose job is to manage editor versions and your projects. Think of the Hub as the front desk: it installs the actual editor (you can have several versions side by side) and creates projects that are pinned to a version.

When you install an editor version, pick an **LTS** release (Long-Term Support). LTS versions are the boring, stable ones that get bug fixes for years - exactly what you want while learning, instead of chasing the newest features and their newest bugs.

Then create a new project. The Hub asks you to pick a **template**:

- **3D** - a scene set up for three-dimensional games (perspective camera, 3D physics).
- **2D** - a scene set up for flat games (orthographic camera, 2D sprites and physics).

> 📝 For the collect-the-pickups game this guide builds, a **3D** template is the simplest starting point - we'll move a sphere around a flat plane. Give the project a name, pick a folder, and let the Hub open the editor. The first open is slow; it's compiling and importing. That's normal.

## Walking the windows

When the editor opens you'll see a handful of docked panels. The exact arrangement varies by layout, but every Unity install has these six, and learning what each is *for* matters far more than where it happens to sit.

**Hierarchy** - the list of every GameObject in the *current* scene, shown as a tree. A fresh 3D scene usually starts with a **Main Camera** and a **Directional Light** already in it. When you add objects, they appear here. The Hierarchy is your scene's table of contents - it answers "what's in this scene?"

**Scene view** - the interactive viewport where you build. You orbit, pan, and zoom around your world here, and you select, move, rotate, and scale objects directly. This is **edit mode** - the workbench. Nothing here is "running"; you're laying out the furniture.

**Game view** - what the player sees, rendered through the scene's **Camera**. It looks similar to the Scene view but it's a fundamentally different thing: the Scene view is *your* god's-eye editing camera, while the Game view is the *player's* camera. The Game view comes alive when you press Play.

**Inspector** - the properties panel for whatever you've selected. Select a GameObject and the Inspector shows its **Components** - each one a block of editable settings. This is where you tweak almost everything in Unity: position, color, physics settings, the public fields of your scripts. If you ever wonder "where do I change this?", the answer is usually the Inspector.

**Project window** - your assets as they live **on disk**: scripts, 3D models, textures, audio, prefabs, and scenes. This is the difference between *what exists in your project* (Project window) and *what's placed in the current scene* (Hierarchy). You drag assets from here into the scene to use them.

**Console** - the message log. Errors (red), warnings (yellow), and your own `Debug.Log` output (white) all show up here. When something doesn't work, the Console is the first place to look - a red error with a line number is Unity telling you exactly what broke.

> 💡 Two pairs are easy to confuse, so anchor them now: **Scene view = your editing camera / Game view = the player's camera.** And **Hierarchy = objects in this scene / Project = assets on disk.** Mixing these up is the most common beginner stumble.

```mermaid
flowchart LR
  P[Project window<br/>assets on disk] -->|drag in| H[Hierarchy<br/>objects in scene]
  H -->|select| I[Inspector<br/>components & settings]
  H -.placed in.-> S[Scene view<br/>edit mode]
  S -->|press Play| G[Game view<br/>player's camera]
  G -.logs & errors.-> C[Console]
```

## Play mode, and the trap that bites everyone

The **Play** button (the triangle at the top center of the editor) runs your game. Press it and the editor switches focus to the **Game view**: scripts start executing, physics simulates, input is read, and you can actually play what you've built. Press it again to stop and return to edit mode.

This is the single most powerful thing about the editor - you can test instantly, without building or exporting anything. But it comes with a trap that catches nearly every beginner at least once:

> ⚠️ **Changes you make to objects WHILE in Play mode are DISCARDED when you stop.** If you press Play, then move the player or tweak a value in the Inspector to "fix" something, all of those edits vanish the moment you hit Stop. Unity does this on purpose - Play mode is a sandbox so you can experiment freely without wrecking your scene. The rule: **make real edits in edit mode (Play not pressed).** A common safeguard is to tint the editor a different color while in Play mode (a setting in Preferences) so you can *see* at a glance that your edits are temporary.

## Building the first scene

Now put the windows to work and lay down the start of the actual game: a flat ground and a player to stand on it. These are pure editor steps - no code yet. You'll do this in **edit mode**, with Play *not* pressed.

**1. Create and save a Scene.** A **Scene** is a saved arrangement of GameObjects - a level, a menu, a screen. A project has many of them. Your new project already opened with an empty-ish scene, so save it first with `File → Save As`, and call it something like `Main`. It'll appear in the Project window as a `.unity` asset. Saving early means there's something to save *to* as you work.

**2. Add the ground.** In the menu bar, choose `GameObject → 3D Object → Plane`. A flat square appears in the Scene view and a "Plane" entry shows up in the Hierarchy. That's your floor.

**3. Add the player.** Choose `GameObject → 3D Object → Sphere` (a capsule works too). A ball drops into the scene. Rename it in the Hierarchy - double-click and type `Player` - so future-you knows what it is. By default it'll likely spawn at the world origin, halfway sunk into the plane.

**4. Position it with the Inspector.** Select `Player` in the Hierarchy. The Inspector fills with its Components - the most important being the **Transform**, which holds **Position**, **Rotation**, and **Scale**. The Transform is on *every* GameObject; it's how Unity knows where a thing is. Set the Player's Position **Y** to something like `0.5` so the sphere rests *on* the plane instead of inside it. Watch the Scene view update live as you type.

> 💡 You just used the core loop of editor work: **add a GameObject, select it, configure it in the Inspector.** Notice you changed the object's place in the world by editing a *Component* (the Transform) - not the object directly. That's the composition idea from Phase 1 made concrete, and it's exactly what Phase 3 cracks open: every GameObject is a bag of Components, and the Transform is the one they all share.

**5. Press Play.** Hit the Play button and look at the **Game view** - you'll see your sphere on a plane, through the Main Camera's eyes. Nothing moves yet (no scripts), but this *is* your game, running. Press Play again to stop. (And remember the trap: if you nudged anything while playing, it didn't stick.)

That's a real, if very quiet, scene - assembled entirely with the windows you just learned.

## Recap

- The editor is **where you assemble a Scene**; each window has one job in that assembly.
- **Hierarchy** = objects in the current scene · **Project** = assets on disk · **Scene view** = your editing camera · **Game view** = the player's camera · **Inspector** = the selected object's Components · **Console** = logs and errors.
- You get Unity through **Unity Hub**, which installs editor versions (pick **LTS**) and creates projects from a **2D** or **3D** template.
- **Play mode** runs the game instantly in the Game view - but ⚠️ edits made *during* Play are discarded; make real changes in edit mode.
- A **Scene** is a saved arrangement of GameObjects; the core editor loop is **add a GameObject → select it → configure it in the Inspector** (where the **Transform** lives).

Check yourself before moving on:

```quiz
[
  {
    "q": "What's the difference between the Hierarchy and the Project window?",
    "choices": ["They're two names for the same panel", "Hierarchy lists objects in the current scene; Project shows assets on disk", "Hierarchy is for 3D and Project is for 2D", "Hierarchy shows assets; Project shows the running game"],
    "answer": 1,
    "explain": "The Hierarchy is the tree of GameObjects in the scene you're editing; the Project window is your assets (scripts, models, scenes) as files on disk."
  },
  {
    "q": "You press Play, move the Player in the Scene view to fix its position, then press Stop. What happens to that move?",
    "choices": ["It's saved permanently", "It's discarded - edits made during Play mode don't stick", "It saves only if you also save the scene", "Unity asks whether to keep it"],
    "answer": 1,
    "explain": "Play mode is a sandbox: any change you make while playing is thrown away when you stop. Edit in edit mode (Play not pressed)."
  },
  {
    "q": "Where do you change a GameObject's position, and through what?",
    "choices": ["In the Console, by typing a command", "In the Project window, on the asset file", "In the Inspector, via its Transform component", "In the Game view, by dragging the camera"],
    "answer": 2,
    "explain": "Selecting an object shows its Components in the Inspector. The Transform component holds Position, Rotation, and Scale - and every GameObject has one."
  }
]
```


---

# GameObjects & Components

Here's the one idea that makes Unity click. Once you hold it, most of the engine stops feeling
like a pile of unrelated menus and starts feeling like a single pattern repeated everywhere.

> 📝 **A GameObject is a bag of Components.** The GameObject itself does nothing. It's an empty
> container with a name. Everything it *does* - show up on screen, have a position, fall under
> gravity, play a sound, run your code - comes from **Components** you attach to it. The only
> Component every GameObject is born with is the **Transform**. Everything else, you add.

If you came from object-oriented C#, your instinct is probably to reach for inheritance: a
`Player` class extends `Character` extends `Entity`. Unity gently asks you not to. Instead of
*being* a deep chain of classes, a player *has* a Transform, a Renderer, a Collider, a
Rigidbody, and a movement script - each a separate Component, each doing one job. That's
**composition over inheritance**, and Unity is built around it from the ground up. (If you want
the broader theory of why composition often beats inheritance, see
[OOP vs Functional](/guides/oop-vs-functional).)

## The Transform: the one Component that's always there

Create an empty GameObject in a scene and look at the Inspector. It's almost bare - but there's
one Component already attached that you can't remove: the **Transform**.

The Transform answers three questions about the object in space:

- **Position** - where it is (an x, y, z point).
- **Rotation** - which way it's facing.
- **Scale** - how big it is.

That's it. An empty GameObject with only a Transform is an invisible, intangible point in your
scene. It has a location, but no shape, no picture, no physics. To make it *anything*, you attach
more Components.

> 💡 In 2D projects you'll often see a **RectTransform** instead - it's a Transform variant built
> for UI rectangles (anchors, pivots, width/height). Same idea, extra knobs. For plain 2D and 3D
> objects, the regular Transform is what you get.

## The common Components, and what each one gives you

Think of these as the building blocks you'll reach for constantly. Each one bolts a single
capability onto a GameObject:

| Component | What it adds | Covered in |
|-----------|--------------|------------|
| **MeshRenderer** / **SpriteRenderer** | Makes the object *visible* (a 3D mesh, or a 2D sprite) | here |
| **Camera** | Turns the object into a viewpoint the player sees through | here |
| **Light** | Makes the object emit light into the scene | here |
| **AudioSource** | Lets the object play sounds | Phase 8 |
| **Collider** (Box/Sphere) | Gives the object a *physical shape* for collisions | Phase 6 |
| **Rigidbody** | Hands the object over to the physics engine (gravity, forces) | Phase 6 |
| **Your scripts** | Custom behavior - your C# code, running as a Component | Phase 4 |

The pattern is always the same: a GameObject is dumb on its own; you make it smart by stacking
Components. A camera is just a GameObject with a Camera component. A light is a GameObject with a
Light component. There's no special "Camera class" you inherit from - you compose.

## Building the player as a composition

Let's make this concrete with the player for our collect-the-pickups game. We don't write a giant
`Player` class that knows how to render itself and simulate physics. We build the player by
stacking Components on one GameObject:

```text
Player (GameObject)
├── Transform          ← where the player is (always present)
├── MeshRenderer       ← so you can see it
├── BoxCollider        ← so it can bump into things
├── Rigidbody          ← so physics moves it
└── PlayerMovement     ← your script: reads input, moves the player
```

*What just happened:* one GameObject, five Components, each with a single responsibility. Want the
player to glow? Add a Light. Want it to play a footstep? Add an AudioSource. You never rewrite the
player - you attach another Component. Compare this to an inheritance tree, where adding "can play
sound" might mean inventing a new base class and reshuffling the hierarchy. Composition lets you
add capabilities like clipping LEGO bricks together.

You add Components two ways: in the **Inspector** with the **Add Component** button (the visual
editor for a GameObject's Components), or from code. Most setup happens in the Inspector; code is
for when you need to add a Component at runtime.

## Reaching Components from a script

A script is itself a Component, attached to a GameObject. Very often your script needs to talk to
*another* Component on the *same* GameObject - for example, the movement script needs the Rigidbody
to apply force. The way you get a reference to a sibling Component is `GetComponent<T>()`:

```csharp
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private Rigidbody rb;

    void Start()
    {
        // Grab the Rigidbody attached to the SAME GameObject as this script.
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        // Now we can use the cached reference every physics step.
        rb.AddForce(Vector3.forward);
    }
}
```

*What just happened:* `GetComponent<Rigidbody>()` looks at the GameObject this script is on and
hands back its Rigidbody Component. We call it **once** in `Start` and store the result in the `rb`
field, so later code (`FixedUpdate`) reuses it instead of looking it up again. ( `Start`,
`FixedUpdate`, and the script lifecycle are Phase 4 - for now, `Start` runs once at the beginning,
and the `Update`/`FixedUpdate` methods run repeatedly.)

> ⚠️ Two traps with `GetComponent`, and you'll hit both eventually:
> 1. **It returns `null` if that Component isn't attached.** If there's no Rigidbody on the
>    GameObject, `rb` is `null`, and the first time you use it you get a `NullReferenceException`.
>    It's a crash waiting to happen - so attach the Component (in the Inspector), or check for
>    `null` before using the result.
> 2. **It's not free - don't call it every frame.** Looking a Component up has a cost. Calling
>    `GetComponent` inside `Update` (which runs ~60 times a second) is wasteful. **Cache it once**
>    in `Awake` or `Start`, like we did above, then reuse the stored reference.

When the Component you want lives on a *child* or *parent* GameObject instead of the same one,
there are sibling methods:

```csharp
// Same GameObject:
var rb   = GetComponent<Rigidbody>();

// Search this GameObject AND its children (e.g. a weapon mesh nested under the player):
var mesh = GetComponentInChildren<MeshRenderer>();

// Search this GameObject AND up toward its parents:
var root = GetComponentInParent<Rigidbody>();
```

*What just happened:* same lookup, different search area. `GetComponent` stays on the one
GameObject; `GetComponentInChildren` and `GetComponentInParent` walk down or up the hierarchy
(next section) to find the first matching Component. They share the same null-and-cost caveats -
cache the result, don't spam it per frame.

You can also *create* a Component from code with `AddComponent<T>()` - handy for assembling
objects at runtime:

```csharp
// Attach a fresh AudioSource to this GameObject and keep a reference to it.
var audio = gameObject.AddComponent<AudioSource>();
```

*What just happened:* `gameObject` refers to the GameObject this script is attached to, and
`AddComponent<AudioSource>()` bolts a new AudioSource onto it - the exact same thing the **Add
Component** button does in the Inspector, but in code.

## The hierarchy: parenting GameObjects

GameObjects don't just float independently - they nest into a **hierarchy** (this is the
Hierarchy window from Phase 2). Drag one GameObject onto another and it becomes a **child**; the
other becomes its **parent**. This relationship lives in the Transform.

The key rule: **a child's Transform is relative to its parent.** Move the parent, and every child
moves with it, keeping its offset. This is how you build composite objects - a car body with four
wheels parented to it, a player with a camera rig parented above. Move the car; the wheels and
everything else come along for free.

```text
Car (parent)              ← move this...
├── Body
├── Wheel_FL              ← ...and all four wheels move with it,
├── Wheel_FR                 each staying in its place relative to the Car.
├── Wheel_RL
└── Wheel_RR
```

*What just happened:* parenting via the Transform turns five separate GameObjects into one thing
you can move, rotate, and scale as a unit. A child positioned at "2 units to the right" stays 2
units to the right *of its parent*, wherever the parent goes. That relative-to-parent math is the
whole point of the hierarchy.

## Recap

- **A GameObject is an empty container.** It does nothing by itself - its abilities come entirely
  from the **Components** attached to it.
- The **Transform** (position, rotation, scale) is the one mandatory Component every GameObject
  has. Everything else - Renderer, Collider, Rigidbody, Camera, AudioSource, your scripts - you
  add.
- This is **composition over inheritance**: you build an object by stacking single-purpose
  Components, not by extending a deep class hierarchy.
- From a script, reach a Component on the same GameObject with `GetComponent<T>()` (and
  children/parent variants). **Cache the result in `Start`** - it returns `null` if absent, and
  it's wasteful to call every frame.
- GameObjects nest into a **hierarchy** via the Transform. A child's position is **relative to its
  parent**, so moving the parent moves the whole group.

## Quick check

Test the mental model before moving on:

```quiz
[
  {
    "q": "You create a brand-new empty GameObject. Which Component does it already have?",
    "choices": ["A MeshRenderer", "A Rigidbody", "A Transform", "None - it's completely empty"],
    "answer": 2,
    "explain": "Every GameObject is born with exactly one mandatory Component: the Transform (position, rotation, scale). Everything else you add yourself."
  },
  {
    "q": "Your script calls GetComponent<Rigidbody>() inside Update() every frame and stores it nowhere. What's the problem?",
    "choices": ["GetComponent only works in Start()", "It's wasteful to look up the same Component ~60 times a second; cache it once in Start", "Update() can't access other Components", "It will add a new Rigidbody each frame"],
    "answer": 1,
    "explain": "GetComponent has a cost. Call it once in Awake/Start, store the reference in a field, and reuse it - don't look it up every frame."
  },
  {
    "q": "Why does Unity favor composition (attaching Components) over a deep inheritance hierarchy for a player?",
    "choices": ["Inheritance isn't supported in C#", "You add capabilities by attaching single-purpose Components instead of reshaping a class tree", "Components run faster than classes", "It's the only way to set a position"],
    "answer": 1,
    "explain": "A player is a GameObject with a Transform + Renderer + Collider + Rigidbody + a script. Want a new ability? Attach another Component - no need to rework a base-class chain."
  }
]
```


---

# MonoBehaviour & the Game Loop

**A MonoBehaviour is a Component the engine drives.** You don't write a `main()` and call your own code. You write a class, override a few specially-named methods, attach it to a GameObject - and from then on Unity calls those methods *for* you, on a schedule. `Start` runs once. `Update` runs every single frame, forever, until the object goes away. That repeating call is the game loop, and your scripts ride on top of it.

> 💡 If you've done web work, flip your usual instinct. There you mostly *call* the framework. Here the framework calls *you*. Your job is to fill in the right hooks and trust the engine to invoke them at the right moments. This is the inversion of control that makes a real-time game possible.

## A script becomes a Component

Back in [Phase 3](03-gameobjects-and-components.md) you saw that a GameObject is a bag of Components, and your scripts are Components too. The mechanism is one keyword: your class inherits from **`MonoBehaviour`**.

```csharp
using UnityEngine;

public class Player : MonoBehaviour
{
    void Start()
    {
        Debug.Log("Player ready");
    }

    void Update()
    {
        // runs once per frame
    }
}
```

*What just happened:* `Player` inherits `MonoBehaviour`, which is what lets you drag the `Player.cs` file onto a GameObject and have it show up as a Component in the Inspector. Once attached, Unity sees the `Start` and `Update` methods and calls them automatically - `Start` one time as the object comes alive, `Update` on every frame after. Notice you never wrote a line that *calls* `Start` or `Update`. You don't. That's the engine's job.

> 📝 The file name must match the class name. `Player.cs` must contain `class Player`. If they disagree, Unity refuses to attach the script and gives you an error in the Console. This trips up nearly everyone once.

## The lifecycle methods

Unity calls a set of methods at specific moments in an object's life. You override the ones you care about and ignore the rest. Here are the ones that actually matter day to day, in roughly the order they fire:

- **`Awake()`** - called once, the moment the object loads, before anything else. Use it to set up *this* object's own references (grabbing a Component, initializing a field).
- **`OnEnable()`** - called whenever the object or component becomes enabled (including every time it's re-enabled later).
- **`Start()`** - called once, just before the object's first frame, *after* every object's `Awake` has run. Because all the `Awake`s are done by now, `Start` is the safe place for setup that reaches *across* objects ("find the score manager and talk to it").
- **`Update()`** - called **every frame**. This is where most of your game logic lives: reading input, moving things that aren't physics-driven, checking conditions.
- **`FixedUpdate()`** - called every fixed physics step (not every frame). Anything touching a Rigidbody or physics goes here - that's [Phase 6](06-physics-and-collisions.md).
- **`LateUpdate()`** - called after *all* `Update`s have run this frame. Classic use: a camera that follows a target, so it moves only after the target has finished moving.
- **`OnDestroy()`** - called when the object is destroyed. Clean-up lives here.

```mermaid
flowchart TD
  A[Awake - once] --> B[OnEnable]
  B --> C[Start - once, before first frame]
  C --> D[Update - every frame]
  D --> E[LateUpdate - every frame, after Update]
  E --> D
  D -. object destroyed .-> F[OnDestroy]
```

The `Awake` vs `Start` split confuses people, so hold this: **`Awake` = set yourself up. `Start` = talk to others.** By the time any `Start` runs, every object has finished its `Awake`, so cross-object references are guaranteed to exist.

## The #1 beginner bug: forgetting `Time.deltaTime`

This is the trap that catches everyone, so read it twice. Your `Update` runs once per frame - but **frames don't arrive at a fixed rate.** A beefy gaming PC might render 240 frames a second; a tired laptop might manage 30; and even on one machine the rate jitters moment to moment.

So if you move an object "a little bit each frame," you've accidentally tied your game's speed to the frame rate. The same code crawls on a slow machine and rockets on a fast one. That's not a quirk you can ignore - it makes your game unplayable on hardware you didn't test on.

The fix is **`Time.deltaTime`**: the number of seconds that elapsed since the *previous* frame. Multiply any per-frame change by it, and you convert "per frame" into "per second" - frame-rate independent.

```csharp
using UnityEngine;

public class Mover : MonoBehaviour
{
    public float speed = 5f;

    void Update()
    {
        transform.position += Vector3.forward * speed * Time.deltaTime;
    }
}
```

*What just happened:* every frame, this nudges the object forward. On a 60-FPS machine `Time.deltaTime` is about `0.0166` (1/60th of a second); on a 30-FPS machine it's about `0.0333`. The slower machine runs `Update` half as often but moves *twice as far* each time - so over a full second both machines move exactly `speed` units (5 units/sec). That's the whole point: the object travels the same real-world distance per second regardless of how fast the hardware draws frames.

> ⚠️ Drop the `* Time.deltaTime` and your object moves `speed` units *per frame* instead of per second - meaning it flies five-plus times faster on a 300-FPS desktop than on a 60-FPS laptop. If your movement "works on my machine" but is unplayable elsewhere, this is almost always why. Make `* Time.deltaTime` a reflex for anything time-based in `Update`.

## Public fields show up in the Inspector

Notice `public float speed = 5f` in that script. Because it's `public`, Unity surfaces it as an editable field in the Inspector when you select the GameObject. A designer (or you, an hour later) can retune the speed by typing a new number - no code change, no recompile.

If you'd rather keep the field private to your code but *still* expose it in the Inspector, mark it with `[SerializeField]`:

```csharp
using UnityEngine;

public class Mover : MonoBehaviour
{
    [SerializeField] private float speed = 5f;

    void Update()
    {
        transform.position += Vector3.forward * speed * Time.deltaTime;
    }
}
```

*What just happened:* `speed` is now `private` - other scripts can't reach in and change it - yet `[SerializeField]` tells Unity to show and serialize it in the Inspector anyway. You get the best of both: encapsulation in code, tweakability in the editor. This is the idiomatic Unity way, and it's how you let non-programmers balance your game without touching C#.

> 💡 The Inspector value *wins* over the value in your code. If you write `= 5f` but type `8` in the Inspector, the object runs with `8`. The code value is just the default for a freshly-added component.

## Talking to the Console with `Debug.Log`

Your oldest, most reliable friend for figuring out what a script is doing is **`Debug.Log(...)`**, which prints to the Console window you met in [Phase 2](02-the-editor.md).

```csharp
void Start()
{
    Debug.Log("Player ready, speed is " + speed);
}
```

*What just happened:* when this object comes alive, a line appears in the Console. Sprinkle these to answer "did this method even run?" and "what's this value right now?" - the two questions behind most early Unity confusion. It's the print-debugging you already know, wired into the editor.

> 📝 A note you'll need in Phase 6: keep **logic in `Update`** and **physics in `FixedUpdate`**. Reading input and non-physics movement belong in `Update` (it tracks the frame rate, so it feels responsive). Anything that pushes a Rigidbody around belongs in `FixedUpdate` (it runs on the steady physics clock, so the simulation stays stable). Mixing them up - shoving a Rigidbody in `Update` - leads to jittery, frame-rate-dependent physics. We'll do this properly when we add collisions.

## Recap

- A class becomes a Component by inheriting **`MonoBehaviour`**; attach the `.cs` file to a GameObject and Unity calls its lifecycle methods for you - you never call them yourself.
- The lifecycle in order of use: **`Awake`** (set yourself up, once), **`OnEnable`**, **`Start`** (talk to other objects, once before the first frame), **`Update`** (every frame, game logic), **`FixedUpdate`** (physics steps), **`LateUpdate`** (after all Updates, e.g. cameras), **`OnDestroy`** (cleanup).
- **`Update` runs every frame, and frame rate varies between machines** - so multiply anything time-based by **`Time.deltaTime`** to make movement consistent (units per second, not per frame). Forgetting this is the classic beginner bug.
- **`public`** or **`[SerializeField]`** fields appear in the Inspector, letting you and designers retune values without editing code; the Inspector value overrides the code default.
- **`Debug.Log`** prints to the Console - your go-to for checking whether code ran and what a value is.

## Quick check

Test the lifecycle and the `deltaTime` rule before moving on:

```quiz
[
  {
    "q": "Which method does Unity call once per frame, where most game logic and non-physics movement belong?",
    "choices": ["Awake()", "Start()", "Update()", "OnDestroy()"],
    "answer": 2,
    "explain": "Update() runs every frame. Awake and Start run once; OnDestroy runs when the object is destroyed."
  },
  {
    "q": "Why must you multiply per-frame movement by Time.deltaTime?",
    "choices": ["To make the object move faster", "Because frame rate varies between machines, so it keeps speed measured per second instead of per frame", "Because Update only runs on physics steps", "It's only needed in FixedUpdate"],
    "answer": 1,
    "explain": "Time.deltaTime is the seconds since the last frame. Multiplying by it converts 'per frame' into 'per second', so movement is the same speed regardless of frame rate."
  },
  {
    "q": "How do you make a private field editable in the Inspector?",
    "choices": ["Make it public", "Mark it with [SerializeField]", "Call Debug.Log on it", "Move it into Awake()"],
    "answer": 1,
    "explain": "[SerializeField] exposes a private field in the Inspector while keeping it private to your code. (Making it public also exposes it, but loses the encapsulation.)"
  }
]
```


---

# Transforms, Input & Movement

Your collect-the-pickups game has a scene, a player sitting in it, and (from Phase 4) a script the engine calls every frame. But the player just sits there. Time to make it move when you press a key.

Here's the whole idea before any code:

> **Moving an object = changing its Transform a little bit every frame, scaled by `Time.deltaTime`, in a direction the player chose with input.**

That's it. There's no "move" command that animates the object for you. *You* nudge its position by hand, 60-ish times a second, and the eye reads those tiny jumps as smooth motion - the same illusion as a flip-book. Once you internalize that movement is "read input → pick a direction → adjust the Transform," every movement system in Unity (player, enemies, projectiles, the camera) is a variation on the same three steps.

## The Transform: where an object lives

Every GameObject has exactly one component it can never lose: the **Transform**. It holds the object's place in the world - position, rotation, and scale. And because your scripts inherit from `MonoBehaviour`, every script gets a free shortcut to its own GameObject's Transform through the word `transform` (lowercase t).

```csharp
public class Probe : MonoBehaviour
{
    void Start()
    {
        Debug.Log(transform.position);    // where am I? -> e.g. (0.0, 1.0, 0.0)
        Debug.Log(transform.rotation);    // which way am I facing? (a Quaternion)
        Debug.Log(transform.localScale);  // how big am I? -> (1.0, 1.0, 1.0)
    }
}
```

*What just happened:* `transform` is a property the engine wires up for you - it always points at the Transform attached to the same GameObject as this script. `transform.position` is the object's location in the world. We logged it once in `Start` so it prints when the object wakes up. (`rotation` uses a `Quaternion`, a four-number representation of orientation; you rarely set it by hand this early, so we'll leave it alone.)

The three pieces you'll actually touch:

- `transform.position` - a `Vector3`, the object's spot in the world.
- `transform.rotation` - its orientation.
- `transform.localScale` - its size, relative to its original.

## Vector3: a position is three numbers

`transform.position` isn't one number - it's a **`Vector3`**, a little bundle of three: `x`, `y`, and `z`. In Unity's default 3D world, x is right/left, y is up/down, and z is forward/back. You build one with `new`:

```csharp
Vector3 spot = new Vector3(2f, 0f, 5f);   // x=2, y=0, z=5
transform.position = spot;                 // teleport this object there
transform.position = new Vector3(0f, 1f, 0f); // or inline, no variable
```

*What just happened:* `new Vector3(2f, 0f, 5f)` creates a position 2 units right and 5 units forward, at floor level (y=0). Assigning it to `transform.position` snaps the object to that exact place instantly. The `f` after each number marks it as a `float` (Unity's positions are floats, not whole numbers) - leave it off and C# will complain.

Unity hands you named shortcuts for the common directions so you don't memorize which axis is which:

```csharp
Vector3.up;       // (0, 1, 0)   -> straight up
Vector3.right;    // (1, 0, 0)   -> to the right
Vector3.forward;  // (0, 0, 1)   -> into the screen
Vector3.zero;     // (0, 0, 0)   -> the origin
```

*What just happened:* these are just pre-made `Vector3` values with friendly names. `Vector3.up` is identical to `new Vector3(0f, 1f, 0f)` - it reads better and is harder to get wrong.

> 💡 Making a **2D** game instead? Unity has a parallel type, **`Vector2`** (just `x` and `y`), and 2D games live on the x/y plane with the camera looking down the z-axis. Everything below works the same - swap `Vector3` for `Vector2` and ignore z. Our collect-the-pickups game is top-down, so we'll use `Vector3` and move on the x/z floor.

## Reading input

Movement needs a *direction*, and the direction comes from the player. Unity has **two** input systems, and it's worth knowing both exist before you pick one.

**1. The legacy Input Manager.** The old, built-in, always-available way. You ask `Input` what's happening right now:

```csharp
float h = Input.GetAxis("Horizontal");        // -1 (left) .. 0 .. 1 (right)
float v = Input.GetAxis("Vertical");          // -1 (down) .. 0 .. 1 (up)

bool jumping = Input.GetKeyDown(KeyCode.Space); // true the frame Space is pressed
bool held = Input.GetKey(KeyCode.Space);        // true every frame Space is held
```

*What just happened:* `Input.GetAxis("Horizontal")` reads the arrow keys and A/D (and a gamepad stick) and returns a number from -1 to 1 - and it *smooths* the value, ramping up and easing back to zero, so motion built on it feels less robotic. `"Vertical"` does the same for up/down via the arrows and W/S. `GetKeyDown` fires `true` for exactly one frame, the instant a key goes down (great for "jump" or "shoot"); `GetKey` stays `true` the whole time it's held (great for "keep moving").

> 📝 **The newer Input System package is the current, recommended choice.** It's action-based (you bind an action like "Move" to keys, a stick, and a touch control at once), handles multiple devices and rebinding cleanly, and is where Unity is investing. It's a bit more setup, so for *learning* the movement idea we'll use the legacy `Input.GetAxis` - the concept is identical, and you can migrate later. Just know that when a real project asks you to add the Input System package, that's not a detour: it's the modern path.

## Putting it together: PlayerMovement

Now the three steps - read input, build a direction, adjust the Transform - in one script. Attach this to your player GameObject (Phase 3 covered the Add Component flow).

```csharp
public class PlayerMovement : MonoBehaviour
{
    [SerializeField] private float speed = 5f;

    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        Vector3 move = new Vector3(h, 0f, v);
        transform.position += move * speed * Time.deltaTime;
    }
}
```

*What just happened:* every frame, `Update` reads horizontal and vertical input into `h` and `v`. We pack them into a `Vector3` - x from horizontal, **z** from vertical (top-down, so vertical input drives forward/back), and y left at 0 so the player stays on the floor. Then we *add* that direction to the current position. The `speed * Time.deltaTime` part is the Phase 4 lesson: `Time.deltaTime` is how long the last frame took, so multiplying by it makes the player travel the same real-world distance per second whether the game runs at 30 or 144 fps. `[SerializeField] private float speed = 5f;` exposes `speed` as a tweakable slider in the Inspector while keeping the field private to other code - so you can balance the feel without recompiling. When no key is pressed, `h` and `v` are 0, `move` is `(0,0,0)`, and the player holds still.

Press Play, tap the arrow keys, and the player slides around the floor. That's a real game responding to you.

### One catch: diagonals are too fast

Hold Right *and* Up together. The player moves faster diagonally than straight - because `new Vector3(1f, 0f, 1f)` has a length of about 1.41, not 1. The two inputs stack.

```csharp
Vector3 move = new Vector3(h, 0f, v);
if (move.magnitude > 1f)
    move = move.normalized;     // clamp diagonal length back to 1
transform.position += move * speed * Time.deltaTime;
```

*What just happened:* `move.normalized` returns the same direction but with length exactly 1, so diagonal movement matches straight-line speed. We only normalize when the length exceeds 1, so partial stick input (a gamepad nudged halfway) still moves slowly instead of being forced to full speed.

> 💡 `.normalized` gives you a *copy* at length 1; `.Normalize()` changes the vector in place. Reach for normalizing any time you have a direction whose length you don't want to matter - movement, aiming, knockback. It's one of those small habits that quietly fixes a "why does this feel off" bug before it happens.

## The wall you'll walk straight through

Run the game and steer the player into a wall. It glides right through it.

> ⚠️ **Setting `transform.position` directly ignores physics entirely.** You are teleporting the object frame by frame - colliders, walls, and gravity have no say. It's perfect for *learning* input and motion (and fine for things like a free-flying camera), but it is **not** how you move a character that should bump into things. For physics-correct movement - stopping at walls, sliding along them, being pushed - you move a **Rigidbody** instead, which is exactly what Phase 6 covers next. Don't try to bolt collision detection onto direct transform movement; that's a rabbit hole. Learn the input here, then hand movement to the physics engine there.

For now, direct transform movement is the right tool: it taught you the loop without a pile of physics setup in the way. The pickups in our game don't need the player to collide with walls yet - they need the player to *reach* them, and now it can.

## Recap

- Every GameObject has a **Transform**; your script reaches its own via `transform`, and `transform.position` is its spot in the world.
- A position is a **`Vector3`** (`x`, `y`, `z`); build one with `new Vector3(...)` or use shortcuts like `Vector3.up` and `Vector3.forward`. 2D uses `Vector2` on the x/y plane.
- **Input** comes from the legacy `Input.GetAxis`/`GetKey` (simple, always there) or the newer **Input System** package (action-based, multi-device, the modern recommendation).
- Move by reading input, building a direction `Vector3`, and adding `direction * speed * Time.deltaTime` to `transform.position` every frame.
- **Normalize** the direction so diagonal movement isn't faster than straight movement.
- Setting `transform.position` directly **ignores physics** and walks through walls - fine for learning input, but real characters move via a Rigidbody (Phase 6).

## Quick check

```quiz
[
  {
    "q": "Why multiply movement by Time.deltaTime each frame?",
    "choices": ["To make the object move faster", "So speed stays consistent regardless of frame rate", "To convert the Vector3 to a Vector2", "It is required for Input.GetAxis to work"],
    "answer": 1,
    "explain": "Time.deltaTime is the duration of the last frame, so multiplying by it makes the object travel the same distance per second whether the game runs at 30 or 144 fps."
  },
  {
    "q": "What does Input.GetAxis(\"Horizontal\") return?",
    "choices": ["true or false", "A Vector3 direction", "A number from -1 to 1 based on left/right input", "The number of keys pressed"],
    "answer": 2,
    "explain": "It returns a smoothed float from -1 (left) to 1 (right), reading arrow keys, A/D, or a gamepad stick."
  },
  {
    "q": "What happens if you steer a player into a wall using transform.position directly?",
    "choices": ["The player stops at the wall automatically", "The player slides along the wall", "The player passes straight through it", "Unity throws an error"],
    "answer": 2,
    "explain": "Setting transform.position directly ignores physics and colliders, so the object teleports through walls. Physics-correct movement uses a Rigidbody (Phase 6)."
  }
]
```


---

# Physics & Collisions

At the end of Phase 5 your player walked straight through a wall. That wasn't a bug in your code - it was the whole point. Setting `transform.position` by hand teleports an object; nothing in the world gets a vote. This phase is where you stop teleporting and start letting Unity's physics engine do the heavy lifting: gravity, stopping at walls, bumping into things, and - the payoff for our game - *noticing* when the player touches a pickup.

The mental model to carry through everything below:

> **A `Rigidbody` hands an object to the physics engine. `Collider`s give that object a shape. Triggers *sense* overlaps; solid colliders *block* movement. And you drive physics in `FixedUpdate`, not `Update`.**

Three parts, one idea. The Rigidbody is the membership card to the physics club. The Collider is the body that other bodies can touch. The trigger flag decides whether touching means "you can't pass" or "I noticed you." Hold those three and physics stops being a black box.

## The Rigidbody: handing an object to physics

By default, a GameObject is invisible to physics. It has a Transform (Phase 5), so it has a position - but gravity ignores it, forces don't push it, and it never falls. The moment you add a **`Rigidbody`** component, that changes: the engine takes the wheel. It applies gravity, integrates forces, and resolves collisions for you, writing the results back into the Transform every physics step.

You add a Rigidbody the same way you add any component (Phase 3's Add Component flow). Once it's on, three properties matter early:

```csharp
public class PlayerSetup : MonoBehaviour
{
    void Start()
    {
        Rigidbody rb = GetComponent<Rigidbody>();
        rb.mass = 1f;            // heavier objects resist forces more
        rb.useGravity = true;    // does it fall? pickups often set this false
        rb.isKinematic = false;  // false = physics moves it; true = code moves it
    }
}
```

*What just happened:* `GetComponent<Rigidbody>()` fetches the Rigidbody already attached to this GameObject (you add the component in the editor; the script grabs a reference to it). `mass` controls how much a force budges the object - a 10-mass crate barely moves when a 1-mass ball shoves it. `useGravity` toggles whether it falls. `isKinematic` is the important switch: when `false`, the physics engine owns the object's motion; when `true`, the object still *participates* in collisions (other things bump off it) but only **you** move it from code - handy for moving platforms or a player you steer precisely.

### Driving a Rigidbody: do it in FixedUpdate

In Phase 5 you moved by editing `transform.position` inside `Update`. With a Rigidbody you do **not** touch the Transform directly anymore - that fights the physics engine and produces jitter and missed collisions. Instead you ask the engine to move the body, and you do it in **`FixedUpdate`**.

`FixedUpdate` is a sibling to `Update`, but the engine calls it on the **physics clock** (a fixed timestep, 50 times a second by default) rather than once per rendered frame. All physics work belongs there. You have three tools:

```csharp
public class PlayerMovement : MonoBehaviour
{
    [SerializeField] private float speed = 5f;
    private Rigidbody rb;

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

    void FixedUpdate()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 move = new Vector3(h, 0f, v);

        // Move the body to a new spot, letting collisions stop it:
        rb.MovePosition(rb.position + move * speed * Time.fixedDeltaTime);
    }
}
```

*What just happened:* this is Phase 5's player, rebuilt to respect physics. We cache the Rigidbody in `Start` (cheaper than calling `GetComponent` every step). In `FixedUpdate` we read input and build a direction exactly as before, but instead of writing `transform.position`, we call `rb.MovePosition(...)` - which moves the body *through* the physics system, so a wall in the way actually stops it. Note `Time.fixedDeltaTime` (the physics step's duration) rather than `Time.deltaTime` here, because we're on the physics clock. The other two tools you'll reach for: `rb.AddForce(Vector3.up * 300f)` shoves the body like a real push (great for jumps and explosions), and setting `rb.velocity = move * speed` commands its speed directly. `MovePosition` is the most "Phase 5-like" of the three and the easiest to start with.

> 💡 Reading input is fine in either method, but *acting* on physics goes in `FixedUpdate`. A common beginner pattern: read one-shot input like `Input.GetKeyDown(KeyCode.Space)` in `Update` (so you never miss the frame it happened), stash a `bool jumpQueued = true`, then apply the force in `FixedUpdate`. For our continuous `GetAxis` movement, reading it right inside `FixedUpdate` is fine.

## Colliders: giving an object a shape

A Rigidbody makes an object obey physics, but physics needs to know its *shape* to figure out what's touching what. That shape is a **`Collider`** - a separate component. Unity gives you a few primitives, cheap and fast:

- **`BoxCollider`** - a rectangular box. Crates, walls, platforms.
- **`SphereCollider`** - a ball. Our pickups, projectiles, anything round.
- **`CapsuleCollider`** - a pill shape. The standard choice for characters (smooth, won't snag on edges).
- **`MeshCollider`** - matches an arbitrary mesh exactly. Precise but expensive; reach for it only when a primitive won't do.

(Every one has a 2D twin - `BoxCollider2D`, `CircleCollider2D`, and so on - for 2D games.) A collider does **not** need a Rigidbody to exist; a static wall is happy with just a `BoxCollider`. But for two objects to register contact, at least one of them must have a Rigidbody - we'll hammer that rule home at the end.

### isTrigger: sense versus block

Every collider has one checkbox that completely changes its behavior: **`isTrigger`**.

- `isTrigger = false` (the default): a **solid** collider. It physically blocks. Walk into it and you stop. This is what makes walls walls.
- `isTrigger = true`: a **trigger**. It stops blocking and becomes a *sensing volume*. Things pass right through it, but the moment something overlaps it, the engine fires an event. This is exactly what a pickup, a checkpoint, a damage zone, or a "you entered the boss room" trigger needs.

For our collect-the-pickups game, the player's collider is solid (so it can bump walls), and each **pickup's collider is a trigger** - the player should walk *over* a coin and collect it, not get stopped by it like a wall.

## Reacting to contact: the callbacks

Here's the part that makes a game feel alive. When colliders touch, Unity calls special methods on any `MonoBehaviour` attached to the involved objects. You don't register anything - you just *define a method with the magic name* and the engine finds it (same deal as `Start` and `Update`). There are two families, matching the two collider modes:

**Solid contact** uses the `OnCollision*` family, which hands you a `Collision` object full of contact detail (where they hit, how hard):

```csharp
void OnCollisionEnter(Collision collision)
{
    Debug.Log("Bumped into " + collision.gameObject.name);
}
// also: OnCollisionStay (every step while touching), OnCollisionExit (when they part)
```

*What just happened:* the engine calls `OnCollisionEnter` once, the instant two **solid** colliders make contact (and at least one has a Rigidbody). The `Collision` parameter describes the hit; `collision.gameObject` is the other object. `OnCollisionStay` fires every physics step while they remain in contact, and `OnCollisionExit` fires when they separate.

**Trigger overlap** uses the `OnTrigger*` family, which hands you the other **`Collider`** directly (no contact physics, because nothing collided - they overlapped):

```csharp
void OnTriggerEnter(Collider other)
{
    Debug.Log("Entered trigger with " + other.name);
}
// also: OnTriggerStay, OnTriggerExit
```

*What just happened:* `OnTriggerEnter` fires once when something enters a trigger volume. The parameter is the *other* object's `Collider` (note: `Collider`, not `Collision` - a trigger has no collision data, only an overlap). This is the callback our pickups will use.

### Knowing *what* touched you: CompareTag

Most contacts need a filter - a pickup should only react to the *player*, not to a stray crate rolling through. The clean way is **tags**. You set a tag on a GameObject in the Inspector (a small dropdown at the top), then check it in code with `CompareTag`:

```csharp
void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Player"))
    {
        Debug.Log("The player reached me!");
    }
}
```

*What just happened:* `other.CompareTag("Player")` returns `true` only if the entering object is tagged `"Player"`. Use `CompareTag` rather than `other.name == "Player"` - names are fragile (Unity renames clones to "Player (1)"), and tags are the purpose-built, faster tool. Set the tag once in the Inspector; check it forever in code.

### The payoff: collecting a pickup

Now the whole point of this guide. Put this script on each **pickup** (a sphere with a `SphereCollider` whose `isTrigger` is checked, tagged `"Pickup"`). When the player overlaps it, the pickup destroys itself:

```csharp
public class Pickup : MonoBehaviour
{
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            Destroy(gameObject);   // collect it - remove this pickup from the scene
            // increment the score here (Phase 8 wires up the UI)
        }
    }
}
```

*What just happened:* the player (tagged `"Player"`, carrying a Rigidbody) walks into a pickup's trigger volume. The engine fires `OnTriggerEnter` on the pickup's script, passing the player's collider as `other`. We confirm it's the player with `CompareTag`, then call `Destroy(gameObject)` - `gameObject` (lowercase g) is *this* pickup, so the pickup vanishes from the scene. That's a working collect mechanic. The score line is a placeholder; Phase 8 connects it to an on-screen counter. Put this on one pickup, and Phase 7 (Prefabs) will let you stamp out a hundred more without copy-pasting.

## The one rule that trips everyone

You will, at some point, set all this up and get *absolutely nothing*. No log, no destroy, no bump. It happens to everyone. Almost always it's this:

> ⚠️ **Collision and trigger events only fire if at least one of the two objects has a `Rigidbody`, and both have `Collider`s.** A pickup with a trigger collider but *no Rigidbody on either object* will sit there silently as the player passes through. This is the number-one physics confusion in Unity. The usual fix is to make sure your **player has a Rigidbody** (it does, from this phase's movement script) - that one Rigidbody is enough to wake up the events for everything it touches. If events still don't fire, check: does each object have a Collider? Is the pickup's `isTrigger` actually checked? Are you moving the player via the **Rigidbody in `FixedUpdate`**, and not still teleporting `transform.position` from Phase 5 (which bypasses physics and can skip right past thin triggers)?

Keep that checklist handy. "Nothing happens" is never mysterious once you know the three things it can be: missing Rigidbody, missing Collider, or movement that dodges physics.

## Recap

- A **`Rigidbody`** hands a GameObject to the physics engine - gravity, forces, and collisions. Key knobs: `mass`, `useGravity`, `isKinematic` (true = you move it from code, but it still collides).
- Drive a Rigidbody in **`FixedUpdate`** (the physics clock) with `rb.MovePosition(...)`, `rb.AddForce(...)`, or `rb.velocity`, scaled by `Time.fixedDeltaTime` - never by editing `transform.position`, which bypasses physics (Phase 5).
- A **`Collider`** (`Box`, `Sphere`, `Capsule`, `Mesh`, plus 2D twins) gives an object a shape. **`isTrigger`** flips it from *blocking* (solid wall) to *sensing* (overlap volume).
- React to contact with **`OnCollisionEnter(Collision c)`** for solid hits and **`OnTriggerEnter(Collider other)`** for trigger overlaps (each also has `Stay`/`Exit`). Identify the other object with **`other.CompareTag("...")`**, not its name.
- Our pickup is a trigger that calls `Destroy(gameObject)` when the `"Player"` overlaps it - a complete collect mechanic.
- **The rule:** events need **at least one Rigidbody** and a **Collider on both** objects, or "nothing happens." That trio is the first thing to check.

## Quick check

```quiz
[
  {
    "q": "You add a trigger SphereCollider to a pickup, write OnTriggerEnter, and walk the player through it - but nothing fires. What is the most likely cause?",
    "choices": ["OnTriggerEnter must be spelled OnTriggerEntered", "Neither object has a Rigidbody, so no physics events fire", "Triggers only work in 2D games", "You must call Physics.Enable() in Start"],
    "answer": 1,
    "explain": "Collision and trigger events only fire when at least one of the two objects has a Rigidbody (and both have Colliders). Adding a Rigidbody to the player wakes the events up."
  },
  {
    "q": "What is the difference between a collider with isTrigger off versus on?",
    "choices": ["Off blocks movement and fires OnCollision events; on lets objects pass through and fires OnTrigger events", "Off is for 3D, on is for 2D", "On makes the object invisible", "There is no functional difference; it is only an editor label"],
    "answer": 0,
    "explain": "A solid collider (isTrigger off) physically blocks and fires OnCollisionEnter. A trigger (isTrigger on) is a sensing volume that things pass through, firing OnTriggerEnter instead."
  },
  {
    "q": "Where should you move a Rigidbody, and with which method?",
    "choices": ["In Update, by setting transform.position", "In FixedUpdate, with rb.MovePosition or rb.AddForce", "In Start, once", "In OnTriggerEnter, with Destroy"],
    "answer": 1,
    "explain": "Physics movement belongs in FixedUpdate (the physics step), driven through the Rigidbody via MovePosition, AddForce, or velocity - not by editing transform.position, which bypasses physics."
  }
]
```


---

# Prefabs & Instantiation

So far every object in your collect-the-pickups game has been a thing you placed by hand in the
editor - the player, the ground, a pickup or two you dropped into the scene. That works right up until
you want *twenty* pickups, or pickups that keep appearing while the game runs. You don't want to copy-paste
a GameObject twenty times and then, when you decide the pickup should be gold instead of blue, edit all
twenty by hand.

The fix is the single most important asset type in Unity: the **prefab**.

## The mental model: a prefab is a template

Here's the whole idea in one breath: **a prefab is a reusable GameObject saved as an asset - a template.
`Instantiate` stamps copies of it at runtime; `Destroy` removes them. Edit the prefab, and every copy
changes.**

📝 If you've used C# classes, the analogy is close: a prefab is like a *class*, and each thing you spawn
from it is an *instance*. One definition, many live copies. (It's not a perfect analogy - a prefab is data,
not code - but "template you stamp out" is exactly the right instinct.)

Think of it like a rubber stamp. You carve the stamp once. Then you press it onto the page as many times as
you like, and every imprint looks the same. Re-carve the stamp and every *future* imprint changes - and
with Unity prefabs, even the imprints already on the page update too, because each one stays linked to the
stamp. That linkage is what makes prefabs the DRY (don't-repeat-yourself) tool for game objects.

## Creating a prefab

You already have the raw material in your scene. To turn a GameObject into a prefab, you drag it from the
**Hierarchy** window down into the **Project** window. That's it - Unity creates a `.prefab` asset, and the
GameObject in your scene becomes a *linked instance* of it (its name turns blue in the Hierarchy to show the
connection).

Walk through it for the pickup:

1. Set up one pickup the way you want it - a small sphere, a Collider marked **Is Trigger**, a script that
   bumps the score, maybe a material so it glows.
2. Drag that GameObject from the Hierarchy into the Project window (a folder like `Assets/Prefabs` is a good
   home).
3. You now have a `Pickup` prefab asset. Delete the one in the scene if you want - the template lives on in
   the Project window, ready to be stamped out.

To change the prefab later, double-click the asset to open it in **Prefab Mode** (an isolated editing view),
make your edits, and save. Every instance in every scene - and every copy you spawn at runtime - picks up
the change. That's the edit-once-update-all payoff.

💡 **Prefab Variants** are prefabs that inherit from a base prefab, the way a subclass inherits from a parent
class. You make a `GoldPickup` variant of `Pickup`, override just its color and point value, and it still
tracks every *other* change you make to the base `Pickup`. Handy when you have a family of similar objects;
reach for it when you notice yourself making near-identical prefabs.

## Spawning copies at runtime: `Instantiate`

A prefab sitting in the Project window does nothing on its own - it's just a template. To put copies into the
running game you call **`Instantiate`** from a script:

```csharp
Instantiate(pickupPrefab, position, rotation);
```

`Instantiate` creates a fresh copy of the prefab in the scene and returns a reference to that new instance,
so you can capture it and tweak it:

```csharp
GameObject pickup = Instantiate(pickupPrefab, spawnPos, Quaternion.identity);
pickup.name = "Pickup (spawned)";
```

*What just happened:* we stamped out a new copy of `pickupPrefab` at `spawnPos` with no rotation, and the
return value `pickup` is *that specific copy* - not the template. Renaming `pickup` touches only this one
instance; the prefab asset and every other copy are untouched. Capturing the return value is how you spawn
something and then immediately give it speed, a target, a color, whatever this particular copy needs.

The mirror image is **`Destroy`**, which removes an object from the scene:

```csharp
Destroy(gameObject);          // remove this object now (end of frame)
Destroy(gameObject, 3f);      // remove it after 3 seconds
```

*What just happened:* the first line schedules this GameObject for removal - Unity actually deletes it at the
end of the current frame, not the instant you call it, so any code running right after still sees a valid
object. The second line delays removal by three seconds, which is perfect for "spawn a particle burst, then
clean it up" or "this pickup expires if nobody grabs it." Spawn with `Instantiate`, remove with `Destroy` -
that's the full lifecycle of a runtime object.

### The PickupSpawner

Let's make pickups actually appear in your game. Create an empty GameObject called `Spawner`, attach this
script, and your scene starts producing pickups on a timer:

```csharp
using UnityEngine;

public class PickupSpawner : MonoBehaviour
{
    [SerializeField] private GameObject pickupPrefab;
    [SerializeField] private float interval = 2f;

    void Start() => InvokeRepeating(nameof(Spawn), 1f, interval);

    void Spawn()
    {
        var pos = new Vector3(Random.Range(-5f, 5f), 0.5f, Random.Range(-5f, 5f));
        Instantiate(pickupPrefab, pos, Quaternion.identity);
    }
}
```

*What just happened:* `[SerializeField] private GameObject pickupPrefab` creates a slot in the Inspector where
you drag your `Pickup` prefab - that's how the script knows *what* to spawn. In `Start`, `InvokeRepeating`
tells Unity: call `Spawn` after a 1-second delay, then again every `interval` seconds, forever. Each `Spawn`
picks a random `x`/`z` somewhere on the ground (`y` is fixed at `0.5` so the pickup sits on the surface) and
calls `Instantiate` to stamp a new pickup there. `Quaternion.identity` means "no rotation" - Unity stores
rotations as quaternions, and `identity` is the do-nothing rotation, the rotational equivalent of zero. The
result: a pickup pops into existence every couple of seconds at a random spot, and your collect-the-pickups
game finally has things to collect.

## The trap: an unassigned prefab

⚠️ Here is the mistake nearly everyone hits at least once. You write `PickupSpawner`, hit Play, and the
console explodes with **`UnassignedReferenceException: The variable pickupPrefab of PickupSpawner has not
been assigned.`**

The cause: `[SerializeField] private GameObject pickupPrefab` declares the slot, but a slot is empty until
*you* fill it. You have to select the Spawner in the Hierarchy and **drag your Pickup prefab into that field
in the Inspector**. The script can't guess which prefab you mean - that wiring happens in the editor, not in
code. A null `pickupPrefab` throws the instant `Spawn` runs.

So the rule: any `[SerializeField]` reference you see in a script is a promise that you'll assign it in the
Inspector. If something "isn't working" and the console mentions `Unassigned`, an empty Inspector slot is
almost always the culprit - go look.

## When spawning gets heavy: object pooling

💡 `Instantiate` and `Destroy` are fine for a pickup every two seconds. But the moment you spawn *fast* - a
machine gun firing bullets, an explosion throwing particles, a wave of enemies - they become a performance
trap. Every `Instantiate` allocates memory, and every `Destroy` leaves garbage behind. Do that hundreds of
times a second and the **garbage collector** eventually has to sweep up, which causes a visible stutter - a
"GC hitch" - right when the action is most intense.

The fix is **object pooling**: instead of creating and destroying objects, you create a fixed pool of them up
front, then reuse them. When you need a bullet, you grab an inactive one from the pool and switch it on
(`SetActive(true)`); when it's done, you switch it off (`SetActive(false)`) and return it to the pool instead
of destroying it. No allocation, no garbage, no hitch - you're recycling the same handful of objects forever.

You don't need to build this by hand. Unity ships a built-in `ObjectPool<T>` in `UnityEngine.Pool` that
manages the get/release cycle for you. For your collect-the-pickups game, a pickup every couple of seconds is
nowhere near the threshold where pooling matters - plain `Instantiate`/`Destroy` is the right, simple choice
here. But file pooling away as *the* next step the day you build something spawn-heavy. Premature pooling is
wasted effort; pooling when you're spawning hundreds of objects a second is the difference between smooth and
stuttering.

## Recap

- A **prefab** is a reusable GameObject saved as an asset - a template you create by dragging a GameObject
  from the Hierarchy into the Project window. Edit the prefab and every linked instance updates.
- **`Instantiate(prefab, position, rotation)`** stamps a copy into the running scene and returns a reference
  to that new instance, so you can capture and customize it. `Quaternion.identity` means no rotation.
- **`Destroy(gameObject)`** removes an object (at end of frame); `Destroy(obj, seconds)` delays removal.
- A spawner references its prefab through a `[SerializeField]` field and spawns on a timer (e.g.
  `InvokeRepeating`).
- ⚠️ You must **assign the prefab in the Inspector** - an empty slot throws `UnassignedReferenceException`
  the moment you spawn.
- 💡 For spawn-heavy games, swap `Instantiate`/`Destroy` for **object pooling** (`ObjectPool<T>`) to avoid
  garbage-collection hitches - but only when you actually spawn fast.

## Quick check

```quiz
[
  {
    "q": "What does Instantiate(pickupPrefab, pos, Quaternion.identity) return?",
    "choices": ["Nothing (void)", "The prefab asset itself", "A reference to the newly spawned copy", "A boolean for success"],
    "answer": 2,
    "explain": "Instantiate returns a reference to the new instance in the scene, so you can capture it and modify that specific copy without touching the prefab asset."
  },
  {
    "q": "You hit Play and get 'UnassignedReferenceException: the variable pickupPrefab has not been assigned.' What's the fix?",
    "choices": ["Mark the field public instead of private", "Drag the Pickup prefab into the script's slot in the Inspector", "Call Instantiate twice", "Add a try/catch around Spawn"],
    "answer": 1,
    "explain": "A [SerializeField] field creates an Inspector slot that starts empty. You have to drag the prefab into that slot in the Inspector; the script can't guess which prefab you mean."
  },
  {
    "q": "Why prefer object pooling over Instantiate/Destroy when spawning many objects fast?",
    "choices": ["Pooling makes objects move faster", "It avoids the memory allocation and garbage-collection hitches that constant create/destroy causes", "Instantiate doesn't work for more than 10 objects", "Pooling is required for all prefabs"],
    "answer": 1,
    "explain": "Constant Instantiate/Destroy allocates memory and creates garbage, triggering GC stutters under heavy spawning. Pooling reuses a fixed set of objects (SetActive on/off), eliminating that churn."
  }
]
```


---

# UI, Audio & Building

You can move a player, collide with things, and spawn pickups (Phases 5–7). But right now collecting a pickup makes it vanish and... nothing else. No score on screen, no satisfying chime, no way to hand the game to a friend. This phase closes that gap.

Three pieces, one idea each:

> **UI is GameObjects living under a Canvas. A GameManager holds shared state (like the score) and updates that UI. Building exports your scenes to a platform people can actually run.**

That's the whole arc. The pickups game already *works* - this phase makes it *finished*. Hold the mental model: there's no separate "UI layer" with its own rules; a score label is just another GameObject with a text component, the same composition you've used since Phase 3. And a build isn't a mysterious export - it's Unity packaging the scenes you list into an app for the platform you pick.

## UI lives under a Canvas

Every bit of on-screen interface in Unity - text, buttons, images, sliders - lives as a child of a special GameObject called a **Canvas**. The Canvas is the drawing surface for UI; by default it renders in **screen-space overlay**, meaning it's painted flat on top of the game, unaffected by the camera or the 3D world. Move your camera around, and the score stays pinned to the corner. That's what you want for a HUD.

In the editor: right-click in the Hierarchy → **UI → Text - TextMeshPro**. Unity creates a Canvas for you automatically (if you don't have one) and drops the text inside it. The first time, it'll offer to import the **TMP Essentials** - say yes; that's the font data TextMeshPro needs.

> 📝 You'll see two text options: plain **Text** (the old, legacy UI text) and **Text - TextMeshPro**. Always reach for **TextMeshPro**. It's the modern text component - sharper rendering at any size, rich formatting, and it's what every current tutorial and project assumes. The legacy one is there for old projects; ignore it.

Position the text in the top-left using the Rect Transform's anchor presets, type a placeholder like `Score: 0`, and you've got a label on screen. Now you need a script to *change* that label as the game plays.

## Referencing and setting text from a script

A script reaches a UI text component the same way it reaches any component: you declare a field for it and drag the object in via the Inspector. The TextMeshPro types live in the `TMPro` namespace, so the file starts with a `using TMPro;`.

```csharp
using UnityEngine;
using TMPro;

public class ScoreLabel : MonoBehaviour
{
    [SerializeField] private TMP_Text label;

    void Start()
    {
        label.text = "Score: 0";
    }
}
```

*What just happened:* `using TMPro;` pulls in the TextMeshPro types so you can name them. `TMP_Text` is the component type for a TextMeshPro label (the on-screen kind is technically `TextMeshProUGUI`, but `TMP_Text` is the shared base - referencing that works and reads cleaner). `[SerializeField] private TMP_Text label;` makes an empty slot appear on this script in the Inspector; you drag your score text object onto it, and now `label` points at that component. Setting `label.text = "..."` changes the words shown on screen. That single `.text` assignment is the whole trick to live UI - change the string, the display updates.

That's the mechanism. But the *score* shouldn't live in a label script - it should live somewhere any part of the game can reach it. That's the job of a GameManager.

## The GameManager: one place for shared state

Your game has state that doesn't belong to any single object. The score isn't the player's, and it isn't a pickup's - it's the *game's*. The common pattern is a **GameManager**: a GameObject with one script that holds that shared state and owns the methods that change it.

Here's a minimal one for our game:

```csharp
using UnityEngine;
using TMPro;

public class GameManager : MonoBehaviour
{
    [SerializeField] private TMP_Text scoreText;
    private int score;

    public void AddPoint()
    {
        score++;
        scoreText.text = $"Score: {score}";
    }
}
```

*What just happened:* the GameManager keeps the score in a private `int` so nothing else can scribble on it directly. The only way to change it is `AddPoint()`, which bumps the score by one and immediately rewrites the on-screen label using a string interpolation (`$"Score: {score}"` drops the current number into the text). Make a GameObject named `GameManager`, attach this script, and drag your score text onto its `scoreText` slot. Now there's one trustworthy owner of the score, and one method that keeps the number and the display in sync - they can never drift apart, because they're updated in the same breath.

### Wiring it to the pickup (back to Phase 6)

Remember the pickup's trigger from Phase 6 - the `OnTriggerEnter` that fires when the player overlaps a pickup and then `Destroy`s it. That's exactly where the score should go up. The pickup needs a reference to the GameManager so it can call `AddPoint()`:

```csharp
using UnityEngine;

public class Pickup : MonoBehaviour
{
    [SerializeField] private GameManager gameManager;

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            gameManager.AddPoint();
            Destroy(gameObject);
        }
    }
}
```

*What just happened:* when the player enters the pickup's trigger, the pickup tells the GameManager to add a point, then destroys itself - the same disappear-on-collect from Phase 6, now with a consequence. The score ticks up, the label updates, the pickup vanishes. That's the full pickup-to-score loop closed. (Each pickup needs its `gameManager` slot filled; if your pickups are spawned from a prefab as in Phase 7, you'd hand them the reference when you `Instantiate` them, or have them find the manager - see the singleton note below.)

> 📝 **The singleton pattern - useful, easy to overuse.** Dragging a GameManager reference onto every pickup gets tedious fast. A very common shortcut is to make the GameManager a *singleton*: a static `Instance` any script can reach without a reference, e.g. `GameManager.Instance.AddPoint();`. You set it in `Awake` with `Instance = this;`. It's genuinely handy for the one or two truly global things in a game (the manager, an audio system). The smell is when *everything* becomes a singleton and your objects all secretly depend on global state - that makes the game hard to test and reason about. Use it sparingly, for things there's genuinely only ever one of.

## Audio: a sound when you collect

A game without sound feels half-asleep. Unity plays audio through two pieces working together: an **`AudioClip`** is the actual sound file (your chime, your music), and an **`AudioSource`** is the component that plays it. You attach an AudioSource to a GameObject, and tell it which clip to play.

For a one-off sound like a pickup chime, the right call is `PlayOneShot`:

```csharp
using UnityEngine;

public class GameManager : MonoBehaviour
{
    [SerializeField] private TMP_Text scoreText;
    [SerializeField] private AudioSource audioSource;
    [SerializeField] private AudioClip pickupSound;
    private int score;

    public void AddPoint()
    {
        score++;
        scoreText.text = $"Score: {score}";
        audioSource.PlayOneShot(pickupSound);
    }
}
```

*What just happened:* we gave the GameManager an `AudioSource` (the speaker) and an `AudioClip` (the chime), both filled via the Inspector. `audioSource.PlayOneShot(pickupSound)` plays the clip once, layered on top of anything else the source is doing - so rapid pickups chime over each other instead of cutting one another off. Putting this in `AddPoint()` means every score increase is *heard* as well as seen. (You'll need `using TMPro;` at the top too, for the `TMP_Text` field - keeping the snippet focused, that line is unchanged from before.)

For **background music** you don't trigger it from code at all - you set it up on the AudioSource component itself in the Inspector: drop in a music clip, and tick **Loop** and **Play On Awake**. That source starts the music the moment the scene loads and loops it forever, no script required.

> 💡 `PlayOneShot` is for fire-and-forget sound effects you might overlap (footsteps, coins, hits). The plain `audioSource.Play()` plays the source's assigned clip and *restarts* it if called again - better for music or a single looping sound, worse for rapid effects because each call cuts off the last.

## Building: from editor to a real app

Everything so far runs inside the Unity editor when you press Play. A **build** is Unity packaging your game into a standalone app - a `.exe`, a Mac app, an Android `.apk`, or a browser-playable WebGL folder - that runs without the editor. This is how the game leaves your machine.

Open **File → Build Settings** (in newer Unity versions this is **Build Profiles**, same idea). You'll do three things:

1. **Add your scenes.** There's a "Scenes In Build" list. Click **Add Open Scenes** (or drag scenes in) to include your game's scene. The order matters - the first scene in the list is the one that loads when the game starts.
2. **Pick a platform.** Windows, Mac, Linux, Android, iOS, or **WebGL**. WebGL is the magic one for sharing: it exports a build that runs in any modern browser, so you can put your game on a web page and someone plays it with a link - no install. Selecting a platform may trigger a one-time module download.
3. **Set Player settings and Build.** The Player settings hold your game's name, icon, and resolution options. Then hit **Build**, choose an output folder, and Unity compiles everything.

> ⚠️ **Scenes must be in the "Scenes In Build" list or they won't ship.** This trips up nearly everyone once: the game runs perfectly in the editor (where the open scene plays regardless), then the build launches to a black screen or the wrong level - because the scene you tested was never added to the list. Before every build, glance at that list and confirm your scenes are there, in the right order.

When the build finishes, you have a real, distributable game. The pickups demo is now something you can hand to someone.

> Building is the technical half of finishing. The other half - actually getting it in front of players, naming it, and not letting it rot in a folder - is its own discipline. [Ship Your Side Project](/guides/ship-your-side-project) is the mindset for crossing that last mile, and it applies to a game build exactly as much as to a web app.

## Recap

- **UI lives under a Canvas** - a special GameObject that draws the interface; text, buttons, and images are its children, rendered in screen-space overlay by default.
- Use **TextMeshPro** (`TMP_Text`) for text, not the legacy Text. A script changes a label by setting `.text` on a referenced component.
- A **GameManager** holds shared game state (the score) and owns the methods that change it, like `AddPoint()` - keeping the number and the displayed label in sync. The pickup's trigger from Phase 6 calls `AddPoint()`.
- The **singleton** pattern (a static `Instance`) makes a manager globally reachable - handy for the one or two truly global systems, a smell when overused.
- **Audio** = an `AudioSource` (the speaker) playing an `AudioClip` (the sound). `PlayOneShot(clip)` for overlapping effects; an AudioSource with Loop + Play On Awake for background music.
- A **build** packages your scenes into a standalone app via Build Settings: add scenes (or they won't ship), pick a platform (WebGL for browser play), set Player settings, and Build.

## Quick check

```quiz
[
  {
    "q": "What does every UI element in Unity need as a parent?",
    "choices": ["A Rigidbody", "A Canvas", "The Main Camera", "A GameManager"],
    "answer": 1,
    "explain": "UI elements (text, buttons, images) live as children of a Canvas, the special GameObject that draws the interface - by default in screen-space overlay, on top of the game."
  },
  {
    "q": "Why keep the score in a GameManager with an AddPoint() method instead of in the pickup or player script?",
    "choices": ["It makes the game build faster", "Shared state needs one owner, and AddPoint() keeps the number and the on-screen label in sync", "Pickups cannot hold integer values", "Unity requires a script named GameManager"],
    "answer": 1,
    "explain": "The score belongs to the game, not any single object. One owner with one update method means the score value and its displayed label can never drift out of sync."
  },
  {
    "q": "Your game runs fine in the editor, but the build launches to a black screen. What is the most likely cause?",
    "choices": ["You forgot to attach an AudioSource", "The scene was never added to the Scenes In Build list", "TextMeshPro Essentials were not imported", "The Canvas is in world-space mode"],
    "answer": 1,
    "explain": "The editor plays whatever scene is open, but a build only includes scenes in the Scenes In Build list. A scene missing from that list won't ship, so the build has nothing to load."
  }
]
```


---

# Where to Go Next

Look at what you can actually do now. You can open the Unity editor and not feel lost in it. You understand that a scene is a pile of **GameObjects**, each one a bag of **Components**, and that your scripts are Components the engine wires into its own loop. You've written a `MonoBehaviour` with `Start` and `Update`, moved an object frame-rate-independently, read input, given things a Rigidbody and watched physics catch collisions, spawned objects from a **prefab** at runtime, put a score on screen, played a sound, and **built** the whole thing into something a person can run. That's not a tech demo you copied. That's a game. You made it.

And the quiet bigger win: the composition model you held onto the whole way through isn't a Unity quirk, it's how the engine *thinks*. You can read a scene now. You can look at a GameObject in the Inspector, see its stack of Components, and reason about why it behaves the way it does. That instinct carries into everything you build next.

So this last phase isn't more `Update` loops. It's the map: where Unity sits among the other engines, the features you'll reach for as your games get bigger, a clear word about what gamedev actually demands, and one concrete thing to go finish.

## Unity vs the field

Unity isn't the only engine, and pretending otherwise does you no favors. Here's the clear-eyed lay of the land for the three you'll hear about most.

```mermaid
flowchart TD
  You[What are you building?] --> M{Mobile / indie / C#?}
  M -->|yes| U[Unity - C#, huge ecosystem]
  M -->|2D or open-source| G[Godot - free, light]
  M -->|high-end 3D / AAA| UE[Unreal - C++ + Blueprints]
```

- **Unity** - C#, an enormous asset store and community, and it ships everywhere: mobile, desktop, console, web. It's the workhorse of indie and a lot of AA. (You're here, and you already speak its language.)
- **Godot** - free and fully open-source, lighter and faster to start, with its own **GDScript** (and C# support too). It shines for 2D and small indie projects, and there's no company or license fee between you and your game.
- **Unreal** - C++ plus **Blueprints** (a visual, node-based scripting system), with AAA-grade rendering out of the box. It's aimed at bigger, high-end 3D projects and is the standard in a lot of studios.

💡 If you already know C#, Unity is a strong default, especially for mobile and indie. Reach for Godot when you want open-source and 2D; reach for Unreal when you're chasing high-end 3D and don't mind C++. The language matters less than people think, but if you want to deepen the one Unity speaks, [C# From Zero](/guides/csharp-from-zero) is right next door.

None of these is "the best engine." They're aimed at different jobs, and knowing which fits *this* project is the senior instinct. You've got the pieces for it now.

## What to learn next in Unity

You learned the engine's spine. These are the next vertebrae, roughly in the order they'll start to matter.

- **ScriptableObjects** - data as assets. Instead of stuffing config, item definitions, or event channels into GameObjects, you make a `ScriptableObject` asset that lives in your project and gets shared and edited in the Inspector. It's how you keep data out of your scenes and your designers happy.
- **Coroutines** - for timed sequences. A method returning `IEnumerator` with `yield return` lets you spread work across frames: wait two seconds, then spawn; fade something out over time; run a step-by-step intro. It's the everyday tool for "do this, wait, then do that."
- **The Animator** - Unity's animation state machine, for character animation, transitions, and blends. Anything that moves with more life than a script nudging a Transform usually runs through here.
- **The new Input System** - action-based input that maps "Jump" or "Move" to keys, buttons, and gamepad sticks without hard-coding devices. It's where input is heading; worth adopting once your control scheme grows past a couple of keys.
- **The Asset Store & Package Manager** - you don't build everything from scratch. The Asset Store has art, tools, and systems; the Package Manager pulls in official Unity packages. Learning to lean on these well is its own skill.
- **DOTS / ECS** - the data-oriented stack, for when you need *thousands* of objects on screen at once and the normal GameObject model can't keep up. It's advanced and a real shift in thinking. File it under "later, if a project demands it" - don't reach for it early.

A small `ScriptableObject` to hold your pickup's settings, a coroutine to spawn pickups on a timer - those two alone will level up the game you already have.

## Gamedev is more than code

📝 Here's the thing nobody tells you early enough: gamedev is as much **design, art, and audio** as it is programming. A mechanically perfect game with no feel, no art, and no sound is a prototype, not a game. You'll spend real time on level pacing, on how a jump *feels*, on a sound that makes a pickup satisfying. That's not a distraction from the "real" work - it *is* the work.

And the hardest, most important lesson: **small finished games beat big unfinished ones.** Every beginner has a sprawling dream project. Almost none of them ship it. The ones who get good are the ones who finished something small, learned what finishing actually costs, and did it again.

The best forcing function for that is a **game jam**. Events like **Ludum Dare** and **GMTK Jam** give you a theme and a deadline (often 48 hours), and the deadline does something tutorials can't: it makes you *ship*. You'll cut scope, solve real problems, and have a finished thing at the end. Do one. It's worth more than a month of reading.

## What to build

Reading more won't make this stick. Finishing one real thing will. So, concretely:

**First, extend the pickups game you built.** Add a **timer** so rounds end. Add **lives**. Add a couple of **levels** that ramp up. Put a **start menu** in front of it and a **game over** screen behind it. Every one of those touches something you learned: UI, game state, prefabs, audio. You'll hit small walls, and climbing them is where the learning is.

**Then, build one small game end to end and publish it.** Pick something tiny and complete it all the way: title screen, gameplay, a win and a lose, and a build you can hand to someone. Then **put it online** - [itch.io](https://itch.io) is the friendliest home for indie games, and a **WebGL** build runs right in the browser so anyone can play with a link. Shipping something a stranger can play is a different feeling from anything a tutorial gives you. Go get it.

And remember the through-line. A scene is a pile of **GameObjects**. Each one is a bag of **Components**. Your scripts are Components among them, and the engine calls them every frame. That's not one kind of Unity game - that's *every* Unity game. You understand it, and now you build them. Go finish something, publish it, and show someone.

## Recap

1. **You shipped a real game** - editor, GameObjects and Components, the `MonoBehaviour` loop, movement and input, physics and collisions, prefabs and spawning, UI and audio, and a finished build. And you understand the composition model underneath it.
2. **Choose your engine on purpose** - Unity for C#/mobile/indie, Godot for open-source and 2D, Unreal for high-end 3D. None is "best"; each fits a different job.
3. **Learn the next features as you need them** - ScriptableObjects for data, Coroutines for timed sequences, the Animator for animation, the new Input System, the Asset Store, and DOTS/ECS only when sheer object counts demand it.
4. **Gamedev is design, art, and audio too** - not just code. Small finished games beat big unfinished ones, and a game jam (Ludum Dare, GMTK) is the fastest way to learn to ship.
5. **Build one thing and finish it** - extend the pickups game (timer, lives, levels, menu), then make one small complete game and publish it on itch.io or as a WebGL build.

## Quick check

Three calls to take with you as you leave this guide:

```quiz
[
  {
    "q": "You already know C# and want to build a 2D mobile indie game with a big community and asset ecosystem behind you. Which engine fits best?",
    "choices": [
      "Unreal, because it has the best rendering",
      "Unity, a strong C# default for mobile and indie with a huge ecosystem",
      "Godot, because it's the only one that does 2D",
      "It doesn't matter; all engines are identical"
    ],
    "answer": 1,
    "explain": "Unity is a strong default for C# developers targeting mobile and indie, with an enormous asset store and community. Godot is the open-source/2D pick and Unreal aims at high-end 3D, but none is universally 'best' - it depends on the job."
  },
  {
    "q": "You want to store your pickup's settings as a shared, editable data asset that lives in the project rather than on a GameObject. What's the right Unity feature?",
    "choices": [
      "A Coroutine",
      "A ScriptableObject",
      "The Animator",
      "DOTS / ECS"
    ],
    "answer": 1,
    "explain": "ScriptableObjects are data assets - config, item definitions, event channels - that live in your project and are edited in the Inspector, keeping data out of your scenes. Coroutines handle timed sequences, the Animator handles animation, and DOTS is for massive object counts."
  },
  {
    "q": "Which piece of advice matches the straight-talk take on getting good at gamedev?",
    "choices": [
      "Start with a huge ambitious project so you learn everything at once",
      "Gamedev is purely a programming problem; art and audio don't matter",
      "Finish small games and try a game jam - small finished beats big unfinished",
      "Skip publishing; nobody needs to play what you build"
    ],
    "answer": 2,
    "explain": "Gamedev is design, art, and audio as much as code, and small finished games beat big unfinished ones. Game jams like Ludum Dare and GMTK force you to ship, which teaches more than tutorials - and publishing something playable is the real milestone."
  }
]
```
