Events are a powerful feature allowing a method to be notified when the event fires.  C# has an event system built into the language itself. Unity provides its own event mechanism called UnityEvents that, unlike C# events, is accessible from the Unity Editor.

A Unity Event called "OnToggleAction" that provides a Controller and Boolean when activated

This is a useful features when configuring prefabs in the Editor. But in my project I do a lot of setup at runtime as well. This can be accomplished by calling AddListener:

[SerializeField]
private ControllerInteractor controllerInteractor;

protected void Start() {
    if(controllerInteractor==null)
        controllerInteractor = GetComponent();
        
    //Inline delegate
    controllerInteractor.OnToggleAction.AddListener((controller, isHeld) => {
        //handle event here
    });
    
    //Or pass a method 
    controllerInteractor.OnToggleAction.AddListener(DoOnToggleAction);
}

protected void DoOnToggleAction(Controller controller, bool isHeld) {
    //handle event here
}

This works for adding event listeners at runtime, but the downside is adding event listeners in this way will not show up in the inspector. Also if you are trying to automate connecting event listeners in a MonoBehaviour Reset method the connection will not be serialized.

The solution is to use a UnityEditor method called AddPersistentListener.

[SerializeField]
private ControllerInteractor controllerInteractor;

///Called when component is added to a GameObject or when a developer 
///selects "Reset" from the component's context menu
protected void Reset() {
    if(controllerInteractor==null) {
        controllerInteractor = GetComponent();
#if UNITY_EDITOR
    UnityEditor.Events.UnityEventTools.AddPersistentListener(
                controllerInteractor.OnToggleAction, 
                DoOnToggleAction);
    }
#endif
}

protected void DoOnToggleAction(Controller controller, bool isHeld) {
    //handle event here
}

There are multiple benefits to implementing it this way:

  • GetComponent gets called once for the prefab, in the Unity Editor, instead of each time the object is instantiated at runtime
  • The listener method will be visible in the Inspector when debugging in the Unity Editor