Unity Scripting Primer Part 3: Collisions and Triggers

Following on from Part 2, where we looked at the common Unity MonoBehaviour methods like Update() and OnEnable(), in Part 3 we will look at the MonoBehaviour methods that deal with physics collisions. These methods make common physics behaviours easy to manage.

A few quick notes:

  • In this article I will discuss the 2D versions of these methods (but the 3D equivalents work in much the same way).
  • Because Unity originally didn’t include 2D tools, 3D is the default, and the 2D methods have the 3D method names with ‘2D’ tacked on the end:
    • OnCollisionEnter – (3D version)
    • OnCollisionEnter2D – (2D version)
  • You must spell the method names correctly (they are case sensitive) and use the correct method parameters (e.g. don’t get Collision2D and Collider2D mixed up).
  • For a great intro to Unity physics for beginners, check out the Unity Beginner Physics tutorial videos.

At the bottom of this article is a link to a small Unity project that demonstrates these concepts with a demo of a fan object that blows balls as they enter into its trigger zone.

Definitions

Colliders

A collider is a shape that defines an object’s physical presence. For example, a 2D wheel would have a circle collider that defines the physical shape of the wheel. Nothing else can occupy the wheel’s physical space, so when another object collides with the wheel (such as the ground) they will interact according to their physics. A collider generally conforms to the shape of the item it’s attached to (i.e. its physical appearance), though you might use a different shape, such as a rectangle for a more complicated shape where precision is not important (simpler shapes need less processing).

Uses for colliders

  • Give objects a physical presence
  • Balls, walls, cars…just about anything that needs physical interaction.

Triggers

A trigger is a special collider that does not have a ‘physical presence’, but still detects when an object enters into the its sace. For example, you could define a trigger area in front of an automatic door, and when the player crosses into the trigger area (unlike a collider other objects can enter the trigger’s physical space) you can trigger an action, such as opening the automatic door. To define a collider as a trigger you simply check the Is Trigger box:

If a ball with a trigger collider (and no regular collider) hits a solid wall the ball will pass through the wall, but the relevant trigger methods will execute – so your scripts are aware that an interaction has occurred despite no actual physical interaction between the objects.

Uses for triggers
  • When you want to detect interaction without physics
  • Proximity (if the player is near something special, like an automatic door)
  • Defining an area of influence (e.g. a fan that blows anything placed close by)
  • Collectible items (e.g. coins in Super Mario Bros. – if the coins had colliders the player would bang into them instead of picking them up).

Enter, Exit, and Stay, Oh My!

There are three collision detecting methods in MonoBehaviour, and corresponding trigger versions (Note: remove the ‘2D’ for the 3D versions):

  • OnCollisionEnter2D / OnTriggerEnter2D – runs when a collider collides with a collider on the gameobject the script is attached to (fires once when the objects initially touch).
  • OnCollisionExit2D / OnTriggerExit2D – runs when a collider stops colliding (fires once)
  • OnCollisionStay2D / OnTriggerStay2D – runs when the colliders are still touching (fires every physics frame while the colliders are touching).

When two colliders touch, OnCollisionEnter2D executes. Then, as long as the two colliders are still touching, OnCollisionStay2D executes during every physics tick/frame. Finally, when the colliders stop colliding, OnCollisionExit2D will execute. Using these three methods well allows for lots of different functionality.

In my game Game of Clowns (a physics puzzle game), I use trigger collisions to create a hose spray effect. When an item is in the hose’s area of influence (OnTriggerStay2D), my hose adds a pushing force.

You can put whatever code you want inside those three methods, but remember that basic physics interactions do not need to be coded (they are handled by Unity’s physics engine), so if you have a ball made out of a bouncy material it will bounce off hard surfaces with no collision detecting required (but you could, for instance, use the collision to destroy the brick the ball hits or increase the player’s score).

The Others

Within these methods, the object that hits the script’s local collider is referred to as ‘other’. Trigger methods use type Collider2D, and regular colliders use Collision2D. It’s important to get this right, because if you use the wrong type in the method signature Unity will not work.

In recent Unity versions this common mistake triggers an error, which should save you a lot of headaches: You can use the otherparameter to access properties and methods of the other object.

Note: when making changes to the ‘local’ object within collision methods I use this to make it clear which object I’m working on (e.g. this.transform.position …).

void OnTriggerEnter2D(Collider2D other)
{
   other.transform.position = new Vector3(0,0,0);
   this.score += 5;
}

With the OnCollision… methods you use Collision2D instead of Collider2D. This gives you some more information to play with (which I won’t go into here). You can use it in exactly the same way:

void OnCollisionEnter2D(Collision2D)
{
   other.transform.position = new Vector3(0,0,0);
}

Fan (an example)

Download the sample project from the link at the bottom and watch colliders and triggers in action. The project has a few balls that fall into the trigger zone of a couple of fans, which contain a script that applies a pushing force to anything that falls within their trigger colliders.

You can see the different behaviour between a regular collider and a trigger by ticking/unticking the Is Trigger property of the fan’s ‘blow’ collider.

I’ve included all the trigger methods:

  • OnTriggerEnter2D – this will be called once when the ball first enters the fan’s air stream. All we will do here is print some text to the debug log to show it’s working.
  • OnTriggerStay2D – this is called every frame when the ball is within the air stream (except the first frame, which is handled by OnTriggerEnter2D). During this method we ‘blow’ the ball by applying a small force.
  • OnTriggerExit2D – this is called once when the ball leaves the air stream area. Again we will just put in some debug log text to show it’s working.

So you can switch the fan between a trigger and regular collider I’ve also included the collision methods, which will just display some debug log text.

Hint: I like to put my collision and trigger events in the order they act: Enter, Stay, and finally Exit.

Here is the code for the FanScript.cs script:

using UnityEngine;
using System.Collections;

public class FanScript : MonoBehaviour
{
   public Transform ParentFan;
   public float FanPower = 25; // how strongly the fan will blow sideways (x axis), 25 by default
   void Start ()
   {
     FanPower = FanPower * -ParentFan.localScale.x; // multiple by the direction the fan is facing to direct the air
   }
  
   void OnTriggerEnter2D(Collider2D other)
   {
     Debug.Log(other.name + " entered fan trigger area");
   }
  
   void OnTriggerStay2D(Collider2D other)
   {
     other.rigidbody2D.AddForce(new Vector2(FanPower, 25));
   }
 
   void OnTriggerExit2D(Collider2D other)
   { 
     Debug.Log(other.name + " exited fan trigger area");
   }

   void OnCollisionEnter2D(Collision2D other)
   {
     Debug.Log(other.transform.name + " collided");
   }

   void OnCollisionStay2D(Collision2D other)
   {
     Debug.Log(other.transform.name + " still touching");
   }

   void OnCollisionExit2D(Collision2D other)
   {
     Debug.Log(other.transform.name + " stopped touching");
   }
}

I’ve included a bit of functionality to allow the fans to blow in the correct direction, and I’ve put a blue sprite in the fans to show where their trigger areas are. You would probably disable this in a real game. Experiment by turning the triggers into colliders, and watch the debug log if you have any difficulty following what is happening.

What next?

You can now detect whenever objects in your game touch (or, in the case of triggers, enter into a certain area). You can use tags on your objects to categorise them and get more control (e.g. if an object tagged ‘ghost’ enters an automatic door’s trigger you can ignore the trigger).

Tips and Tricks

  • In pre- Unity 4.5 versions make sure you use the correct object type in the method signatures. In Unity 4.5 an error is triggered,  but not so in earlier versions
  • Make sure your scripts are attached to the same object as the colliders
  • When you can’t tell what’s happening use Debug.Log inside your collision methods to see if they are being triggered correctly.
  • In earlier Unity versions there were bugs with the exit methods not always being called, and possibly other issues, so be careful with older versions.
  • When designing and testing your game I recommend using temporary sprites to indicate trigger regions. This can help you figure out the best size/placement.

That’s it for colliders and triggers. In the next part of this series I’ll run through some optimization techniques for Unity games based on some scripting best practices.

Downloadable Demo

Unity Collision and Trigger demo project 

Leave a Comment