2D Collision Detection

Learn how to detect 2D collisions in Unity. Covers OnTriggerEnter2D, OnTriggerStay2D, OnCollisionEnter2D, and other functions.

What is 2D Collision Detection?

Detecting when objects collide with each other is a very important feature in games. For example, when a player collects a coin, or when a bullet hits an enemy.

Basic Concepts

  • Collider2D: Component that defines 2D collision area
  • Trigger: Mode that only detects without physical collision
  • Collision: Mode where actual physical collision occurs
  • Rigidbody2D: Component for physics simulation

1. Collider2D Setup

To detect collisions, you first need to set up a Collider2D component.

Collider2D Types

  • BoxCollider2D: Rectangular collision area
  • CircleCollider2D: Circular collision area
  • CapsuleCollider2D: Capsule-shaped collision area
  • PolygonCollider2D: Polygon collision area

Trigger Setup

using UnityEngine;

public class Coin : MonoBehaviour
{
    void Start()
    {
        // Get Collider2D
        Collider2D collider = GetComponent<Collider2D>();
        
        if (collider != null)
        {
            // Set to Trigger mode (detect without physical collision)
            collider.isTrigger = true;
        }
    }
}

2. OnTriggerEnter2D() - Detecting Collision Start

OnTriggerEnter2D() is called only once when another object first enters the Trigger area.

Basic Usage

using UnityEngine;

public class FallingFireball : MonoBehaviour
{
    void OnTriggerEnter2D(Collider2D other)
    {
        // Check if collided object is player
        if (other.CompareTag("Player"))
        {
            Debug.Log("Collided with player!");
            
            // Handle game over
            if (GameManager.Instance != null)
            {
                GameManager.Instance.GameOver();
            }
        }
    }
}

Example: Collecting Coins

using UnityEngine;

public class Coin : MonoBehaviour
{
    public int coinValue = 10;

    void OnTriggerEnter2D(Collider2D other)
    {
        // Check if player touched coin
        if (other.CompareTag("Player"))
        {
            // Add score
            GameManager.Instance.AddScore(coinValue);
            
            // Destroy coin
            Destroy(gameObject);
        }
    }
}

Example: Fireball Collision

using UnityEngine;

public class FallingFireball : MonoBehaviour
{
    private bool hasCollided = false;

    void OnTriggerEnter2D(Collider2D other)
    {
        // Ignore if already collided (prevent duplicate collision)
        if (hasCollided)
        {
            return;
        }

        // Check if collided with player
        if (IsPlayer(other))
        {
            hasCollided = true;
            TriggerGameOver();
        }
    }

    private bool IsPlayer(Collider2D other)
    {
        // Player if has "Player" tag or SheepController component
        return other.CompareTag("Player") || 
               other.GetComponent<SheepController>() != null;
    }

    private void TriggerGameOver()
    {
        if (GameManager.Instance != null)
        {
            GameManager.Instance.GameOver();
        }
    }
}

3. OnTriggerStay2D() - Detecting Collision Continuation

OnTriggerStay2D() is called every frame while another object is inside the Trigger area.

Basic Usage

using UnityEngine;

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

    void OnTriggerStay2D(Collider2D other)
    {
        // While player is in damage zone
        if (other.CompareTag("Player"))
        {
            // Deal damage every second
            PlayerController player = other.GetComponent<PlayerController>();
            if (player != null)
            {
                player.TakeDamage(damagePerSecond * Time.deltaTime);
            }
        }
    }
}

Using with OnTriggerEnter2D

using UnityEngine;

public class FallingFireball : MonoBehaviour
{
    private bool hasCollided = false;

    void OnTriggerEnter2D(Collider2D other)
    {
        HandleCollision(other);
    }

    // Backup in case OnTriggerEnter2D is not called
    void OnTriggerStay2D(Collider2D other)
    {
        HandleCollision(other);
    }

    private void HandleCollision(Collider2D other)
    {
        // Ignore if already collided
        if (hasCollided)
        {
            return;
        }

        // Check collision with player
        if (IsPlayer(other))
        {
            hasCollided = true;
            TriggerGameOver();
        }
    }

    private bool IsPlayer(Collider2D other)
    {
        return other.CompareTag("Player") || 
               other.GetComponent<SheepController>() != null;
    }

    private void TriggerGameOver()
    {
        if (GameManager.Instance != null)
        {
            GameManager.Instance.GameOver();
        }
    }
}

4. OnTriggerExit2D() - Detecting Collision End

OnTriggerExit2D() is called only once when another object exits the Trigger area.

Basic Usage

using UnityEngine;

public class SafeZone : MonoBehaviour
{
    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            Debug.Log("Entered safe zone!");
        }
    }

    void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            Debug.Log("Left safe zone!");
        }
    }
}

5. OnCollisionEnter2D() - Physical Collision Detection

OnCollisionEnter2D() is called when a physical collision occurs. This is an actual collision, not a trigger.

Trigger vs Collision

// Trigger mode: Only detect without physical collision
collider.isTrigger = true;
// OnTriggerEnter2D() called

// Collision mode: Actual physical collision occurs
collider.isTrigger = false;
// OnCollisionEnter2D() called

OnCollisionEnter2D Usage

using UnityEngine;

public class Ball : MonoBehaviour
{
    void OnCollisionEnter2D(Collision2D collision)
    {
        // Information about collided object
        GameObject otherObject = collision.gameObject;
        
        // Collision point information
        ContactPoint2D contact = collision.contacts[0];
        Vector2 point = contact.point;
        
        // Collision direction
        Vector2 normal = contact.normal;
        
        Debug.Log("Collision occurred: " + otherObject.name);
        Debug.Log("Collision point: " + point);
    }
}

6. Rigidbody2D Setup

Rigidbody2D is required for collision detection.

Kinematic Setup

using UnityEngine;

public class FallingFireball : MonoBehaviour
{
    void Start()
    {
        SetupRigidbody();
    }

    private void SetupRigidbody()
    {
        Rigidbody2D rb = GetComponent<Rigidbody2D>();
        if (rb == null)
        {
            // Add Rigidbody2D if not present
            rb = gameObject.AddComponent<Rigidbody2D>();
        }

        // Set to Kinematic (move without physics influence)
        rb.bodyType = RigidbodyType2D.Kinematic;
        
        // Disable gravity
        rb.gravityScale = 0;
        
        // Prevent rotation
        rb.freezeRotation = true;
        
        // Enable simulation (required for collision detection)
        rb.simulated = true;
    }
}

7. Practical Examples

Example 1: Player and Fireball Collision

using UnityEngine;

public class FallingFireball : MonoBehaviour
{
    private bool hasCollided = false;

    void OnTriggerEnter2D(Collider2D other)
    {
        HandleCollision(other);
    }

    void OnTriggerStay2D(Collider2D other)
    {
        HandleCollision(other);
    }

    private void HandleCollision(Collider2D other)
    {
        // Prevent duplicate collision
        if (hasCollided)
        {
            return;
        }

        // Check player
        if (other.CompareTag("Player") || 
            other.GetComponent<SheepController>() != null)
        {
            hasCollided = true;
            
            // Game over
            if (GameManager.Instance != null)
            {
                GameManager.Instance.GameOver();
            }
        }
    }
}

Example 2: Item Collection

using UnityEngine;

public class Item : MonoBehaviour
{
    public string itemType = "Coin";
    public int value = 10;

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            PlayerController player = other.GetComponent<PlayerController>();
            if (player != null)
            {
                // Handle item collection
                player.CollectItem(itemType, value);
                
                // Destroy item
                Destroy(gameObject);
            }
        }
    }
}

Example 3: Damage Zone

using UnityEngine;

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

    void OnTriggerStay2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            PlayerController player = other.GetComponent<PlayerController>();
            if (player != null)
            {
                // Deal damage every second
                player.TakeDamage(damagePerSecond * Time.deltaTime);
            }
        }
    }
}

8. Precautions

1. Rigidbody2D Required

// ✅ At least one side needs Rigidbody2D for collision detection
// If both don't have it, collision won't be detected

2. Trigger Setup

// Trigger mode: OnTriggerEnter2D() called
collider.isTrigger = true;

// Collision mode: OnCollisionEnter2D() called
collider.isTrigger = false;

3. Using Tags

// ✅ Good example: Check with tag
if (other.CompareTag("Player"))
{
    // Handle
}

// ❌ Bad example: Check with name (slow)
if (other.name == "Player")
{
    // Handle
}

4. Prevent Duplicate Collision

private bool hasCollided = false;

void OnTriggerEnter2D(Collider2D other)
{
    if (hasCollided) return; // Prevent duplicate
    
    hasCollided = true;
    // Handle collision
}

9. Summary

Collision Detection Function Comparison

Function When Called Usage
OnTriggerEnter2D() When first entering Trigger area Coin collection, item collection
OnTriggerStay2D() While inside Trigger area Continuous damage, buff zone
OnTriggerExit2D() When exiting Trigger area Zone exit notification
OnCollisionEnter2D() When physical collision occurs Physics-based collision

Required Setup

  1. Collider2D: Define collision area
  2. Rigidbody2D: Required on at least one side
  3. Trigger Setup: Choose based on usage
  4. Tag Setup: For object identification

Best Practices

  1. Use tags: Check with tags instead of names
  2. Null check: Check null after GetComponent()
  3. Prevent duplicates: Use flags to prevent duplicate collisions
  4. Performance: OnTriggerStay2D is called every frame, be careful

Practice Problems

  1. Write a script that adds 10 points to the score when the player touches a coin and destroys the coin.

  2. Write a script that reduces the player's health by 5 every second while the player is in a poison gas zone.

  3. Write a script that reduces the enemy's health when a bullet hits an enemy and destroys the bullet.