OnTriggerEnter Not Working in Unity? 12-Point Checklist (3D and OnTriggerEnter2D)

Capsule entering a glowing trigger collider volume

You add a collider, tick Is Trigger, write OnTriggerEnter, walk your player into it… and nothing happens. No log, no error. Trigger problems are frustrating because Unity fails silently, but there are only a handful of reasons a trigger won’t fire, and you can check all of them in a few minutes. This checklist covers 3D and 2D triggers in Unity 6, plus the related “OnCollisionEnter not working” and “OnMouseDown not working” problems, and includes a script that checks your setup for you.

Quick answer

OnTriggerEnter only fires when one of the two colliders has Is Trigger ticked, at least one object has a Rigidbody (kinematic is fine) or a CharacterController, and the method is spelled exactly void OnTriggerEnter(Collider other) on a script attached to one of those objects. In 2D, every piece must be 2D: Collider2D, Rigidbody2D and OnTriggerEnter2D(Collider2D other). In 3D, two kinematic Rigidbodies do get trigger events, so if that case fails, check the layer collision matrix and the rest of the 12-point checklist.

Watch it in action: real Unity footage of each trigger problem, then the fix (4:15).


The Rules Unity Triggers Follow

A trigger event needs three things:

  1. Two colliders that overlap, and at least one of them has Is Trigger ticked.
  2. At least one of the two objects has a Rigidbody (a kinematic Rigidbody counts), or is moved by a CharacterController.
  3. A script with a correctly spelled message method on the right GameObject.

Whether you get events depends on what each object has:

Moving object Trigger object OnTriggerEnter fires?
Collider only (no Rigidbody) Trigger collider only (no Rigidbody) No. Neither has a Rigidbody.
Collider + Rigidbody (dynamic) Trigger collider only Yes
Collider + Rigidbody (kinematic) Trigger collider only Yes
CharacterController Trigger collider only Yes
Collider only Trigger collider + kinematic Rigidbody Yes

The first row is the cause of most “trigger not working” posts: a player moved by transform.position or Translate with no Rigidbody, walking into a trigger that has no Rigidbody either.

Two Unity test scenes side by side: on the left a player cube with no Rigidbody passes through a trigger zone and the console shows no messages; on the right the same cube with a kinematic Rigidbody turns the zone green and logs OnTriggerEnter
Left: no Rigidbody on either object, so the cube walks through and the console stays empty. Right: the same cube with a kinematic Rigidbody fires OnTriggerEnter.

The 12-Point Checklist

Work through these in order. The first four fix the large majority of cases.

1. At least one object has a Rigidbody

Add a Rigidbody to the moving object (usually the player or the projectile). If you move it from code and don’t want gravity or physics pushing it around, tick Is Kinematic. A kinematic Rigidbody still generates trigger events. If the object uses a CharacterController, it already works with triggers and doesn’t need a Rigidbody.

If you move a Rigidbody from code, use Rigidbody.MovePosition in FixedUpdate instead of setting transform.position. Physics then knows the object moved, rather than seeing it teleport.

Unity Inspector showing a Rigidbody component added to the player with Is Kinematic ticked
Add a Rigidbody to the mover and tick Is Kinematic if you move it from code.

2. Is Trigger is ticked on one of the colliders

If neither collider is a trigger, the objects collide physically and Unity calls OnCollisionEnter, not OnTriggerEnter. If the objects bump into each other instead of passing through, this is your problem. Tick Is Trigger on the zone, pickup or checkpoint collider.

With Is Trigger off, the player cube stops against the zone and the console logs OnCollisionEnter instead of OnTriggerEnter
Is Trigger off: the objects collide and Unity calls OnCollisionEnter instead.
Unity Inspector for the TriggerZone object with Is Trigger ticked on its Box Collider
The fix: tick Is Trigger on the zone’s collider.

3. The method signature is exactly right

Unity finds message methods by name and parameter type. A typo means Unity never calls it, and there’s no compiler error because it’s a perfectly valid method name:

// Correct (3D)
void OnTriggerEnter(Collider other) { }
void OnTriggerStay(Collider other) { }
void OnTriggerExit(Collider other) { }

// Wrong: never called
void OnTriggerEnter(Collision other) { }   // wrong parameter type (Unity logs a script error)
void onTriggerEnter(Collider other) { }    // lowercase o
void OnTriggerEntered(Collider other) { }  // wrong name
void OnTriggerEnter2D(Collider other) { }  // 2D name with a 3D parameter

With the wrong parameter type, Unity prints a Console message like “Script error: OnTriggerEnter. This message parameter has to be of type: Collider.” Your code editor helps too: with IntelliSense working, typing OnTrig should autocomplete the correct signature. If it doesn’t, see our IntelliSense fix guide.

4. You’re not mixing 2D and 3D physics

Unity has two completely separate physics engines. A BoxCollider never detects a BoxCollider2D, and a Rigidbody2D does nothing for a 3D collider. For sprites and tilemaps, use the 2D components (Rigidbody2D, BoxCollider2D, CircleCollider2D) and OnTriggerEnter2D(Collider2D other). It’s easy to get wrong because both sets appear in the Add Component menu. See the 2D section.

5. The script is on the right GameObject

Trigger messages go to the GameObject that owns the collider involved, and to the GameObject that owns the Rigidbody. If your collider is on a child object and your script is on a sibling or an unrelated object, it won’t hear anything. Put the script on the trigger’s GameObject, or on the Rigidbody’s GameObject.

Also remember that other is the collider that entered, which may be on a child of your player (a weapon, a foot collider). If you check other.CompareTag("Player") and the tag is only on the root, the check fails. Use the Rigidbody’s GameObject instead:

void OnTriggerEnter(Collider other)
{
    // Works even if the collider that entered is on a child of the player
    GameObject root = other.attachedRigidbody != null
        ? other.attachedRigidbody.gameObject
        : other.gameObject;

    if (root.CompareTag("Player"))
    {
        Debug.Log("Player entered " + name);
    }
}

6. Your if-statement isn’t hiding it

Put a log on the very first line of the method, before any if:

void OnTriggerEnter(Collider other)
{
    Debug.Log($"{name} trigger entered by {other.name} (tag: {other.tag}, layer: {LayerMask.LayerToName(other.gameObject.layer)})", this);
    // ...your checks
}

If this logs, the trigger works and your condition is wrong: a misspelled tag (tags are case-sensitive), a comparison against other.name that includes “(Clone)” on spawned objects, or a layer check with the wrong mask. Prefer CompareTag over other.tag == "Player"; it’s faster and logs an error if the tag doesn’t exist.

7. The Layer Collision Matrix allows it

Open Edit > Project Settings > Physics and find the Layer Collision Matrix. If the checkbox where the two objects’ layers meet is unticked, those layers ignore each other completely, triggers included. 2D physics has its own matrix under Physics 2D. Also check the Layer Overrides (Include/Exclude Layers) section on the collider and Rigidbody components, which can exclude layers per object.

8. Mesh Colliders are convex

A non-convex Mesh Collider can’t be a trigger. Tick Convex on the Mesh Collider, or use a Box, Sphere or Capsule Collider instead. Primitive colliders are cheaper anyway, and for most trigger zones a box is exactly the right shape.

9. The object isn’t moving too fast

Physics runs in fixed steps (50 per second by default). A bullet moving 100 metres per second travels 2 metres per step, so it can be on one side of a thin trigger in one step and past it in the next. This is called tunnelling. Fixes:

  • Make the trigger thicker in the direction of travel.
  • For fast projectiles, don’t rely on triggers: cast a ray or sphere from last frame’s position to this frame’s position with Physics.Raycast or Physics.SphereCast and handle the hit yourself.
  • Teleporting an object with transform.position can skip over a trigger entirely. Move it with Rigidbody.MovePosition.
Slow-motion physics steps of a fast bullet: it skips past a thin trigger with no message, while a thicker trigger catches it and logs OnTriggerEnter
Each faded cube is one physics step. The bullet steps over the thin trigger (top) but lands inside the thick one (bottom).

10. Physics is actually running

If Time.timeScale is 0 (a pause menu that never unpaused), no physics runs and no triggers fire. Also check Project Settings > Physics > Simulation Mode: if it’s set to Script, physics only steps when your code calls Physics.Simulate.

11. Both GameObjects and colliders are enabled

An inactive GameObject or a disabled Collider component takes part in no physics. Note the asymmetry with scripts: a disabled script (unticked MonoBehaviour) still receives trigger and collision messages, so disabling the component is not a way to stop them. Use a bool flag or disable the collider instead.

Related gotcha: if an object is deactivated or destroyed while inside a trigger, OnTriggerExit is not called for it. Code that counts “things inside the zone” should also handle OnDisable/OnDestroy on the objects, or clean up null entries.

12. The trigger’s own Rigidbody isn’t sleeping or misconfigured

If you put a non-kinematic Rigidbody on a trigger zone, it falls through the floor due to gravity (it’s a trigger, so nothing holds it up) and your “trigger” ends up far below the level. Use Is Kinematic for Rigidbodies on static trigger zones, or leave the zone without a Rigidbody and put one on the mover instead.

A trigger zone with a non-kinematic Rigidbody sinking through the floor, so the player passes the spot and nothing is logged
A trigger zone with a dynamic Rigidbody sinks through the floor, so nothing is there when the player arrives.

๐Ÿ›  Half of these bugs are spelling

Message methods like OnTriggerEnter, tags and layer names all fail silently when they’re misspelled. A consistent naming standard for scripts, tags and layers catches most of them before they happen.

Open the Unity Naming Convention Reference →

2D Triggers: OnTriggerEnter2D Not Working

Everything above applies to 2D, with these differences:

  • Use the 2D method and parameter: void OnTriggerEnter2D(Collider2D other).
  • Use 2D components only: Rigidbody2D plus a Collider2D (BoxCollider2D, CircleCollider2D, CapsuleCollider2D, PolygonCollider2D, CompositeCollider2D).
  • Body Type matters. Two objects with Static Rigidbody2Ds (or no Rigidbody2D at all) never interact. Give the mover a Dynamic or Kinematic Rigidbody2D. Kinematic bodies normally only register collisions with Dynamic bodies, but triggers are an exception, so a kinematic mover does fire trigger events against a static trigger.
  • Simulated must be ticked on the Rigidbody2D. Unticking it removes the body from 2D physics entirely.
  • Z position doesn’t matter. 2D physics ignores Z, so a trigger at Z = 5 still overlaps a player at Z = 0. That also means sorting-layer order has no effect on triggers.
  • Tilemap triggers: add a Tilemap Collider 2D (optionally with a Composite Collider 2D) and tick Is Trigger on the one that’s used. When a Composite Collider is used, the trigger setting on the composite is the one that counts.
using UnityEngine;

public class Coin : MonoBehaviour
{
    [SerializeField] int value = 1;

    void OnTriggerEnter2D(Collider2D other)
    {
        if (!other.CompareTag("Player")) return;

        ScoreManager.Instance.Add(value);
        Destroy(gameObject);
    }
}

OnCollisionEnter Not Working

Collision events have a stricter rule than triggers: at least one object needs a non-kinematic (dynamic) Rigidbody, and neither collider can be a trigger.

  • Kinematic vs static, or kinematic vs kinematic: no OnCollisionEnter in 3D. Make one of them dynamic, or switch to triggers.
  • The signature is void OnCollisionEnter(Collision collision), with a Collision, not a Collider. Get the other object with collision.gameObject and the contact point with collision.GetContact(0).point.
  • CharacterController doesn’t produce OnCollisionEnter for the objects it walks into. Use OnControllerColliderHit(ControllerColliderHit hit) on the character’s script instead.
  • In 2D, the method is OnCollisionEnter2D(Collision2D collision). Kinematic Rigidbody2Ds only get collision callbacks against Dynamic bodies unless you enable full kinematic contacts on the Rigidbody2D.
  • Fast objects can pass through each other. Set the fast Rigidbody’s Collision Detection to Continuous (or Continuous Dynamic if both objects move fast).

OnMouseDown Not Working

OnMouseDown is a related “why isn’t my method called” problem. Check these:

  1. The object needs a collider (3D or 2D). No collider, no mouse events. The script must be on the same GameObject as the collider.
  2. It’s not on the Ignore Raycast layer. Unity skips objects on that layer.
  3. Trigger colliders only receive mouse events if Queries Hit Triggers is enabled in the Physics (or Physics 2D) settings.
  4. The new Input System. This is the big one in Unity 6. If Project Settings > Player > Active Input Handling is set to Input System Package (New), the OnMouseDown/OnMouseEnter/OnMouseDrag family is never called. Either set it to Both, or use the event system approach below.
  5. Something in front blocks the ray, such as a large invisible trigger volume. Note that UI does not block OnMouseDown: clicks on a button also reach 3D objects behind it.

The Input System-friendly replacement uses the EventSystem, which also respects UI blocking:

using UnityEngine;
using UnityEngine.EventSystems;

// Requirements:
// 1. The camera has a Physics Raycaster (or Physics 2D Raycaster) component.
// 2. The scene has an EventSystem (GameObject > UI > Event System).
// 3. This object has a collider.
public class ClickableCrate : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log($"Clicked {name} with {eventData.button}");
    }
}

More on the new input stack in our Unity Input System guide.

A Script That Checks Your Trigger Setup

Add this component to the trigger object (or the mover) and press Play. It logs every problem from the checklist that it can detect, then logs each trigger event it receives. Remove it once things work.

using UnityEngine;

public class TriggerSetupCheck : MonoBehaviour
{
    void Start()
    {
        Collider[] cols3D = GetComponentsInChildren<Collider>();
        Collider2D[] cols2D = GetComponentsInChildren<Collider2D>();

        if (cols3D.Length == 0 && cols2D.Length == 0)
            Debug.LogWarning($"{name}: no colliders on this object or its children.", this);

        if (cols3D.Length > 0 && cols2D.Length > 0)
            Debug.LogWarning($"{name}: has BOTH 3D and 2D colliders. 3D and 2D physics never interact.", this);

        foreach (Collider c in cols3D)
        {
            if (!c.enabled) Debug.LogWarning($"{c.name}: collider is disabled.", c);
            if (c is MeshCollider mc && mc.isTrigger && !mc.convex)
                Debug.LogWarning($"{c.name}: non-convex MeshCollider can't be a trigger. Tick Convex.", c);
            Debug.Log($"{c.name}: {c.GetType().Name}, isTrigger={c.isTrigger}, rigidbody={(c.attachedRigidbody ? c.attachedRigidbody.name + (c.attachedRigidbody.isKinematic ? " (kinematic)" : " (dynamic)") : "none")}", c);
        }

        foreach (Collider2D c in cols2D)
        {
            if (!c.enabled) Debug.LogWarning($"{c.name}: collider is disabled.", c);
            Rigidbody2D rb = c.attachedRigidbody;
            if (rb != null && !rb.simulated) Debug.LogWarning($"{c.name}: Rigidbody2D has Simulated turned off.", c);
            Debug.Log($"{c.name}: {c.GetType().Name}, isTrigger={c.isTrigger}, rigidbody2D={(rb ? rb.name + " (" + rb.bodyType + ")" : "none")}", c);
        }

        if (Time.timeScale == 0f) Debug.LogWarning("Time.timeScale is 0, so physics is paused.");
    }

    void OnTriggerEnter(Collider other) => Debug.Log($"[3D] {name} OnTriggerEnter with {other.name}", this);
    void OnTriggerExit(Collider other) => Debug.Log($"[3D] {name} OnTriggerExit with {other.name}", this);
    void OnTriggerEnter2D(Collider2D other) => Debug.Log($"[2D] {name} OnTriggerEnter2D with {other.name}", this);
    void OnTriggerExit2D(Collider2D other) => Debug.Log($"[2D] {name} OnTriggerExit2D with {other.name}", this);
    void OnCollisionEnter(Collision c) => Debug.Log($"[3D] {name} OnCollisionEnter with {c.gameObject.name}", this);
    void OnCollisionEnter2D(Collision2D c) => Debug.Log($"[2D] {name} OnCollisionEnter2D with {c.gameObject.name}", this);
}

Read the output like this: if both objects report rigidbody=none, you’ve found point 1. If you see OnCollisionEnter logs but no trigger logs, Is Trigger is off. If nothing logs at all and the setup looks right, check the Layer Collision Matrix.

You can also see colliders while playing: enable Gizmos in the Game view toolbar, or open Window > Analysis > Physics Debugger to visualize every collider and its type in the Scene view.

FAQ

Why is OnTriggerEnter not being called?

The most common reason is that neither object has a Rigidbody. Add one to the moving object (tick Is Kinematic if you move it from code), make sure one collider has Is Trigger ticked, and check the method is spelled OnTriggerEnter(Collider other).

Does a trigger need a Rigidbody in Unity?

At least one of the two objects involved needs a Rigidbody (kinematic is fine) or a CharacterController. It doesn’t have to be the trigger itself. Usually it’s easiest to put it on the moving object.

Why does OnTriggerEnter fire twice?

The entering object has two colliders (for example a capsule plus a child hitbox), and each one generates its own event. Filter by other.attachedRigidbody, keep a set of objects already handled, or put the extra collider on a layer that doesn’t interact with the trigger.

What’s the difference between OnTriggerEnter and OnCollisionEnter?

Triggers detect overlap without any physical response; objects pass through. Collisions happen when neither collider is a trigger and at least one object has a dynamic Rigidbody; the objects bounce or stop and you get contact points.

Does OnTriggerEnter work in Unity 6?

Yes, nothing about the rules changed in Unity 6. What did change is that new projects default to the Input System, which stops OnMouseDown from being called. That’s a separate issue from triggers.

Why does OnTriggerEnter2D not work with my 3D collider?

2D and 3D physics are separate engines. Replace the 3D collider and Rigidbody with BoxCollider2D (or another 2D collider) and Rigidbody2D.

Why isn’t OnTriggerEnter firing between two kinematic triggers?

In 3D it should: two kinematic Rigidbodies do get trigger events as long as one collider has Is Trigger ticked. If they don’t, check that their layers are allowed to collide in the Layer Collision Matrix, that both colliders are enabled, that a Mesh Collider is convex, and that the method is OnTriggerEnter(Collider other). In 2D it’s different: two kinematic Rigidbody2Ds ignore each other unless you tick Use Full Kinematic Contacts on the Rigidbody2D, or make one of them Dynamic with Gravity Scale 0.

Comments

2 responses to “OnTriggerEnter Not Working in Unity? 12-Point Checklist (3D and OnTriggerEnter2D)”

  1. […] zones and checkpoint volumes. If you’re not sure why an object isn’t being hit, our OnTriggerEnter checklist covers the same collider and layer pitfalls from the collision […]

  2. […] 1–3 are covered in depth in our OnTriggerEnter checklist. This guide focuses on 4 and […]

Leave a Reply

Your email address will not be published. Required fields are marked *