Delegates, Events and UnityEvents

As I was looking at the Unity Tutorials for Scripting this week I happened to find a concept that seemed particularly relevant for one of the applications I’m developing for HoloLens: Delegates.

After a few Google searches and more than a couple of hours watching tutorials I also found a lot of references to something called Events. I thought to myself, “maybe this should be used instead?“. So, once again, I went into my usual information hunting and it didn’t take long after I found yet another term I had not seen before: UnityEvents.

Now, if you come from a C# background, chances are you’ve heard of at least one of these terms before, but since my past includes mostly C and C++, I was left quite confused. So here is me, trying to figure all of this out!

What are Delegates?

Let’s start with the basics: Delegates.

From Microsoft’s C# Programming Guide we have the following definition:

A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.

Let’s brake this down:

  • delegate is a reserved word in C# to define a reference type, just like string or var
  • the things it references are methods. This sounds to me surprisingly similar to function pointers in C/C++
  • the delegate and the referenced method must have the same signature and return type

This is all well and good, but why would we use delegates in Unity?

Well, delegates allow you to build up functionality by dynamically assigning methods. Let’s try an example. In the scene we have the following GameObjects:

  • A primitive Sphere
  • A primitive Capsule
  • An empty GameObject called Manager

The Sphere has a script attached to change its color. The Capsule has a script attached to rotate it on the Z axis. The Manager is used to draw the UI button at the top of the screen and this is where the delegate will be defined.

The code looks like this:

ManagerScript:

[snippet id=369]

SphereScript:

[snippet id=365]

CapsuleScript:

[snippet id=368]

You need to be careful to check if the delegate actually contains a subscriber and to remove subscribers to prevent any memory leaks. The best place to do this is in the OnEnable() and OnDisable() functions.

What are Events?

Microsoft has this to say about events:

Events enable a class or object to notify other classes or objects when something of interest occurs. The class that sends (or raises) the event is called the publisher and the classes that receive (or handle) the event are called subscribers.

We can think of events as specialized delegates, which have inherent security measures that delegates do not:

  • With events, other classes can only subscribe and unsubscribe, preventing clients from resetting the delegate and invocation list
  • With delegates, other classes could invoke or overwrite delegate variables

Going back to our example scene, the changes in the code to use events would be the following:

ManagerScript:

[snippet id=373]

Notice that we only had to add the reserved word event and the rest of the files remain the same.

In short, it is preferred to use events over regular delegates and the changes to achieve that are minimal.

What are UnityEvents?

The definition from the Unity Manual says the following:

UnityEvents are a way of allowing user driven callback to be persisted from edit time to run time without the need for additional programming and script configuration.

Honestly, I have a hard time understanding that definition. The Manual also mentions:

UnityEvents can be added to any MonoBehaviour and are executed from code like a standard .net delegate. When a UnityEvent is added to a MonoBehaviour it appears in the Inspector and persistent callbacks can be added.

Let’s try doing exactly that, let’s add a UnityEvent to a Monobehaviour and see what happens in the Editor. Using the same scene as before, let’s create a new script called UnityEventsManager.cs and attach it to the Manager object we had previously created.

UnityEventsManagerScript:

[snippet id=377]

With this script, the Editor will show something like this:

UnityEvents Editor

Clicking the ‘+’ sign will allow you to select what objects and what functions will be added as listeners:

UnityEvents Editor Listener List

We can reduce the code present in the scripts attached to the Sphere and the Capsule primitives to only contain the functions we want to add as listeners:

SphereScript:

[snippet id=382]

CapsuleScript:

[snippet id=383]

Finally, select the objects and functions to be added in the Editor:

UnityEvents Editor List

A final note of warning when using UnityEvents:

UnityEvents have similar limitations to standard delegates. That is, they hold references to the element that is the target and this stops the target being garbage collected. If you have a UnityEngine.Object as the target and the native representation disappears the callback will not be invoked.

And that’s basically it. Of course, there is more to Delegates, Events and UnityEvents than what is presented here, but this should be a good starting point for someone who is not familiar with these concepts.

Until next time!

Leave a Reply

Your email address will not be published. Required fields are marked *