Lesson 8 - Colliders, Triggers and Collision Callbacks

Which pairs of objects actually report contact and which stay silent: the Rigidbody rule, the trigger switch, the difference between OnCollisionEnter and OnTriggerEnter, and why CompareTag beats comparing tag strings.

Subject: Unity Game Engine · 62 slides · code lesson

Open the interactive version of this deck · Homework for this lesson

What this lesson covers

The lesson, slide by slide

1. Colliders, Triggers and Callbacks

Title

Unity - Lesson 8

Which pairs of objects talk to each other - and which overlap in complete silence.

2. What you will be able to do

Objectives

The diagnostic got 2 of 3 here, both with low confidence. That pattern - right answers, no certainty - is what this deck is for: a rule you can derive beats one you half remember.

  1. State the two switches that decide whether any callback fires at all
  2. Predict which of OnCollisionEnter and OnTriggerEnter you will get, before running it
  3. Explain why two static colliders can overlap and report nothing
  4. Read the callback signature and know what data you have
  5. Identify what you hit with CompareTag, and say why the == version is worse

3. Answer from memory

Warm-up

Before anything else.

Discussion prompt

A ball rolls into a wall. Both have colliders. Under what circumstances does your OnCollisionEnter get called - and on which of the two objects?

Hint: One of the two objects has to be doing something the other is not.

Answer:

At least one of the pair needs a Rigidbody. Normally that is the ball; the wall has a collider and nothing else, and that is correct level design.

Both objects get the callback. Unity delivers it to both sides of the pair, so the script can live on either - which surprises people who assume only the moving one is told.

If neither has a Rigidbody, nothing happens at all. That is the row worth remembering.

4. A collider is a shape

Section

Part 1

5. Shape for contact tests, nothing more

Concept

A Collider defines the volume the physics engine tests against. It does not draw anything, does not move anything, and does not make an object physical - lesson 3's Rigidbody does that.

Collider — A shape attached to a GameObject, used to test whether things touch. Independent of the mesh you see and independent of whether the object is simulated.

The collider and the visible mesh are separate. A capsule collider on a detailed character model is normal and desirable - the shape is for physics, not for looks.

Unity Manual - Colliders Colliders

6. The five you will use

Concept

collidershapecostuse for
Boxa boxcheapestcrates, walls, most scenery
Spherea ballcheapestballs, blast radii, pickups
Capsulea pillcheapcharacters - it does not catch on steps
Meshthe actual meshexpensivecomplex static geometry only
Compound (several primitives)whatever you buildcheapan L-shape, a chair, a vehicle

A Mesh Collider cannot be dynamic unless you tick Convex, and even then it is the last resort. Building a shape out of two or three boxes is faster in every sense - to compute, and to reason about.

7. Predict: the invisible wall

Prediction

A cube with a Box Collider and its Mesh Renderer removed.

Predict first

What is it now?

  • Nothing - with no renderer it does not exist
  • An invisible object that things still bump into
  • An invisible object that things pass through
  • It errors on Play

Correct: An invisible object that things still bump into.

Why: Being drawn and being solid are separate capabilities from separate components - lesson 1's model, applied. Every invisible boundary in every game you have played is exactly this: a collider with no renderer.

8. The two switches

Concept

Figure (svg): Three lanes showing a dynamic body hitting a solid wall, passing through a trigger, and two static colliders overlapping in silence

The third row is the one that costs people an evening.

Whether anything is reported when two colliders meet depends on exactly two questions.

  1. Is there a Rigidbody on at least one of the pair? No - nothing happens at all.
  2. Is either of them a trigger? Yes - you get OnTrigger* and nothing is stopped. No - you get OnCollision* and things are stopped.

Everything else in this lesson is a consequence of those two lines.

Unity Manual - Collision action matrix Collision action matrix

9. Which of these need a collider?

Sorting

Sort into buckets

Collider, or no collider?

Needs a collider
A wall the player cannot walk through; A checkpoint the player runs through; A bullet
No collider
A decorative cloud in the sky; A UI health bar
yes
Something has to be able to touch it, or it has to be able to touch something. The checkpoint is the interesting one - it needs a collider with Is Trigger ticked, because it must detect the player without blocking them.
no
Nothing ever touches it physically. Decorative geometry and UI have no business in the physics simulation, and giving them colliders costs performance for nothing.

10. Reading what an object is, in collision terms

Worked example

The lab describes each object in the two terms that matter.

public string Describe()
{
    Collider shape = GetComponent<Collider>();
    Rigidbody body = GetComponent<Rigidbody>();

    string kind = shape == null ? "no collider"
        : shape.isTrigger ? "trigger collider" : "solid collider";
    string physics = body == null ? "no Rigidbody"
        : body.isKinematic ? "kinematic Rigidbody" : "dynamic Rigidbody";

    return $"{kind} + {physics}";
}
objectDescribe() returnswhat it can do
Ball Asolid collider + dynamic Rigidbodymoves, is stopped, reports
Solid Wallsolid collider + no Rigidbodystops things, reports, never moves
Trigger Zonetrigger collider + no Rigidbodydetects, never stops
Static Xsolid collider + no Rigidbodynothing happens with Static Y

Two words describe every object in the matrix

Why: kind of collider, and kind of body. Once you can say those two for both objects in a pair, the outcome is determined.

11. Why do two static colliders report nothing?

Explain it to yourself

Discussion prompt

Two cubes with colliders and no Rigidbodies are overlapping. Explain why Unity fires no callback - and why that is a deliberate design choice rather than an oversight.

Answer:

Because neither is being simulated. Static colliders are baked into a structure the engine uses to answer 'what is near this moving thing?', and static-against-static pairs are never queried at all.

The reason is cost. A level has thousands of static colliders; testing every pair of them every frame would be enormous work to discover something that by definition never changes - they are static, so their overlap is the same this frame as last.

12. Trap: 'both have colliders, so they will collide'

Trap

The trap

Two objects, two colliders, overlapping. Something should fire.

Static X   BoxCollider, no Rigidbody
Static Y   BoxCollider, no Rigidbody
They overlap by half a metre.

OnCollisionEnter on X: never called
OnCollisionEnter on Y: never called

No error, no warning, no log line. The most confusing kind of failure: nothing at all.

The fix

Give one of them a Rigidbody, and pick the kind that matches what it should do.

Static X   BoxCollider, no Rigidbody          (still fine as scenery)
Mover Y    BoxCollider + Rigidbody            (dynamic: falls and is pushed)
           or BoxCollider + kinematic Rigidbody, moved with MovePosition

Now both objects receive OnCollisionEnter.
what Y should dogive it
fall and be pushed arounda dynamic Rigidbody
move exactly as you script ita kinematic Rigidbody + MovePosition
never move, but be detectedleave it static and make the OTHER one the mover

13. Triggers: detect without blocking

Section

Part 2

14. Is Trigger turns a wall into a sensor

Concept

Tick Is Trigger on a collider and it stops resolving contacts. Things pass straight through it, and instead of OnCollision* you get OnTrigger*.

That is the whole feature: a volume that notices you without stopping you. Checkpoints, pickups, damage zones, doors that open, cutscene starts - all triggers.

Unity Scripting API - MonoBehaviour.OnTriggerEnter OnTriggerEnter

15. A doorway versus a door

Intuition

A door stops you and you feel it. A doorway with a sensor above it notices you and does nothing to your movement.

Both are 'the same shape in the same place'. The difference is entirely in whether anything is pushed back - and Unity spells that difference isTrigger.

16. Predict: which callback?

Prediction

A ball with a dynamic Rigidbody rolls into a box whose collider has Is Trigger ticked. The ball's script defines both OnCollisionEnter and OnTriggerEnter.

Predict first

Which one runs?

  • Both - a trigger is still a collision
  • OnCollisionEnter only
  • OnTriggerEnter only
  • Neither - the trigger has no Rigidbody

Correct: OnTriggerEnter only, and the ball keeps going.

Why: A trigger anywhere in the pair means the whole interaction is a trigger interaction. There is no collision to report, because nothing was resolved - which is exactly why the parameter is a Collider and not a Collision. This is the first misconception the diagnostic recorded.

17. The two callback families

Concept

Figure (svg): Two callback signatures side by side showing Collision carries contact data and Collider does not

The parameter type is the tell: a resolution, or just a shape that entered.

Six callbacks, two families of three. The parameter type tells you which family you are in.

Unity Scripting API - MonoBehaviour.OnCollisionEnter OnCollisionEnter

18. The signatures, and what they carry

Worked example

Get the type wrong and Unity never calls your method - with no error.

void OnCollisionEnter(Collision collision)
{
    GameObject other = collision.gameObject;
    int points = collision.contactCount;             // where they touched
    Vector3 impact = collision.relativeVelocity;     // how hard
}

void OnTriggerEnter(Collider other)
{
    GameObject them = other.gameObject;
    // no contact points, no impulse: nothing was resolved
}
you haveOnCollisionEnterOnTriggerEnter
the other GameObjectcollision.gameObjectother.gameObject
contact pointsyesno
relative velocityyesno
was anything stopped?yesno
parameter typeCollisionCollider

The parameter type is the tell

Why: Collision describes a resolution - what was stopped, where, how hard. Collider is just the shape that entered.

19. Match the job to the callback

Matching

Match the pairs

Which callback for each job?

  • j1. Play a crash sound scaled by impact force
  • j2. Open a door as the player approaches
  • j3. Damage the player while they stand in lava
  • j4. Know when the player has left the safe zone
  • r1. OnCollisionEnter
  • r2. OnTriggerEnter
  • r3. OnTriggerStay
  • r4. OnTriggerExit

Why: Only the first needs a real collision, because only it needs the impact data - relativeVelocity is what scales the sound. The other three are volumes that detect without blocking, and the Enter/Stay/Exit trio covers arriving, remaining and leaving.

20. Enter, Stay, Exit

Concept

Each family has three moments, and Stay is the expensive one.

callbackfirestypical usewatch out
*Enteronce, on arrivalpickups, damage on hit, doors-
*Stayevery physics step while overlappingdamage over time, standing checksruns ~50x a second, per pair
*Exitonce, on leavingclosing doors, leaving a zonealso fires if the object is destroyed

Put nothing expensive in a Stay callback. A lava zone should accumulate damage * Time.fixedDeltaTime, not run a search or spawn an object every step.

21. Find the callback bug

Error analysis

A pickup that never fires. Everything looks right.

Annotate

  • The bug: OnTriggerEnter takes a Collider, not a Collision. Unity matches these callbacks by name AND signature, so this method is simply never called.
  • No error appears. The class compiles, the component sits happily in the Inspector, and nothing happens - which is why this can cost an hour.
  • The fix is one word: OnTriggerEnter(Collider other). If you wanted the collision version instead, rename the method to OnCollisionEnter and untick Is Trigger.

A useful habit: let the IDE generate these. Typing OnTrigger and accepting the completion gets the signature right every time.

22. Trigger or solid?

Discrimination

Sort into buckets

Should this collider have Is Trigger ticked?

Trigger
A coin the player collects by walking into it; A checkpoint volume; A damage zone in a fire
Solid
A crate the player pushes; The ground
trig
The player should pass through it while it notices them. Anything that would feel wrong to bump into - a pickup, a zone, a checkpoint - is a trigger.
solid
It should physically stop or support something. If the player expects to feel it, it stays solid.

23. Complete the pickup

Fill the middle

Fill in the blanks

void OnTriggerEnter(Collider other)
CompareTag}("Player")) return;
score += 1;
Destroy(gameObject);
}

Why: Collider is the parameter type for every trigger callback, and getting it wrong means Unity silently never calls the method. CompareTag is checked against the project's tag list, so a tag that does not exist throws instead of quietly returning false - which is the next part of this lesson.

24. The collision matrix

Section

Part 3

25. Seven rows worth knowing

Concept

Every pair of colliders falls into one of these. The lab derives the whole table from one scene.

object Aobject Bwhat fires
solid + Rigidbodysolid, no RigidbodyOnCollision* on both
solid + Rigidbodysolid + RigidbodyOnCollision* on both
solid + Rigidbodytrigger, no RigidbodyOnTrigger* on both
trigger + Rigidbodysolid, no RigidbodyOnTrigger* on both
solid, no Rigidbodysolid, no Rigidbodynothing
kinematic Rigidbodysolid, no Rigidbodynothing
kinematic Rigidbodytrigger, no RigidbodyOnTrigger* fires

Two shorthand rules cover almost all of it: a Rigidbody must be somewhere in the pair, and a trigger anywhere in the pair makes it a trigger interaction.

26. Predict the silent pair

Prediction

Two cubes with Box Colliders, overlapping, neither with a Rigidbody. Both have a script implementing every collision and trigger callback.

Predict first

How many callbacks fire?

  • Two - one on each
  • One - on the one that moved last
  • None
  • It depends on which is bigger

Correct: None at all.

Why: Neither is simulated, so the engine never tests that pair. This is the second misconception the diagnostic recorded, and it is the hardest to spot because there is no error to search for - the code is correct, the colliders are correct, and nothing happens.

27. Deriving the matrix from one scene

Worked example

The lab's three lanes, and the summary it prints after four seconds.

foreach (ContactReporter reporter in ContactReporter.All)
    Debug.Log($"{reporter.name} | {reporter.Describe()} | " +
              $"collision enters {reporter.CollisionEnters} | " +
              $"trigger enters {reporter.TriggerEnters}");
objectkindcollision enterstrigger enters
Ball Asolid + dynamic10
Solid Wallsolid + none10
Ball Bsolid + dynamic01
Trigger Zonetrigger + none01
Static Xsolid + none00
Static Ysolid + none00

Read it in pairs

Why: Both members of a pair report the same number, or both report zero. A callback is never delivered to only one side.

28. Watch what holds across the rows

Invariant

Step through the three lanes and find the thing that is true in every one.

Step through it

What is constant across all three lanes, and what does it mean for where you put your script?

  1. solid lane
  2. trigger lane
  3. silent lane

Both sides always agree. So the script can go on either object - put it wherever the logic belongs, not on 'the moving one'.

29. Complete the matrix

Comparison

Comparison matrix

A \ Bsolid, no Rigidbodytrigger, no Rigidbody
solid + dynamic RigidbodyOnCollision*OnTrigger*
solid, no Rigidbodynothingnothing
kinematic RigidbodynothingOnTrigger*

The bottom-right cell is worth remembering on its own: a kinematic body does fire triggers, which is what makes scripted movers usable with detection zones.

30. Trap: giving scenery a Rigidbody to 'make collisions work'

Trap

The trap

Nothing is firing, and the rule says I need a Rigidbody. I will add one to the wall.

Wall: BoxCollider + Rigidbody

Result: the wall falls through the floor, the level collapses,
        and the callbacks now fire on the way down.

The rule was satisfied and the level was destroyed. The Rigidbody belongs on the thing that should move.

The fix

Put the Rigidbody on the mover. Scenery stays as a plain collider - that is what static geometry is.

Wall:  BoxCollider, no Rigidbody          <- correct, and it stays put
Ball:  BoxCollider + Rigidbody            <- the mover carries the requirement

Both objects now receive OnCollisionEnter.
if nothing fires, asknot
is anything in this pair actually moving?should I add more Rigidbodies?
does the mover have the Rigidbody?does the wall need one?
is either one a trigger?why is OnCollisionEnter not called?

31. Layers: the other collision matrix

Concept

Edit > Project Settings > Physics has a checkbox grid: which layers may collide with which. Objects on layers whose box is unticked never interact, whatever their colliders say.

use casehow
bullets should not hit the shooterput them on separate layers, untick that pair
UI raycasts should ignore the worldlayer + LayerMask on the raycast
performance: lots of debrisa Debris layer that only collides with the ground

It is also the first thing to check when a collision mysteriously stops working after someone else touched the project - the setting is global, invisible from the objects, and not in any script.

32. Two of these are true

Two truths and a lie

Eliminate the wrong options

Which claim about collision callbacks is false?

  • A. A wall with no Rigidbody can still receive OnCollisionEnter.
  • B. OnCollisionEnter is delivered only to the object that was moving.
  • C. A trigger fires callbacks but never stops anything.

Survives elimination: B

Why: Both objects in the pair receive the callback, which is why your script can live on either one. That symmetry is genuinely useful: a damage zone can hold the logic, or the player can, and both designs work with no change to the scene.

33. What did I hit?

Section

Part 4

34. Tags, and the right way to check them

Concept

A tag is a short label on a GameObject, set at the top of the Inspector. CompareTag is how you check one.

void OnTriggerEnter(Collider other)
{
    if (!other.CompareTag("Player")) return;
    // ...it really was the player
}
approachallocates?typo behaviour
other.CompareTag("Player")nothrows if the tag is not defined
other.tag == "Player"yes - a string per callsilently returns false forever
other.name == "Player"yesbreaks on 'Player(Clone)'

Unity Scripting API - GameObject.CompareTag CompareTag

35. Predict: the undefined tag

Prediction

You write other.CompareTag("Enemy") but never created an Enemy tag in Tags & Layers.

Predict first

What happens?

  • It returns false quietly
  • It throws a UnityException naming the tag
  • It creates the tag automatically
  • It returns true for everything

Correct: It throws: UnityException: Tag: Enemy is not defined.

Why: That is CompareTag being helpful. A tag you never defined is always a mistake, and an exception naming it takes seconds to fix - whereas tag == "Enemy" would return false forever and leave you debugging the collision instead of the typo.

36. Trap: comparing the collider to a string

Trap

The trap

The parameter is the thing I hit, so compare it to what I am looking for.

void OnCollisionEnter(Collision collision)
{
    if (collision == "Player") { ... }        // does not compile

    if (collision.gameObject.name == "Player") { ... }   // compiles, fragile
}
problemwhy
comparing a Collision to a stringdifferent types - a Collision is not a name
comparing namespawned objects are called 'Player(Clone)'
comparing namerenaming an object in the Hierarchy breaks the logic
comparing tag with ==a typo fails silently, and it allocates

The fix

Reach the GameObject, then ask it a question with CompareTag - or better, ask for a component.

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("Player")) { ... }

    // usually better: ask what it CAN DO, not what it is called
    if (collision.gameObject.TryGetComponent(out Health health))
        health.TakeDamage(10);
}

The component check scales further than tags: anything with a Health component can be damaged, whether it is a player, an enemy or a barrel, and no string is involved at all.

37. Tag, layer, or component?

Discrimination

Three ways to identify what you hit. Sort each situation.

Sort into buckets

Which identification method fits?

Tag - CompareTag
Only the player can open this door; Count how many enemies are in the zone
Layer - the physics matrix
Bullets should never hit other bullets
Component - TryGetComponent
Anything with health should take damage from lava
tag
You are asking 'is this the specific kind of thing I care about', and there are only one or two such kinds. Tags are cheap, visible in the Inspector, and designers can set them.
layer
You want the interaction never to happen at all. Layers are decided before any callback runs, so they cost nothing and cannot be forgotten in code.
comp
You care about a capability rather than an identity. Asking for a Health component covers every current and future thing that can be damaged, with no list to maintain.

38. A pickup, complete

Worked example

Everything from this lesson, in one small script.

public class Coin : MonoBehaviour
{
    public int value = 1;
    bool collected;                       // guards the double-fire

    void OnTriggerEnter(Collider other)
    {
        if (collected) return;
        if (!other.CompareTag("Player")) return;

        collected = true;
        ScoreBoard.Add(value);
        Destroy(gameObject);
    }
}
linewhich lesson it came from
OnTriggerEnter(Collider other)8 - trigger family, correct signature
if (collected) return;5 - Destroy is deferred, so it can fire twice
CompareTag8 - allocation-free, throws on a typo
Destroy(gameObject)5 - the object, not the component
Is Trigger ticked on the collider8 - detect without blocking

The collected flag is not paranoia

Why: The coin survives to the end of the frame, so a second overlap in that same frame finds a live coin with a live script. Lesson 5's timing, showing up as a scoring bug.

39. Decode a contact log

Notation

Annotate

  • A contact POINT and a position: this was a resolution, so the engine knows exactly where the two shapes met. Only the collision family gives you this.
  • The zone received the callback, not the ball only - both sides are told. And [tagged Player] is the CompareTag check passing.
  • Exit fired when the ball left. Note it never stopped: Enter and Exit with no collision in between is the signature of a trigger doing its job.

40. Break this claim

Counterexample

Discussion prompt

'If OnTriggerEnter fires, OnTriggerExit will fire too.' Find a case where it does not.

Hint: What if one of the two objects stops existing?

Answer:

Destroy or deactivate either object while they overlap and Exit may never arrive - the pair stops existing rather than separating.

Same for a collider being disabled, or the object being teleported. So any code that pairs an Enter with an Exit - a counter of who is inside a zone, a door that closes when empty - needs to handle objects vanishing, usually by cleaning the list in OnDisable or by validating entries before use.

41. Build it in Unity

Section

Build

42. What you are about to build

Concept

Three lanes that between them cover every row of the matrix, and a report that prints who heard what.

ContactReporter
All six callbacks, plus a self-description.
CollisionMatrixReport
The summary table, derived from the scene.
ConstantMover
Moves a ball by velocity so contacts behave.

Tags used are Player and Finish - both exist in a new project, so nothing needs defining first. Files: unity-labs/Assets/NaruhodoLabs/Lesson08_Collisions/.

43. Design the three lanes

Step zero

Discussion prompt

What is the smallest set of objects that demonstrates all three outcomes - collision, trigger, and silence? List them with their two properties each.

Answer:

  1. Lane 1: ball (solid + dynamic Rigidbody) and wall (solid + none) - collision on both, ball stops
  2. Lane 2: ball (solid + dynamic Rigidbody) and zone (trigger + none) - trigger on both, ball passes
  3. Lane 3: two cubes (solid + none), overlapping - nothing at all
  4. Plus a reporter on every one of the six, so silence is recorded rather than assumed

The sixth object matters: without a script on the silent pair you have not shown they heard nothing, only that you did not ask.

44. Step 1: build the two lanes

Worked example

Lane 1 stops; lane 2 passes through.

  1. Sphere Ball A at (-4, 1, -4), Tag Player, Rigidbody with Use Gravity off, Constant Mover velocity (0, 0, 3), Contact Reporter
  2. Cube Solid Wall at (-4, 1, 0), Scale (3, 2, 0.4), Contact Reporter, no Rigidbody
  3. Duplicate both at x = 0; on the second wall tick Is Trigger and set Tag to Finish
laneyou should seein the Console
1the ball stops at the wallOnCollisionEnter on both
2the ball sails throughOnTriggerEnter, then OnTriggerExit, on both

45. Step 2: the silent pair

Worked example

Two static cubes, overlapping, with reporters on both. This is the part people skip.

// both cubes: BoxCollider, no Rigidbody, overlapping by 0.8 units
// after 4 seconds the report prints:
//   Static X | solid collider + no Rigidbody | collision enters 0 | trigger enters 0
//   Static Y | solid collider + no Rigidbody | collision enters 0 | trigger enters 0
objectcolliderRigidbodycallbacks
Static XBox, solidnone0
Static YBox, solidnone0
(add a Rigidbody to Y)Box, soliddynamicboth wake up - and Y falls

The third row is the experiment

Why: Add the Rigidbody, watch the callbacks appear, then remove it again. Seeing silence turn into signal from one checkbox is what makes the rule stick.

46. Commit before you run it

Hypothesis

You tick Is Trigger on the solid wall in lane 1 and press Play.

Predict first

What changes?

  • Nothing - the ball still stops
  • The ball passes through, and the callbacks become OnTrigger*
  • The ball stops but no callbacks fire
  • An error, because a wall cannot be a trigger

Correct: The ball passes through, and both objects get OnTrigger* instead.

Why: One checkbox changes both halves at once: what is reported, and whether anything is stopped. That coupling is the thing to hold on to - you cannot have a trigger that blocks, or a solid collider that reports trigger callbacks.

47. Where this shows up in a real game

Real world

Discussion prompt

A player walks over a coin and nothing happens. List the checks you would make, in order, and what each one rules out.

Answer:

  1. Does the coin have a collider, with Is Trigger ticked? No collider means no detection; solid means the player bumps into it instead.
  2. Does either object have a Rigidbody? Usually the player. Two static colliders is the silent row.
  3. Is the method signature right? OnTriggerEnter(Collider other) - a Collision parameter is never called.
  4. Is the tag check passing? Log other.name before the check; a player tagged Untagged fails silently.
  5. Are they on layers that can collide? Project Settings > Physics - invisible from both objects.

Every one of those is a two-second check, and they are ordered by how often they are the answer. Working the list beats reading the code again.

48. Explain the two rules

Explain it

Discussion prompt

A teammate's trigger is not firing. Explain the two switches in two sentences, without using the word 'matrix'.

Answer:

Model answer: 'Something in the pair has to have a Rigidbody - usually whatever is moving - because two objects that are both just scenery are never even tested against each other.'

'And if either collider has Is Trigger ticked you get the OnTrigger callbacks and nothing gets blocked, so check which of the two methods you wrote.'

49. Now break it, on purpose

Concept

Eight experiments from the lab notes.

changewhat happens
Rename OnTriggerEnter to OnCollisionEnter on the zoneit never fires - a trigger only sends trigger callbacks
Remove the Rigidbody from Ball Ait stops moving AND stops reporting
Tick Is Trigger on the solid wallthe ball passes through and the callbacks change family
Use gameObject.tag == "Player"works, allocates, and fails silently on a typo
CompareTag("Enemy") with no Enemy tag definedthrows, naming the tag - which is the point
Add a Rigidbody to Static Ythe silent pair wakes up, and Y falls over
Make Ball A kinematicit drives through the wall in silence
Tick Log Stay on the wallOnCollisionStay fires every physics step while resting

50. One symptom, four suspects

Elimination

A damage zone works for the player but not for enemies, and both have colliders.

Eliminate the wrong options

What should you check first?

  • A. The enemies have no Rigidbody, so their pair with the static zone is never tested.
  • B. The zone's Is Trigger is unticked.
  • C. OnTriggerEnter has the wrong parameter type.
  • D. The zone script checks CompareTag("Player").

Survives elimination: A

Why: The difference between the two cases is what the objects are, not what the code says - so look at the objects. A player usually has a Rigidbody or a Character Controller; enemies moved by a script with neither are two static colliders as far as the zone is concerned, and the pair is never tested. Choice D is the right second check, and it is the one line of code worth reading.

51. The procedure: making contact work

Pattern

Five questions, in this order. They diagnose any 'nothing happens' in under a minute.

  1. Do both objects have colliders? Look in the Inspector, not at the mesh.
  2. Does at least one have a Rigidbody? Put it on whatever moves. Never on the scenery.
  3. Is either one a trigger? Trigger means OnTrigger* and nothing is blocked; solid means OnCollision* and things are stopped.
  4. Is the signature exactly right? OnCollisionEnter(Collision) and OnTriggerEnter(Collider). A mismatch is silent.
  5. Can those layers collide? Project Settings > Physics, the checkbox grid.

And when identifying what you hit: CompareTag over tag ==, and TryGetComponent over both when you care about a capability rather than a label.

52. Check 1: which callback

Check

Check your understanding

A ball with a Rigidbody rolls into a box whose collider has Is Trigger ticked. Which callback fires?

  • A. OnCollisionEnter, because they physically touched
  • B. OnTriggerEnter, and the ball passes through (correct)
  • C. Both, because a trigger is a kind of collision
  • D. Neither, because the box has no Rigidbody

Answer: B

Why: A trigger anywhere in the pair makes the whole interaction a trigger interaction: OnTrigger* fires on both objects and nothing is stopped. There is no collision to report because nothing was resolved.

Why A tempts people
OnCollisionEnter only fires when contacts are actually resolved. A trigger deliberately skips that step, which is what lets things pass through.
Why C tempts people
The two families are exclusive. You get one or the other, never both - which is why writing both methods on one script is a common way to discover that only one of them ever runs.
Why D tempts people
The box does not need one: the rule is a Rigidbody somewhere in the pair, and the ball supplies it for both of them.

53. Check 2: the silent pair

Check

Check your understanding

Two cubes with Box Colliders overlap. Neither has a Rigidbody. Both have scripts implementing every callback. What fires?

  • A. OnCollisionEnter on both
  • B. OnCollisionStay every physics step
  • C. Nothing at all (correct)
  • D. OnTriggerEnter on both

Answer: C

Why: Two static colliders are never tested against each other. The engine treats static geometry as a fixed structure to test MOVING things against, and pairs within it are skipped entirely - a performance decision, since a level can hold thousands of static colliders.

Why A tempts people
That would require a Rigidbody in the pair. Without one there is nothing being simulated and nothing to report.
Why B tempts people
Stay has the same requirement as Enter; if Enter never fires, neither does Stay.
Why D tempts people
Neither is a trigger, and the trigger family has the same Rigidbody requirement anyway.

54. One question to sit with

Socratic

Discussion prompt

Why does Unity deliver the callback to BOTH objects rather than only to the one with the Rigidbody?

Answer:

Because which object 'owns' the interaction is a design decision, not a physics fact. A door should decide whether it opens; a bullet should decide what damage it deals; a damage zone should decide how much it hurts.

If only the moving object were told, every piece of scenery would need the mover to know about it - so a coin would need the player's script to list every kind of pickup. Telling both sides lets the logic live wherever it belongs.

55. Check 3: identifying what you hit

Check

Check your understanding

Inside OnCollisionEnter(Collision collision), how do you check whether you hit the player?

  • A. if (collision == "Player")
  • B. if (collision.gameObject.CompareTag("Player")) (correct)
  • C. if (collision.name == "Player")
  • D. if (collision.tag == "Player")

Answer: B

Why: Reach the GameObject through the Collision, then ask it with CompareTag - which allocates nothing and throws if the tag is not defined, so a typo is a loud error rather than a silent false.

Why A tempts people
A Collision is not a string and this does not compile. It is the misconception the diagnostic recorded, and the compiler catches this one at least.
Why C tempts people
Collision has no name property, and even via gameObject a name check breaks the moment the object is spawned as 'Player(Clone)' or renamed.
Why D tempts people
Collision has no tag property either. Even written correctly as collision.gameObject.tag == "Player", it allocates a string per call and fails silently on a typo.

56. A number worth feeling

Estimation

A player rests on the ground for 10 seconds, with OnCollisionStay implemented on both.

Predict first

Roughly how many times does that callback run?

  • 10
  • 60
  • 500
  • 5,000

Correct: About 500 - 50 physics steps a second for 10 seconds.

Why: And that is one pair. A character touching the ground and two walls triples it, and every object in the scene is doing the same. This is why Stay callbacks must be cheap, and why damage-over-time is written as damage times Time.fixedDeltaTime rather than a fixed amount per call.

57. What else do you need to know?

Missing information

Discussion prompt

'Make the player take damage from the spikes.' What do you need to establish before writing it?

Answer:

  • Once, or continuously? Enter for a one-off hit; Stay with a cooldown for continuous - and never raw Stay, which would do 50 hits a second.
  • Blocked or passed through? Solid spikes stop the player; a trigger lets them walk over and be hurt.
  • How is the player moved? A Character Controller does not use OnCollisionEnter at all - it has OnControllerColliderHit, which is a genuinely different API.
  • Who owns the number? Damage on the spikes lets designers tune each hazard; damage on the player forces one global value.

The third bullet is the one that catches people: a Character Controller is not a Rigidbody, and half the rules in this deck change for it.

58. What this unlocks - and what comes next

Concept

This is the eighth lesson in the sequence the diagnostic recommended. Together they cover the whole loop: objects, prefabs, physics, lifecycle, the API calls, transforms, vectors and contact.

still on the reportwhy it was not a lesson
Audio, build settings, profilingFragile at 2/3, but not on the recommended lesson order - worth a short ninth session
Canvas and UItested fine, and it is its own subject
Time.deltaTimetested fine, and it appeared in lessons 3, 6 and 7 anyway

59. Connect it to something you know

Analogy

Match the pairs

Match each Unity idea to a familiar cousin.

  • u1. Collider
  • u2. Is Trigger
  • u3. The layer matrix
  • u4. OnTriggerStay
  • o1. an element's hit area, separate from how it looks
  • o2. pointer-events: none - detected but not blocking
  • o3. a firewall rule table: which pairs may talk at all
  • o4. a callback on every tick while the pointer is held

Why: The hit-area analogy is the one worth keeping: a button's clickable region is not its picture, and getting them out of step produces exactly the Unity bug where an object looks like it should be hit and is not. Same idea, same failure mode.

60. Draw the matrix

Connect it up

Draw it

Draw a 2x3 grid: columns are 'solid, no Rigidbody' and 'trigger, no Rigidbody'; rows are 'solid + dynamic', 'solid, no Rigidbody' and 'kinematic'. Fill each cell with what fires, and circle the cell that catches people.

61. Before you close this

Exit ticket

Predict first

Which is still shakiest?

  • The Rigidbody-in-the-pair rule
  • Trigger vs collision callbacks
  • The callback signatures
  • CompareTag vs comparing strings

Correct: Whichever you picked - the lab's summary table shows all four in one Play session.

Why: You scored 2 of 3 here with low confidence on both correct answers, which is the profile of a rule half-remembered rather than derived. Naming the shakiest one and running its experiment converts it, and this is the last lesson in the recommended sequence - so it is worth being solid before the next session.

62. What you can now do

Recap

You can predict, from two objects' Inspectors alone, whether anything will happen when they touch.

Lab: unity-labs/Assets/NaruhodoLabs/Lesson08_Collisions/SETUP.md. Run the three lanes, then go back through the eight recap slides and check you can say each lesson's one sentence without looking.

Sources

  1. Unity Manual - Colliders
  2. Unity Manual - Collision action matrix
  3. Unity Scripting API - MonoBehaviour.OnCollisionEnter
  4. Unity Scripting API - MonoBehaviour.OnTriggerEnter
  5. Unity Scripting API - GameObject.CompareTag
  6. Naruhodo Unity Labs - Lesson 08 setup notes — unity-labs/Assets/NaruhodoLabs/Lesson08_Collisions/SETUP.md

Want this taught 1-on-1? Alexander tutors Unity Game Engine — $55/session, free consultation.

Book on Wyzant · Text (657) 465-8108