A Relatable Experience  

There is a famous story of the great philosopher and scientist Archimedes. As it is told; whilst stepping into a warm bath intending to relax after a long day of musings, Archimedes noticed the water in the tub began to rise. In fact it rose more and more the further he immersed himself. After pausing for a moment to ponder this; he leapt out of the tub and without so much as thought to clothe himself, ran into the streets screaming “Eureka! Eureka”.  

Archimedes excitement was not misplaced, as he had just come to the realisation that objects displaced water equal to their volume when submerged. This was an exciting revelation indeed. Whilst I cannot confess to have run through the street naked, I have experienced many a “Eukrea!” moments during my time learning Unity. One such time was as when I discovered the existence of Unity Events.

Why Make an Event?

One of the reoccurring issues I recall struggling with when beginning to work in Unity; was communicating data between my scripts. I understood enough of Object-Oriented Programming that my scripts should be written to carry out all but a single task. But my coding logic would always require information from different parts of the game in order to work. For example; each aspect of the game, from the UI to enemy AI might have to execute different logic when the player dies. But how are these different scripts supposed to know when they player died?

Initially my ‘hacky’ solution to this was to do multiple Boolean condition checks in each call of Update. For example my player health script would have a Boolean called ‘IsPlayerAlive’, and upon each frame, every script that needed to know would check. Needless to say, this was a disgustingly inefficient way to do it. Not to mentioned compounded by the all the ‘Get Component’ calls needed in the Start method to make this work. I knew there had to be a better way. So yes, my excitement was comparable to Archimedes when I discovered I could do away with all of this with a little understanding of Unity Events and Delegates.

A Quick Brief on Delegates.

The concept of a delegate in C# is one of enormous depth and with numerous applications in your games. Delegates are certainly worthy of a blog post of their own, but for now I will provide a brief explanation of what a delegate is since Unity Events are delegates. You are probably aware of the distinction between a variable type such as int or float, and method.  The former is data and the latter is logic. Well a delegate is both. Essentially is a delegate is special type of function that can be stored into a variable as if it were data. Pretty nifty huh?

The process for creating and using a delegate is as follows:

  1. Define the delegate.
  2. Create a static instance of that delegate.
  3. Assign desired methods to the delegate as if they and the delegate were variables.
  4. Call the delegate like a method within another method.

The result is that all the methods you assigned to the delegate get called simultaneously with the delegate. 

 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DelegateExample : MonoBehaviour
{
    public delegate void MyDelegate(); //1. Define the Delegate
    public static MyDelegate myDelegateInstance;   //2. Create a static instance of that delegate

    // Start is called before the first frame update
    void Awake()
    {        
        //3. Assign desired methods to the delegate as if they were variables.
        myDelegateInstance += FirstDelegateMethod;
        myDelegateInstance += SecondtDelegateMethod;
    }

    // Update is called once per frame
    void Start()
    {
        //4.Call the delegate like a method within another method.
        myDelegateInstance(); 
    }

    private void FirstDelegateMethod()
    {
        Debug.Log("First Delegant Method is Called.");
    }

    private void SecondtDelegateMethod()
    {
        Debug.Log("Second Delegant Method is Called.");
    }
}

 

Getting the Unity Event Started

So what is the relevance of this delegate nonsense to Unity Events? Well, Unity Events are really an abstracted form of delegates and thus the process is the same.

 

  1. Define a Unity Event.
  2. Create a static instance of that event.
  3. Assign desired methods to the event.
  4. Invoke the event within another method.

To see this in action I will given an example that solves a similar problem to the one initially discussed above. In this situation I have a script that monitors and controls the enemy’s health. Now when the enemy is killed, I want two things to happen. Firstly, update the score and secondly spawn a new enemy.

In the code below an event called “enemyDied” is defined and assigned in the Awake method. Now this leads to a large pitfall to watch out for. The instance of the event is created in the Awake method, meaning that any assignments to this event cannot occur within the Awake method unless you enjoy errors that break your game. A null exception will also be raised if the Enemy Health script is not in the scene when the event assigned is to. Have no fear there is a solution. Simply check that the event is not null before assigning to it .

 

 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;  //Be sure to include the namespace

public class EnemyHealth : MonoBehaviour
{
    private float enemyHealth; //Enemy Health

    public static UnityEvent enemyDied; //Define the event.

    // Awake called before start
    private void Awake()
    {   
        enemyDied = new UnityEvent(); //Create instance of the event. 
    }

    // Start is called before the first frame update
    void Start()
    {
        enemyHealth = 100f; //Set inital health value
    }

    /// 
    /// This method will reduce the enemy's health by the damage given.
    /// 
    ///
    public void DamageEnemy(float damage)
    {
        enemyHealth -= damage;
        if (enemyHealth <= 0f)
        {
            enemyDied.Invoke();  //Invoking/Calling the Unity Event when enemy health as dropped to zero.  
        }
    }
}

 

Now within the start method of our spawner and player score classes we add our methods to the event as if as if they were variables. Also note you do not need to use the Unity Event namespace when adding to or invoking events. Only when the event is defined.

 

 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerScore : MonoBehaviour
{
    public float playerScore = 0; //players score

    private Text score; //UI text on this object.

    // Start is called before the first frame update
    void Start()
    {
        score = GetComponent();
        //Check that enenmy exsits
        if (EnemyHealth.enemyDied != null)
        {
            EnemyHealth.enemyDied.AddListener(IncreaseScore); //Add Listner
        }
       
    }

    /// 
    /// This method will increase the player's score by specified amount.
    /// 
    ///
    private void IncreaseScore()
    {
        playerScore += 10f;
    }

    /// 
    /// This method will update the score displayed on the screen. 
    /// 
    private void UpdateUI()
    {
        score.text = playerScore.ToString();
    } 



 
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    [SerializeField]
    private GameObject enemy; //A reference to the prefab of our enemy.
    [SerializeField]
    private Vector3 spawnLocation;


    private void Start()
    {
        EnemyHealth.enemyDied.AddListener(SpawnEnemy);  //The the Spawn Enemy Method to the Event      
    }

    /// 
    /// This method when called will spawn an enemy at a the spawn location. 
    /// 
    private void SpawnEnemy()
    {
        Instantiate(enemy, spawnLocation, Quaternion.identity);
    }
}

This is example is not perfect and susceptible to errors. For instance, if there is no enemy in the scene at runtime. The enemy spawner will never actually spawn a new enemy. However, the purpose of this example was simply to demonstrate how you can create and listen to a unity event.

Creating an Event Manager

With any programming endeavour, the goal is simplicity and modularity. Programmers are a lazy species and if we can get create a more universal way to do something we will. So, if your game utilizes lots of different events (which hopefully I have convinced you that it should) you can create a universal event manager. This is also away to get around some of the null exceptions that might arise from the example discussed above.

However rather than demonstrate my own example of an Event manager I will simply direct you to this great tutorial developed by the team at Unity on the topic. The event manager outlined in their tutorial is essentially what I now use in all my games. Regardless of if you need an event manager, I encourage you to take advantage of Unity Events in your games.

 References & Other Resources

 

  1. Vivek Tank, 2018, How to use C# Events in Unity

  2. Unity3D, Events

  3. Wikipedia, 2019, Eureka (word)

  4. UnityGeek, 2016, Delegates and Events in Unity