Unity

Events in Unity: event delegates and Unity events

What is an Event?

An Event can be defined as a function pointer. It notifies its subscriber of an incident. It means that it stores the pointer to a method which will be invoked when the “event” happens. As you can see from the definition, pointers are at the heart of the event system. So, the question is how is it type safe. After all, pointers are not considered a type safe way of calling a method.

The answer is Events in C# use delegates to point to a method. The type safety is guaranteed by the use of delegates. A delegate only allows storing a pointer to a method if the target method satisfies the method signature of the delegate. This will guarantee that the event will not call illegal methods when invoked. Events in .NET are based on the Publisher-Subscriber model.

C# event delegates (cite from the .net library)

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. Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates. You create a custom method, and a class such as a windows control can call your method when a certain event occurs. (source)

Unity events (cite from the Unity manual)

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. UnityEvents are useful for a number of things: Content driven callbacks, decoupling systems, persistent callbacks, preconfigured call events. 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. 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. (source)

First impression

It seems Unity events are some kind of hidden, not obvious feature added when they implemented the new UI system (in 4.6? need source on this…). At first glance it seems Unity events are easier to implement and has nice added features, you can for example see the subscribers which you can’t with delegates.

Performance

Performance wise delegate events are way faster than Unity events. Using a little program I invoked 10000000 events both using delegates and Unity events, the results are shown below. Does this matter? That will depend on the application itself I guess.
ScreenHunter_288 Apr. 28 15.55

C# event Implementation

The basic steps to creating an event is:
1. [publisher script] create a delegate.
2. [publisher script] create an event based on the delegate.
3. [publisher script] create an event publisher method.
4. [listener script] create an event listener method.
5. [listener script] add the listener method to the event.
6. [publisher script] raise the event and pray =p

1. An example delegate would be:
public delegate void ButtonPressEventHandler(object source, EventArgs e);
You can create your own event arguments which inherit from EventArgs but that is optional.

2. You then create an event based on the just created delegate:
public event ButtonPressEventHandler ButtonPressed;

3. Then you create a event publisher method. The C# convention is that the method has to be protected and virtual, and the name has to be “On” + the event name. In this case our method would become: protected virtual void OnButtonPressed() { ButtonPressed(); }

4. An event listener (or subscriber) will have the same naming as the publisher. In our case that would be: public void OnButtonPressed(object source, EventArgs e) { //do something } 

5. We then “subscribe” by adding the method itself to the event: ButtonPressed += OnButtonPressed; Now when an button press event is raised this method (OnButtonPressed) will be notified.

6. Raising an event can be done by calling the event publisher OnButtonPressed()

using UnityEngine;
using System;
 
public class Publisher : Singleton<Publisher>
{
    //-- delegate --//
    public delegate void ButtonPressEventHandler(object source, EventArgs e);
    //-- event based on delegate --//
    public event ButtonPressEventHandler ButtonPressed;
 
    void Start()
    {
        //-- raise the event --//
        Debug.Log("Broadcasting button press event...");
        OnButtonPressed();
    }
 
    //-- event publisher (broadcaster) --//
    protected virtual void OnButtonPressed()
    {
 
        ButtonPressed(this, EventArgs.Empty);
    }
}
using UnityEngine;
using System;
 
public class Subscriber : MonoBehaviour
{
    void Start()
    {
        //-- subscribe to event --//
        Publisher.Instance.ButtonPressed += OnButtonPressed;
    }
 
    //-- event listener method --//
    public void OnButtonPressed(object source, EventArgs e)
    {
        Debug.Log("Button press event registered!");
    }
}

Leave a Reply

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