Quick answer: The most common cause is that one or both GameObjects involved in the collision are missing a Rigidbody component. Unity requires at least one of the two colliding objects to have a Rigidbody for OnCollisionEnter to fire.
Here is how to fix Unity oncollisionenter not called. Your player walks straight through enemies. Projectiles pass through walls. You added OnCollisionEnter to your script, the method signature looks correct, and there are no errors in the Console — but the callback never fires. This is one of the most common issues in Unity and it almost always comes down to a missing Rigidbody, an isTrigger mismatch, or a layer collision matrix misconfiguration.
The Symptom
You have a MonoBehaviour script attached to a GameObject with a Collider. You implemented OnCollisionEnter (or OnCollisionStay / OnCollisionExit), but the method is never called when your object comes into contact with another collider. There are no errors or warnings in the Console. The objects may visually overlap or pass through each other entirely.
In some cases, you might see the opposite problem: you expected OnTriggerEnter but implemented OnCollisionEnter, or vice versa. The two callback families are mutually exclusive for any given collider pair — a collider with isTrigger enabled will never produce OnCollisionEnter events.
What Causes This
Unity's physics system has strict requirements for collision callbacks to fire. The most common causes are:
- Missing Rigidbody — At least one of the two colliding GameObjects must have a Rigidbody (or Rigidbody2D for 2D physics). Two static colliders without any Rigidbody will never generate collision callbacks. This is the number one cause of OnCollisionEnter not firing.
- isTrigger mismatch — If either collider has
isTriggerchecked in the Inspector, Unity treats the interaction as a trigger overlap, not a collision. Triggers callOnTriggerEnter, notOnCollisionEnter. You cannot mix the two. - Layer Collision Matrix — Unity lets you disable collisions between specific layers in Edit > Project Settings > Physics. If the two objects are on layers that are unchecked in the matrix, no collision detection occurs at all — no callbacks, no physics response.
- Collider on a child object — If the Collider is on a child GameObject but the Rigidbody is on the parent, the collision callback fires on the Rigidbody's GameObject, not the child. Your script needs to be on the same object as the Rigidbody, or you need to use
GetComponentInParentfrom the child. - 2D / 3D mismatch — A BoxCollider (3D) will never interact with a BoxCollider2D. Similarly,
OnCollisionEnteris for 3D physics andOnCollisionEnter2Dis for 2D physics. Mixing the two dimensions is a silent failure. - Kinematic Rigidbody limitations — A Rigidbody with
isKinematicset to true will not generateOnCollisionEnterwhen colliding with another kinematic Rigidbody or a static collider. At least one object must be a non-kinematic (dynamic) Rigidbody.
The Fix
Step 1: Add a Rigidbody and verify isTrigger settings. Select each of the GameObjects involved in the collision. Make sure at least one has a Rigidbody component. Then check every Collider on both objects and ensure isTrigger is unchecked if you want OnCollisionEnter (or checked if you want OnTriggerEnter).
using UnityEngine;
public class ProjectileCollision : MonoBehaviour
{
private void Start()
{
// Verify this object has a collider and a Rigidbody at runtime
Collider col = GetComponent<Collider>();
Rigidbody rb = GetComponent<Rigidbody>();
if (col == null)
Debug.LogError("No Collider found on " + gameObject.name);
if (rb == null)
Debug.LogWarning("No Rigidbody on " + gameObject.name +
". OnCollisionEnter requires at least one Rigidbody.");
if (col != null && col.isTrigger)
Debug.LogWarning("Collider isTrigger is ON. Use OnTriggerEnter instead.");
}
// This will only fire if:
// 1. At least one object has a Rigidbody
// 2. Neither collider has isTrigger enabled
// 3. Both layers can collide in the Physics matrix
private void OnCollisionEnter(Collision collision)
{
Debug.Log("Collision with: " + collision.gameObject.name);
Debug.Log("Contact point: " + collision.GetContact(0).point);
}
}
Step 2: Check the Layer Collision Matrix. Go to Edit > Project Settings > Physics (or Physics 2D for 2D games). At the bottom you will see a matrix of checkboxes showing which layers can collide with which. Find the layers your two objects are on and make sure their intersection is checked.
using UnityEngine;
public class CollisionLayerDebugger : MonoBehaviour
{
[SerializeField] private GameObject otherObject;
private void Start()
{
if (otherObject == null) return;
int layerA = gameObject.layer;
int layerB = otherObject.layer;
bool canCollide = !Physics.GetIgnoreLayerCollision(layerA, layerB);
Debug.Log("Layer '" + LayerMask.LayerToName(layerA) +
"' vs '" + LayerMask.LayerToName(layerB) +
"' can collide: " + canCollide);
if (!canCollide)
{
Debug.LogError("These layers are set to IGNORE each other. " +
"Fix in Edit > Project Settings > Physics.");
}
}
}
Step 3: Verify collider placement and method signatures. If the Collider sits on a child object while the Rigidbody is on the parent, the callback fires on the parent. Also make sure you are using the correct callback for your physics dimension — OnCollisionEnter for 3D, OnCollisionEnter2D for 2D. The parameter type must match exactly.
using UnityEngine;
// For 3D physics: requires Collider + Rigidbody
public class Collision3DHandler : MonoBehaviour
{
// Correct signature for 3D collisions
private void OnCollisionEnter(Collision collision)
{
Debug.Log("3D collision with " + collision.gameObject.name);
// Access collision details
ContactPoint contact = collision.GetContact(0);
Debug.Log("Hit normal: " + contact.normal);
Debug.Log("Impact force: " + collision.impulse.magnitude);
}
}
// For 2D physics: requires Collider2D + Rigidbody2D
public class Collision2DHandler : MonoBehaviour
{
// Correct signature for 2D collisions - note the "2D" suffix
private void OnCollisionEnter2D(Collision2D collision)
{
Debug.Log("2D collision with " + collision.gameObject.name);
ContactPoint2D contact = collision.GetContact(0);
Debug.Log("Hit point: " + contact.point);
}
}
// If collider is on a child, put the script on the Rigidbody parent
// OR forward the event from the child:
public class ChildCollisionForwarder : MonoBehaviour
{
private void OnCollisionEnter(Collision collision)
{
// Forward to parent script
var parentHandler = GetComponentInParent<Collision3DHandler>();
if (parentHandler != null)
{
parentHandler.OnCollisionEnter(collision);
}
}
}
Here is a quick reference for the Unity collision matrix rules. Both objects need Colliders, and at least one needs a Rigidbody:
- Static Collider vs Static Collider — No callbacks. No physics interaction at all.
- Rigidbody vs Static Collider — Callbacks fire on both objects.
- Rigidbody vs Rigidbody — Callbacks fire on both objects.
- Kinematic Rigidbody vs Static Collider — No callbacks.
- Kinematic Rigidbody vs Kinematic Rigidbody — No callbacks.
- Kinematic Rigidbody vs Rigidbody — Callbacks fire on both objects.
If you need collision detection between two kinematic bodies, consider using triggers (isTrigger = true) with OnTriggerEnter instead, or enable Contact Pairs Mode to Enable Kinematic Kinematic Pairs in your Physics settings.
Related Issues
See also: Fix: Unity Raycast Not Hitting Any Colliders.
See also: Fix: Unity Camera Not Rendering or Showing Black Screen.
At least one Rigidbody, matching isTrigger settings, and layers that can collide.