Unity Collisions and Triggers - OnCollisionEnter and OnTriggerEnter

January 17, 2026 ยท View on GitHub

Unity provides two types of collision detection: Collisions (physics-based) and Triggers (overlap detection).

Collision vs Trigger: When to Use Each

Use CaseTypeExample
Physical interactionsCollisionPlayer hitting a wall, ball bouncing
Detecting overlap without physicsTriggerPicking up coins, entering zones
Damage on impactCollisionBullet hitting enemy with knockback
Damage without impactTriggerWalking through lava, laser beam

Requirements

For collision/trigger events to fire, you need:

RequirementCollision EventsTrigger Events
Collider on both objectsYesYes
Rigidbody on at least oneYesYes
"Is Trigger" checkedNoYes (on at least one)

3D Collision Events

Called when colliders physically collide. Objects will bounce/interact based on physics.

OnCollisionEnter

Called once when collision begins.

void OnCollisionEnter(Collision collision)
{
    Debug.Log("Hit: " + collision.gameObject.name);
}

OnCollisionStay

Called every frame while collision continues.

void OnCollisionStay(Collision collision)
{
    Debug.Log("Still touching: " + collision.gameObject.name);
}

OnCollisionExit

Called once when collision ends.

void OnCollisionExit(Collision collision)
{
    Debug.Log("Stopped touching: " + collision.gameObject.name);
}

Collision Class Properties

The Collision parameter provides detailed collision information:

void OnCollisionEnter(Collision collision)
{
    // The GameObject we collided with
    GameObject other = collision.gameObject;
    
    // The Rigidbody we collided with (can be null)
    Rigidbody otherRb = collision.rigidbody;
    
    // The Collider we collided with
    Collider otherCollider = collision.collider;
    
    // Relative velocity of the collision
    Vector3 impactVelocity = collision.relativeVelocity;
    float impactForce = impactVelocity.magnitude;
    
    // Total impulse applied during collision
    Vector3 impulse = collision.impulse;
    
    // Number of contact points
    int contactCount = collision.contactCount;
    
    // First contact point
    if (contactCount > 0)
    {
        ContactPoint contact = collision.GetContact(0);
        Vector3 hitPoint = contact.point;
        Vector3 hitNormal = contact.normal;
    }
}

Practical Example: Damage on Impact

public class DamageOnCollision : MonoBehaviour
{
    public float damageMultiplier = 10f;
    public float minImpactForce = 5f;

    void OnCollisionEnter(Collision collision)
    {
        float impactForce = collision.relativeVelocity.magnitude;
        
        if (impactForce > minImpactForce)
        {
            float damage = impactForce * damageMultiplier;
            
            // Try to get Health component from collided object
            Health health = collision.gameObject.GetComponent<Health>();
            if (health != null)
            {
                health.TakeDamage(damage);
            }
        }
    }
}

3D Trigger Events

Called when colliders overlap. No physics response occurs - objects pass through each other.

Setup: Check "Is Trigger" on at least one of the colliders in the Inspector.

OnTriggerEnter

Called once when another collider enters the trigger.

void OnTriggerEnter(Collider other)
{
    Debug.Log(other.gameObject.name + " entered trigger");
}

OnTriggerStay

Called every frame while another collider is inside the trigger.

void OnTriggerStay(Collider other)
{
    Debug.Log(other.gameObject.name + " is inside trigger");
}

OnTriggerExit

Called once when another collider exits the trigger.

void OnTriggerExit(Collider other)
{
    Debug.Log(other.gameObject.name + " exited trigger");
}

Practical Example: Pickup Item

public class PickupItem : MonoBehaviour
{
    public int coinValue = 10;
    public AudioClip pickupSound;

    void OnTriggerEnter(Collider other)
    {
        // Only respond to player
        if (other.CompareTag("Player"))
        {
            // Add coins to player
            PlayerScore score = other.GetComponent<PlayerScore>();
            if (score != null)
            {
                score.AddCoins(coinValue);
            }
            
            // Play sound at pickup location
            if (pickupSound != null)
            {
                AudioSource.PlayClipAtPoint(pickupSound, transform.position);
            }
            
            // Destroy pickup
            Destroy(gameObject);
        }
    }
}

Practical Example: Damage Zone

public class DamageZone : MonoBehaviour
{
    public float damagePerSecond = 10f;

    void OnTriggerStay(Collider other)
    {
        Health health = other.GetComponent<Health>();
        if (health != null)
        {
            health.TakeDamage(damagePerSecond * Time.deltaTime);
        }
    }
}

2D Collision Events

For 2D games, use the 2D variants with Collision2D and Collider2D types.

Collision Events (2D)

void OnCollisionEnter2D(Collision2D collision)
{
    Debug.Log("Hit: " + collision.gameObject.name);
    
    // 2D-specific properties
    Vector2 contactPoint = collision.GetContact(0).point;
    Vector2 contactNormal = collision.GetContact(0).normal;
}

void OnCollisionStay2D(Collision2D collision)
{
    Debug.Log("Still touching: " + collision.gameObject.name);
}

void OnCollisionExit2D(Collision2D collision)
{
    Debug.Log("Stopped touching: " + collision.gameObject.name);
}

Trigger Events (2D)

void OnTriggerEnter2D(Collider2D other)
{
    Debug.Log(other.gameObject.name + " entered trigger");
}

void OnTriggerStay2D(Collider2D other)
{
    Debug.Log(other.gameObject.name + " is inside trigger");
}

void OnTriggerExit2D(Collider2D other)
{
    Debug.Log(other.gameObject.name + " exited trigger");
}

2D Platformer Example: Ground Check

public class GroundCheck : MonoBehaviour
{
    public bool isGrounded = false;

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Ground"))
        {
            isGrounded = true;
        }
    }

    void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Ground"))
        {
            isGrounded = false;
        }
    }
}

Common Patterns

Tag Checking

Filter collisions by tag using CompareTag() (faster than ==):

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("Enemy"))
    {
        // Handle enemy collision
    }
    else if (collision.gameObject.CompareTag("Pickup"))
    {
        // Handle pickup collision
    }
}

Layer Checking

Filter by layer for more complex scenarios:

void OnTriggerEnter(Collider other)
{
    // Check if object is on "Interactable" layer
    if (other.gameObject.layer == LayerMask.NameToLayer("Interactable"))
    {
        // Handle interaction
    }
}

Getting Components

Access components on the collided object:

void OnCollisionEnter(Collision collision)
{
    // Try to get a component (returns null if not found)
    Enemy enemy = collision.gameObject.GetComponent<Enemy>();
    if (enemy != null)
    {
        enemy.TakeDamage(10);
    }
    
    // TryGetComponent is slightly more efficient (Unity 2019.2+)
    if (collision.gameObject.TryGetComponent<Enemy>(out Enemy e))
    {
        e.TakeDamage(10);
    }
}

Destroy on Collision

void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("Enemy"))
    {
        // Destroy the enemy
        Destroy(collision.gameObject);
        
        // Destroy this object (e.g., bullet)
        Destroy(gameObject);
    }
}

Collision Matrix

Not all collider combinations generate events. Here's a simplified reference:

Collision Events (OnCollisionEnter, etc.)

Object AObject BEvents Fire?
RigidbodyStatic ColliderYes
RigidbodyRigidbodyYes
RigidbodyKinematic RigidbodyYes
KinematicStatic ColliderNo
KinematicKinematicNo
StaticStaticNo

Trigger Events (OnTriggerEnter, etc.)

Object AObject BEvents Fire?
Rigidbody TriggerAny ColliderYes
Kinematic TriggerAny ColliderYes
Static TriggerRigidbody/KinematicYes
Static TriggerStatic ColliderNo

Collider Type Reference

TypeRigidbodyIs KinematicIs Trigger
Static ColliderNone-Off
Rigidbody ColliderYesOffOff
Kinematic ColliderYesOnOff
Static TriggerNone-On
Rigidbody TriggerYesOffOn
Kinematic TriggerYesOnOn

Common Mistakes

1. Missing Rigidbody

Problem: No collision events firing.

Solution: At least one object needs a Rigidbody (or Rigidbody2D for 2D).

// This script won't receive collision events if neither 
// this object nor the collided object has a Rigidbody
void OnCollisionEnter(Collision collision) { } // Never called!

2. Both Objects Are Kinematic

Problem: Two kinematic rigidbodies don't generate collision events.

Solution: Make at least one non-kinematic, or use triggers instead.

3. Trigger Not Enabled

Problem: OnTriggerEnter not being called.

Solution: Check "Is Trigger" on at least one collider in the Inspector.

4. Wrong 2D/3D Methods

Problem: Using OnCollisionEnter in a 2D game.

Solution: Use OnCollisionEnter2D with 2D colliders.

// WRONG for 2D games
void OnCollisionEnter(Collision collision) { }

// CORRECT for 2D games  
void OnCollisionEnter2D(Collision2D collision) { }

5. Layer Collision Matrix

Problem: Objects on certain layers don't collide.

Solution: Check Edit > Project Settings > Physics > Layer Collision Matrix.

6. Scale Affecting Colliders

Problem: Colliders not matching visual mesh after scaling.

Solution: Apply scale in modeling software, or manually adjust collider size.

7. Method Signature Wrong

Problem: Collision methods not being called.

Solution: Ensure exact method signature. Common errors:

// WRONG - lowercase 'c'
void onCollisionEnter(Collision collision) { }

// WRONG - missing parameter
void OnCollisionEnter() { }

// WRONG - wrong parameter type
void OnCollisionEnter(Collider other) { } // Should be Collision

// CORRECT
void OnCollisionEnter(Collision collision) { }

Quick Reference

3D Methods

MethodParameterWhen Called
OnCollisionEnter(Collision)CollisionCollision begins
OnCollisionStay(Collision)CollisionEvery frame during collision
OnCollisionExit(Collision)CollisionCollision ends
OnTriggerEnter(Collider)ColliderEnters trigger
OnTriggerStay(Collider)ColliderEvery frame inside trigger
OnTriggerExit(Collider)ColliderExits trigger

2D Methods

MethodParameterWhen Called
OnCollisionEnter2D(Collision2D)Collision2DCollision begins
OnCollisionStay2D(Collision2D)Collision2DEvery frame during collision
OnCollisionExit2D(Collision2D)Collision2DCollision ends
OnTriggerEnter2D(Collider2D)Collider2DEnters trigger
OnTriggerStay2D(Collider2D)Collider2DEvery frame inside trigger
OnTriggerExit2D(Collider2D)Collider2DExits trigger

See Also