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
- Collider2D: Define collision area
- Rigidbody2D: Required on at least one side
- Trigger Setup: Choose based on usage
- Tag Setup: For object identification
Best Practices
- Use tags: Check with tags instead of names
- Null check: Check null after GetComponent()
- Prevent duplicates: Use flags to prevent duplicate collisions
- Performance: OnTriggerStay2D is called every frame, be careful
Practice Problems
-
Write a script that adds 10 points to the score when the player touches a coin and destroys the coin.
-
Write a script that reduces the player's health by 5 every second while the player is in a poison gas zone.
-
Write a script that reduces the enemy's health when a bullet hits an enemy and destroys the bullet.