AnyLearn
All lessons
Programmingintermediate

Unity: the GameObject and component model

Unity is built on composition, not inheritance: a GameObject is an empty container, and everything it can do comes from components bolted onto it. Learn the Transform and scene graph, how components find each other, the active-versus-enabled trap, and why composition beats a deep class hierarchy for games.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 9

Why games reject deep inheritance

The obvious way to model a game is a class tree: Entity, then Character, then Player. It collapses the moment requirements cross the branches. A crate that is destructible but not alive, an enemy turret that shoots but cannot move, a pickup that floats and glows. Each new combination wants to inherit from two places at once, and single inheritance says no.

Unity's answer is composition. There is no Player class in the engine. There is a GameObject, which is essentially an empty bag with a name, plus a list of components you attach to it. A component contributes one capability: a shape, a renderer, physics, your own script.

A thing in a Unity scene is therefore defined by what it has, not by what it is. Combinations become additive instead of a taxonomy problem.

Full lesson text

All 9 steps on one page, for reading, reference, and search.

Show

1. Why games reject deep inheritance

The obvious way to model a game is a class tree: Entity, then Character, then Player. It collapses the moment requirements cross the branches. A crate that is destructible but not alive, an enemy turret that shoots but cannot move, a pickup that floats and glows. Each new combination wants to inherit from two places at once, and single inheritance says no.

Unity's answer is composition. There is no Player class in the engine. There is a GameObject, which is essentially an empty bag with a name, plus a list of components you attach to it. A component contributes one capability: a shape, a renderer, physics, your own script.

A thing in a Unity scene is therefore defined by what it has, not by what it is. Combinations become additive instead of a taxonomy problem.

2. The GameObject and its Transform

A GameObject on its own does almost nothing. It has a name, an active flag, a layer, a tag, and exactly one component it can never lose: the Transform.

The Transform holds position, rotation, and scale, and it is also the parent link. That dual job is the point: parenting objects is done through their Transforms, which is why the scene hierarchy and the spatial hierarchy are the same tree.

// Every GameObject has one, always.
transform.position = new Vector3(0f, 1f, 0f);   // world space
transform.localPosition = Vector3.zero;         // relative to parent
transform.SetParent(hangar.transform);          // reparent

print(transform.childCount);
Transform first = transform.GetChild(0);

Moving a parent moves every descendant, because children store their position relative to the parent. That single rule explains turrets riding on tanks, UI nesting, and why an object jumps when you reparent it carelessly.

3. Components: where behavior lives

Everything beyond position comes from components. A cube that renders needs a MeshFilter (which mesh) and a MeshRenderer (which material). A thing that falls needs a Rigidbody. A thing that collides needs a Collider. Your own logic is a class deriving from MonoBehaviour, which is just another component.

using UnityEngine;

public class Health : MonoBehaviour
{
    [SerializeField] private int max = 100;
    private int current;

    private void Awake() => current = max;

    public void Damage(int amount)
    {
        current -= amount;
        if (current <= 0) Destroy(gameObject);   // the whole object
    }
}

Note Destroy(gameObject) versus Destroy(this): the first removes the entire object, the second removes only this one component and leaves the rest running. Components are independent parts of a whole, and they can be added and removed at runtime.

4. How components find each other

Components on the same GameObject are siblings, and they look each other up through the object.

private Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();              // same object
    var gun = GetComponentInChildren<Gun>();     // this or below
    var rig = GetComponentInParent<Rig>();       // this or above
}

GetComponent walks the object's component list, so it is not free. Cache it in Awake once, never call it every frame.

Avoid GameObject.Find("Player") and FindObjectOfType. They scan the scene, they are slow, and Find matches on a string name so renaming an object in the Editor silently breaks code with no compiler error. Prefer a [SerializeField] reference you drag in the Inspector: it is checked, it is fast, and it survives renames because it is stored as a real reference.

5. Active objects versus enabled components

Two switches look similar and are not. This trips up nearly everyone once.

  • gameObject.SetActive(false) deactivates the whole object and every child. Nothing on it runs. Update stops, physics stops, renderers vanish.
  • component.enabled = false disables one component. The object still exists, its other components keep running.
gameObject.SetActive(false);      // object and all children: off
GetComponent<Renderer>().enabled = false;  // invisible, still collides
GetComponent<Health>().enabled = false;    // Update stops, object stays

The gotcha: enabled only gates the lifecycle callbacks (Update, OnEnable). It does not stop other scripts from calling your public methods, and a disabled Collider still stops colliding while a disabled Renderer still collides. Also, activeSelf is this object's own flag, while activeInHierarchy accounts for a deactivated parent, and a child of an inactive parent never runs no matter what its own flag says.

6. A real object, assembled

Concretely, a player character is not a class. It is a GameObject wearing a stack of components:

ComponentContributes
Transformposition, rotation, parenting (mandatory)
CapsuleColliderthe shape physics sees
Rigidbodymass, gravity, forces
MeshRenderer + MeshFilterthe visible body
Animatorthe animation state machine
PlayerInput (yours)reads the controller
Health (yours)damage and death

Swap PlayerInput for an AiBrain component and the same body becomes an enemy. Delete Rigidbody and it becomes scenery. Add Health to a crate and the crate is destructible, with zero shared base class between crate and player.

That substitution is the whole payoff of composition: capabilities move between objects freely because they were never welded into a class hierarchy.

7. Composition versus inheritance, concretely

The tradeoff is real, not ideological.

deep inheritanceUnity composition
new combinationnew class, often duplicatedattach a component
shared behaviorin a base classin a component
cross-cutting traitsmultiple inheritance, blockedjust add both
where is the logicfollow the class chaininspect the object
costrigid, brittlemany small objects, indirection

Composition is not free. Logic is scattered across components, so answering what does this do means reading the Inspector rather than one file, and components must agree on shared state. Order between components is also not guaranteed by default, which the lifecycle lesson covers.

What you should not do is fight it. Deep MonoBehaviour hierarchies are a common beginner instinct and they reintroduce every problem composition removed. Keep components small, focused, and ignorant of each other where you can.

8. The limits, and what comes next

This model is object-oriented at heart: each GameObject is a heap object, each component is a heap object holding a reference back. That is flexible and cache-hostile. Iterating ten thousand enemies means chasing pointers all over memory, which is why Unity also ships a data-oriented stack (DOTS/ECS) that stores components as tight arrays instead. Different tradeoff, same vocabulary of entity and component.

For almost everything you will build, the classic GameObject model is the right tool, and it is what the Editor, prefabs, and the Inspector are built around.

The model raises two questions the rest of this path answers. When does each component's code actually run, given no guaranteed order between them? And how does an object built in the Editor survive being saved to disk and loaded back exactly as configured?

9. How an object is put together

A GameObject is a container. The Transform is mandatory and also holds the parent link, so the scene tree and the spatial tree are one and the same. Every other capability is an attached component.

flowchart TD
  A["GameObject: Player"] --> B["Transform (mandatory): position and parent link"]
  A --> C["Rigidbody: mass and forces"]
  A --> D["CapsuleCollider: shape physics sees"]
  A --> E["MeshRenderer: how it looks"]
  A --> F["PlayerInput (your MonoBehaviour)"]
  A --> G["Health (your MonoBehaviour)"]
  B --> H["child GameObject: Gun"]
  H --> I["its own Transform, local to Player"]

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. Which component can a GameObject never exist without?
    • Rigidbody
    • Transform
    • MeshRenderer
    • Collider
  2. Inside a MonoBehaviour, what is the difference between `Destroy(gameObject)` and `Destroy(this)`?
    • They are identical; both remove the whole object
    • Destroy(this) removes the object, Destroy(gameObject) removes the script
    • Destroy(gameObject) removes the whole object, Destroy(this) removes only this component
    • Destroy(this) is invalid inside a MonoBehaviour
  3. Why is `GameObject.Find("Player")` a poor way to wire up a reference?
    • It only works on inactive objects
    • It scans the scene and matches a string name, so a rename breaks it with no compiler error
    • It cannot return components, only meshes
    • It is blocked outside of Awake()
  4. A GameObject has a Renderer and a Collider. You set `GetComponent<Renderer>().enabled = false`. What happens?
    • The whole object deactivates, including its children
    • The object is destroyed at the end of the frame
    • Both the Renderer and the Collider stop working
    • The object becomes invisible but still collides
  5. You need an enemy that reuses the player's body but is computer-controlled. The composition answer is:
    • Swap the input component for an AI component on the same object
    • Create an Enemy class inheriting from Player
    • Duplicate the Player script and edit the copy
    • Add an `isEnemy` boolean to the Player script

Related lessons

Programming
intermediate

Unity: prefabs, assets, and serialization

How a Unity object survives being saved to disk and loaded back exactly as configured. Covers what serialization actually accepts, why GUIDs in .meta files matter more than filenames, prefabs and variants with their override rules, ScriptableObjects as shared data, and the field that keeps reverting to zero.

9 steps·~14 min
Programming
intermediate

Unity: the script lifecycle and execution order

When your Unity code actually runs. Covers the Awake, OnEnable, Start ordering guarantees, the split between Update, FixedUpdate, and LateUpdate, why deltaTime is mandatory, how coroutines fit the frame, and the allocation habits that turn a smooth game into a stuttering one.

9 steps·~14 min
Programming
intermediate

Unity: physics and the fixed timestep

Why Unity runs physics on its own 50Hz clock instead of the frame rate, and what follows from that. Covers rigidbodies and colliders, moving things correctly with forces rather than the Transform, interpolation for smooth motion, tunneling and continuous collision detection, and where physics cost actually comes from.

9 steps·~14 min
Programming
advanced

The Failure Modes the Design Creates

Reconciliation buys robustness and charges for it in a specific currency: nothing is ever definitely finished, commands succeed without meaning anything worked, and manual fixes are silently undone. This lesson covers the failures that come from the model rather than from bugs, how to debug them, and when the whole thing is the wrong tool.

8 steps·~12 min