Trigger
A Trigger is a Collider in ghost mode — it detects enter, stay, and exit without a physical push-back, used for checkpoints, pickups, and automatic doors.
Imagine...
A Trigger is like a supermarket door sensor. The door does not shove you back when you step in — it only notices you and opens. No physical force, just a signal: "someone entered." In Unity, `OnTriggerEnter` is that signal — fired the moment a character touches the zone, so you can open a door, heal, start a cutscene...
The concept in detail
A Trigger is a normal Collider with the Is Trigger checkbox on. Once enabled, the
Collider becomes pass-through — bodies walk through it with no push-back. Unity instead fires
three callbacks: OnTriggerEnter (on enter), OnTriggerStay
(every frame while inside), and OnTriggerExit (on leave).
For a trigger to fire, at least one of the two objects
must have a Rigidbody. That is the classic miss — two static objects (no
Rigidbody) never trigger each other. If you do not want gravity, set
isKinematic = true.
Triggers cover a lot of ground: checkpoint (save position on walk-through), pickup zone (collect an item), enemy detection (AI awareness radius), damage zone (fire, acid), cutscene trigger (story beat). None of these need real physics — only “who entered this volume?”
In Unity 2D the matching callbacks are OnTriggerEnter2D,
OnTriggerStay2D, OnTriggerExit2D — same shape, but they receive a
Collider2D instead of a Collider.
Trigger vs Collision lifecycle
Trigger (isTrigger = true)
OnTriggerEnter
First frame of contact
OnTriggerStay
Every frame while still inside
OnTriggerExit
Last frame when leaving
✅ Walk through — no contact force
Collision (isTrigger = false)
OnCollisionEnter
First frame of impact
OnCollisionStay
Every frame while touching
OnCollisionExit
When they separate
🔒 Blocked — a physical contact force
⚠️ Hard requirement:
At least one of the two objects must have a Rigidbody (or Rigidbody2D) or trigger/collision will never fire.
Hands-on steps
Create a trigger volume
Create an empty GameObject, Add Component → BoxCollider, check "Is Trigger". Size it to the zone you want.
Give the moving body a Rigidbody
The character or projectile needs a Rigidbody. If gravity should not apply, set isKinematic = true.
Write the trigger handler
Add a script with OnTriggerEnter(Collider other) on the trigger object or the moving body.
Filter with Layers
Check other.gameObject.layer or CompareTag so you only react to the objects you care about.
Debug with Gizmo color
Triggers draw cyan (collisions draw green). Add OnDrawGizmos if you need extra debug drawing.
Interactive simulator
Use the ← → arrow keys (or the buttons below) to walk the character through trigger zones.
Walk the character into a trigger zone...
Code example
BasicSimple pickup: collect a coin when the player enters the trigger.
using UnityEngine;
// Attach this to a Coin with a Collider that has isTrigger = true
public class CoinPickup : MonoBehaviour
{
public int value = 10;
public AudioClip pickupSound;
void OnTriggerEnter(Collider other)
{
// Only react to the Player
if (!other.CompareTag("Player")) return;
// Award points via GameManager
GameManager.instance.AddScore(value);
// Play a pickup sound
AudioSource.PlayClipAtPoint(pickupSound, transform.position);
// Remove the coin from the scene
Destroy(gameObject);
}
}Code example
AdvancedTimed hazard: deal damage every frame while inside, stop on exit.
using UnityEngine;
using System.Collections;
// A fire zone that damages while you stand in the trigger
public class DamageZone : MonoBehaviour
{
public float damagePerSecond = 10f;
public LayerMask damageable;
Coroutine damageRoutine;
PlayerHealth currentTarget;
void OnTriggerEnter(Collider other)
{
if ((damageable.value & (1 << other.gameObject.layer)) == 0) return;
currentTarget = other.GetComponent<PlayerHealth>();
if (currentTarget != null)
damageRoutine = StartCoroutine(DamageLoop());
}
void OnTriggerExit(Collider other)
{
if (damageRoutine != null)
{
StopCoroutine(damageRoutine);
damageRoutine = null;
currentTarget = null;
}
}
IEnumerator DamageLoop()
{
while (true)
{
currentTarget.TakeDamage(damagePerSecond * Time.deltaTime);
yield return null; // Wait one frame
}
}
}📌 Quick recap
- ▸isTrigger=true → walk through, receive events
- ▸At least one side must have a Rigidbody
- ▸CompareTag() is faster than comparing strings directly
- ▸OnTriggerStay runs every frame — watch the cost
- ▸Use a LayerMask to filter objects cheaply
⚠️ Common mistakes
❌ Trigger never fires even though isTrigger is on
Neither object has a Rigidbody
✅ Add a Rigidbody (isKinematic=true if needed) to the moving body
❌ Calling Destroy(other.gameObject) inside OnTriggerStay
Errors because the object is destroyed mid physics loop
✅ Destroy in OnTriggerEnter and null-check first