Summary
Collider2D is the component that defines the physical shape of a 2D GameObject for collision detection. It has two operating modes: solid (objects physically push each other) and trigger (overlap detection only, no physical response). Solid collisions fire OnCollisionEnter2D; trigger overlaps fire OnTriggerEnter2D. The distinction controls whether the physics engine actually pushes objects apart or simply notifies the script that an overlap has begun.
Key ideas
Collider2D types:
| Type | Shape | Common use |
|---|---|---|
BoxCollider2D | Rectangle | Characters, walls, platforms |
CircleCollider2D | Circle | Coins, projectiles, round enemies |
PolygonCollider2D | Arbitrary polygon | Irregular terrain, shaped pickups |
CapsuleCollider2D | Capsule | Humanoid characters |
Is Trigger: When enabled on a Collider2D, that collider no longer blocks movement. It only detects overlap. OnTriggerEnter2D fires when the overlap begins. OnTriggerExit2D fires when it ends. Use for: pickups, hazards, area detectors, exit zones.
Solid collision (Is Trigger off on both colliders): Objects physically block each other. OnCollisionEnter2D fires on contact. Use for: walls, floors, platforms.
OnTriggerEnter2D(Collider2D other): The other parameter is the collider that entered the trigger. Use other.CompareTag("TagName") to identify what type of object it is.
OnCollisionEnter2D(Collision2D collision): The collision parameter provides contact data. collision.gameObject is the other object; collision.contacts[0].normal is the surface direction of the hit.
CompareTag(string tag): The correct way to check an object’s tag. Faster than other.tag == "TagName" because it does not allocate a new string. Unity will log a warning if you compare against a tag name that does not exist in the project.
Destroy(GameObject): Removes a GameObject from the scene. Always call this last in a pickup handler, after all other logic has run, so nothing tries to access the object after it is destroyed.
In practice
Trigger overlap detection (coins, hazards, health packs):
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Coin"))
{
HandleCoin(other.gameObject);
}
else if (other.CompareTag("Hazard"))
{
HandleHazard(other.gameObject);
}
else if (other.CompareTag("HealthPack"))
{
HandleHealthPack(other.gameObject);
}
// Unrecognised tags are silently ignored
}
private void HandleCoin(GameObject coin)
{
score += 10;
Debug.Log("Coin collected! Score: " + score);
Destroy(coin); // call LAST
}Reading the trigger event chain:
- Unity calls
OnTriggerEnter2Dautomatically when the overlap begins. otheris the Collider2D on the object that entered this trigger. It is not always the player and not always the pickup, so read the setup carefully.CompareTag("Coin")decides which branch runs.other.gameObjectconverts the collider reference into the GameObject that should be passed toHandleCoin.HandleCoinupdates state, logs the result, then destroys the coin last.
If this script is on the player, Destroy(coin) removes the coin. If the same logic is placed on the coin instead, gameObject and other.gameObject swap meanings. This is why the course fast-track tasks explicitly ask students to distinguish the object the script is attached to from the object that entered the trigger (course lab series, see source-csharp-unity-labs).
Solid collision detection (walls):
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Wall"))
{
Debug.Log("Wall hit. Normal: " + collision.contacts[0].normal);
}
}Invincibility window after taking damage:
[SerializeField] private float invincibilityDuration = 1.5f;
private float invincibilityTimer = 0f;
private bool isInvincible = false;
void Update()
{
if (isInvincible)
{
invincibilityTimer -= Time.deltaTime;
if (invincibilityTimer <= 0f)
{
isInvincible = false;
}
}
}
private void HandleHazard(GameObject hazard)
{
if (isInvincible) return; // blocked during invincibility window
health = Mathf.Max(health - 25, 0);
isInvincible = true;
invincibilityTimer = invincibilityDuration;
}Health pack with Mathf.Min clamp:
private void HandleHealthPack(GameObject pack)
{
health = Mathf.Min(health + 30, maxHealth); // cannot exceed maxHealth
Destroy(pack);
}Setup requirements
For OnTriggerEnter2D to fire, the following must all be true:
- The moving object (e.g. player) must have a Rigidbody2D
- At least one of the two colliders must have Is Trigger enabled
- Both objects must be on layers that interact in the Physics Layer Matrix (Edit > Project Settings > Physics 2D)
- Tags referenced in
CompareTagmust be defined in the project (Edit > Project Settings > Tags and Layers)
Most beginner collision bugs are configuration errors, not code errors. When a trigger is not firing, check these four things before reading the script.
Gotchas
other.tag == "Coin"works but allocates a new string each call. Useother.CompareTag("Coin")instead.- Both
OnTriggerEnter2DandOnCollisionEnter2Dmust be on a script attached to a GameObject that has aCollider2D. They do not fire on a script attached to an empty object with no collider. OnTriggerEnter2Dfires once per overlap start. It will not fire repeatedly while the objects remain overlapping — useOnTriggerStay2Dfor continuous detection.Destroy(gameObject)destroys the object the script is attached to.Destroy(other.gameObject)destroys the other object. Confusing these is a common error.- After calling
Destroy(coin), any further code that referencescoinwill throw aNullReferenceException. Always callDestroylast.
Debugging practice
Use this table before rewriting code. Most trigger bugs are setup bugs.
| Symptom | Likely cause | Fix |
|---|---|---|
OnTriggerEnter2D never runs | No Rigidbody2D on either object | Add Rigidbody2D to the moving object |
| Objects bounce instead of overlap | Is Trigger is off | Enable Is Trigger on the pickup, hazard or detector |
| Code runs for the wrong object | Tag check is missing or wrong | Add the tag in Tags and Layers, then use CompareTag |
| Coin destroys the player | Used Destroy(other.gameObject) in a script on the coin | Destroy the coin with Destroy(gameObject) |
| Trigger works in one scene but not another | Layer collision matrix differs | Check Physics 2D layer settings |
Self-test
- What is the main difference between a trigger and a solid collision?
- What component is required for 2D trigger messages to fire reliably?
- Why should
Destroynormally be called last in a pickup method? - Why is
CompareTag("Coin")preferred overother.tag == "Coin"? - Which object does
Destroy(gameObject)destroy?
Answers
- A trigger detects overlap without pushing objects apart. A solid collision produces physical contact.
- A
Rigidbody2D, normally on the moving object. - Later code may try to access the destroyed object and cause an error.
CompareTagavoids string allocation and warns about missing tags.- The GameObject that this script is attached to.
Worked example
Overlap-query collision (rather than trigger callbacks) in the Breakout teaching example (see overview-arcade-classics-as-learning-projects):
- Ball2D.cs — detects bricks with
Physics2D.OverlapBoxagainst a layer mask
Related
- unity-rigidbody2d - Rigidbody2D is required on the moving object for triggers to fire
- monobehaviour-lifecycle -
Updatefor the invincibility timer and lifecycle context for collision methods - unity-inspector-references - wiring
GameManagerreferences on pickup scripts - csharp-control-flow -
if/else ifchains in trigger handlers