GameObjects & Components
The one idea Unity is built on
Almost every confusing thing about Unity becomes obvious once this one idea clicks: a GameObject does nothing by itself. It is an empty container. Everything you can see, hear, or interact with comes from the components attached to it.
A GameObject is an empty box
Create an empty GameObject in a scene and you get almost nothing: a name, a position, and a place in the hierarchy. It does not render. It does not collide. It has no behaviour. It is a label with coordinates.
What makes a GameObject into a player, an enemy, a door, or a camera is the set of components bolted onto it. Change the components and you change what the object is.
The same box, different components
| What you want | Components you attach | Note |
|---|---|---|
A visible cube | MeshFilter + MeshRenderer | Geometry, then the material that draws it |
A physical crate | + BoxCollider + Rigidbody | Collider gives it shape, Rigidbody gives it mass |
A trigger zone | BoxCollider (Is Trigger) | No renderer at all — invisible in play mode |
A player | + your own MonoBehaviour | Your script is a component like any other |
A camera | Camera + AudioListener | Both are built-in components |
Transform. You cannot remove it. That is the only guaranteed component — everything else is optional.Your scripts are components too
When you write a class that extends MonoBehaviour, you are writing a component. Unity can attach it to a GameObject, show its public fields in the Inspector, and call its lifecycle methods.
using UnityEngine;
// This class becomes a component the moment it extends MonoBehaviour
public class Health : MonoBehaviour
{
[SerializeField] private int maxHealth = 100;
private int current;
private void Awake()
{
current = maxHealth;
}
public void TakeDamage(int amount)
{
current = Mathf.Max(0, current - amount);
if (current == 0)
Destroy(gameObject); // destroys the whole GameObject
}
}Destroy(this) removes only this component. Destroy(gameObject) removes the entire object. Mixing these up produces enemies that stop taking damage but stay on screen forever.Talking to other components
Components on the same GameObject find each other with GetComponent<T>(). It is a search, not a free lookup, so cache the result instead of calling it every frame.
public class Enemy : MonoBehaviour
{
private Rigidbody rb;
private Health health;
private void Awake()
{
// Look them up once, reuse forever
rb = GetComponent<Rigidbody>();
health = GetComponent<Health>();
}
private void FixedUpdate()
{
rb.AddForce(Vector3.forward);
}
}public class Enemy : MonoBehaviour
{
private void FixedUpdate()
{
// Searching the component list every single physics step.
// Works, but it is wasted time in your hottest loop.
GetComponent<Rigidbody>().AddForce(Vector3.forward);
}
}There are directional variants when the component lives elsewhere in the hierarchy:
GetComponent<T>()— this GameObject onlyGetComponentInChildren<T>()— this object and everything beneath itGetComponentInParent<T>()— this object and everything above itGetComponents<T>()— all matches, not just the first
null unexpectedly, check whether the component is on a child rather than the object itself. A model imported from Blender usually puts the renderer on a child, not the root.Require what you depend on
If your script cannot work without another component, say so. [RequireComponent] makes Unity add it automatically and stops anyone removing it while your script is attached.
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Movement : MonoBehaviour
{
private Rigidbody2D rb;
private void Awake()
{
// Guaranteed to exist, so no null check needed
rb = GetComponent<Rigidbody2D>();
}
}Composition over inheritance
Coming from other engines or from classic OOP, the instinct is to build a class tree: Entity → Character → Enemy → FlyingEnemy. Unity pushes the opposite way. Instead of one deep class, you write several small components and mix them.
A flying enemy that explodes is not a new class. It is a GameObject with Health, FlightMovement, and ExplodeOnDeath attached. Want a ground enemy that explodes? Swap one component. No new subclass, no refactor.
Why this matters more than it sounds
Deep inheritance chains force you to decide the shape of every future object up front. The moment you need a variant that does not fit the tree, you either duplicate a branch or push behaviour up into a base class where it does not belong.
With composition, each behaviour is written once and reused freely. A designer can build a new enemy type in the Inspector without you writing any code at all — which is the actual point.
When inheritance is still fine
Composition is the default, not a religion. A shared abstract base for a family of genuinely related components is perfectly reasonable — for example a Weapon base with Pistol and Shotgun deriving from it, where every weapon truly does share the same interface.
The rule of thumb: inherit to share implementation between things that are the same kind of thing. Compose to combine different kinds of behaviour on one object.
Active, enabled, and the difference
These two are not the same, and mixing them up causes bugs that look like the engine misbehaving.
| Call | Effect | Note |
|---|---|---|
gameObject.SetActive(false) | Disables the whole object | All components stop, children deactivate too |
myComponent.enabled = false | Disables one component | Update stops, but the object stays in the scene |
gameObject.activeSelf | Is this object switched on? | Ignores whether a parent is off |
gameObject.activeInHierarchy | Is it actually running? | False if any parent is inactive |
Update, does not receive collisions, and cannot be found by GameObject.Find. Coroutines started on it are stopped, not paused — they do not resume when you switch it back on.What to take away
- A GameObject is a container; components give it behaviour.
- Your
MonoBehaviourscripts are components, no different from built-in ones. - Cache
GetComponentresults inAwakerather than calling them per frame. - Declare hard dependencies with
[RequireComponent]. - Prefer several small components over one deep class hierarchy.
SetActiveaffects the object;enabledaffects one component.