How to host a (Unity) event

Seona Bellamy
3 min readMay 30, 2021

The more scripts you have in your project, the more likely you are going to need to get them to talk to each other. There are several ways to do this, and the most common is with a GetComponent<>() call. This involves finding a specific GameObject (often by name or tag) and then accessing the script component attached to it. You can then call public variables and methods in that script.

This has a few downsides. The biggest is that GameObject.Find() and similar functions are not terribly efficient, especially in a game with lots of objects. This means that if it’s something you need to do often you can really suffer a performance hit. The second pitfall is that if you don’t do very thorough null-checking there is a chance that your whole game can fall over if you retrieve a GameObject that doesn’t have the required script attached. Lastly, it makes all of your scripts extremely dependant on each other — if one script in the sequence is removed, the whole process falls down.

Events make handling inter-script communication much easier and safer. Script A simply raises an event, saying “I’m doing a thing!”. Other scripts that care that Script A is doing the thing listen for that event, and respond accordingly when when they hear it. The important thing to note is that Script A doesn’t care who is listening and the other scripts don’t care where the event is coming from.

Let’s see it in action. Imagine you have a game where you want your player to take damage every time it collides with an obstacle. At the top of the Obstacle script, you would create an event like this:

public static event Action onPlayerCollision;

Further down the Obstacle script, in the OnTriggerEnter() or OnCollisionEnter() method, you would include the following:

if (onPlayerCollision != null)
{
onPlayerCollision();
}

This says “Is anyone listening for this event? If so, do whatever you do in response.” It can also be written in a more condensed form:

onPlayerCollision?.Invoke();

So now that we’re raising the event, how do we listen for it and respond? Let’s start by giving our Player a basic lives system. Add the following variable to the top of the Player class:

private int _lives = 3;

So our player starts with three lives, and will die when those lives reach zero. Now we’ll create a Damage method to actually do this:

void Damage()
{
_lives--;

if (_lives < 1)
{
Destroy(gameObject);
}
}

When this method is called, we subtract one from _lives. Then we check if we’re out of lives, and if we are we destroy the player object. Note that the check is for less-than-one rather than equals-zero. This is because if the player collides with multiple objects simultaneously it is possible for the lives counter to drop below zero.

Now we need to actually tie this function to the event so that it will happen when we need it to. For this we’re introducing two of Unity’s built-in methods: OnEnable() and OnDisable().

void OnEnable()
{
Obstacle.onPlayerCollision += Damage;
}

void OnDisable()
{
Obstacle.onPlayerCollision -= Damage;
}

Unlike the Start() method that only runs once at the beginning of the scene, OnEnable() will run every time an object becomes active — so it runs at the beginning of the scene, and then if you turn the object off and then on again it runs again. So we tell the script to listen for the event whenever it’s enabled. Likewise, OnDisable() runs every time the object is turned off. So we tell the script to stop listening for the even whenever it’s disabled. This means that if you are using SetActive() to control which objects are currently running in your scene, you can be sure that the event will only be listened to by objects that are currently active.

And that’s it. Your player will now lose a life every time they collide with an obstacle, and will pop out of existence when they run out of lives. And you’ve done it without having to perform costly GetComponent() checks.

--

--