Delegates

A Delegate is a Variable which references a Method.

The most common type of delegate is System.Action which represents a method with no parameters and void as its return type. There are also generic System.Action<T> and System.Func<TResult> delegates which can take parameters and return values. Though if you need parameters you will often want to define your own delegate type so that you can properly name the parameters, for example:

public delegate int PerformCalculation(int x, int y);

Delegates can be used as a type of Variable just like any other, except that you assign methods to them and can call them like methods (calling a delegate is referred to as "invoking" it):

using System;// For System.Action.
using UnityEngine;// For UnityEngine.MonoBehaviour.

public class Health : MonoBehaviour
{
    public event Action onDeath;

    private int _CurrentHealth;

    public int CurrentHealth
    {
        get => _CurrentHealth;
        set
        {
            if (value < 0)
                value = 0;
        
            _CurrentHealth = value;

            if (value <= 0)
            {
                // If an onDeath delegate has been registered, invoke it.
                if (onDeath != null)
                    onDeath();
                else// Otherwise just destroy the GameObject this script is attached to.
                    Destroy(gameObject);
            }
        }
    }
}

public class Character : MonoBehaviour
{
    [SerializeField]
    private Health _Health;

    private void Awake()
    {
        // Register our Die method for the Health component to call.
        _Health.onDeath += Die;
    }

    private void Die()
    {
        // Play a death animation.
        // Turn the model into a ragdoll.
        // Create an explosion.
        // etc.
    }
}
  • The Animancer Events system uses delegates to allow users to specify their own methods that they want Animancer to call at specific times throughout an animation.
  • Delegates are Reference Types, meaning that they need to be Garbage Collected.
  • Multiple methods can be combined into a single delegate using the + and += operators (then removed with - and -=), which creates a Multicase Delegate.
  • The event keyword is a special Access Modifier which can be used on delegate fields to allow other classes to add and remove methods from it without allowing those classes to invoke it.

Inline Delegates

If you do not already have a method you want a delegate to point to, you can use an Anonymous Method or Lambda Expression to define the target method in the same place where you assign it:

// Using the Health class from the above example.

public class Character : MonoBehaviour
{
    [SerializeField]
    private Health _Health;

    private void Awake()
    {
        // Lambda expression:
        _Health.onDeath += () =>
        {
            Debug.Log("Character Died");
        };
        
        // One-line Lambda expression:
        _Health.onDeath += () => Debug.Log("Character Died");
        
        // Anonymous method:
        _Health.onDeath += delegate()
        {
            Debug.Log("Character Died");
        };
    }
}

Unity Events

Unity's Serialization System cannot serialize regular delegates or show them in the Inspector, which is where UnityEvents come in. They have several limitations on the types of methods they can call:

  • Access Modifier must be public.
  • Return Type must be void.
  • Must have either no Parameters or one parameter of any of the following types: bool, int, float, string, or anything derived from UnityEngine.Object (including any MonoBehaviour or ScriptableObject).

Any unsupported methods will simply not be listed in the menu.

One common use for UnityEvents is in Buttons and other UI components so that they can easily be set up to call methods in your scripts.

If you want your own scripts to have events which you can set up in the Inspector like that, you can use a UnityEvent like any other Serialized Field. However, you may be interested in my free UltEvents plugin which serves the same purpose but does not have the same restrictions (see UltEvents vs. UnityEvents for a comparison). Unfortunately, it is not possible to simply change Unity's UI Buttons to use UltEvents instead of UnityEvents, however it is possible to redirect events to an UltEventHolder.

Note that UnityEvents (and UltEvents) are less efficient than regular delegates so if you want to use events in your own scripts which you do not need to set up in the Inspector, then you should just use regular delegates.