Skip to content
This repository has been archived by the owner on Aug 7, 2021. It is now read-only.

RelativeEvents

Porrith Suong edited this page May 6, 2018 · 2 revisions

RelativeEventHandler

Global events are useful when invoking system wide events or an event which must be applied to every entity (e.g. healing every agent in the game).

But, if you want to invoke an event relative to a particular object, you can subscribe an object with its method signature and event name to the RelativeEventHandler.

.NET 3.5 Runtime

The .NET 3.5 runtime uses reflections to mimic what the GlobalEventHandler does. The table consists of an event name as the key series of smaller tables which includes object instances as keys and a series of subscribed methods.

Subscribed methods are represented as strings. See the table below for an example of how different instances which are subscribed to the same event can register different methods.

Event Name Object Instance Method(s)
Stop Alice "StopAI", "StopAnimator"
(Same Event) Bob "StopAI", "StopAnimator", "StopAudio"

When an event is invoked given an object instance, only the methods subscribed to that object will be invoked. For example, if the object Alice has the subscribed methods, StopAI, StopAnimator then only those methods will be invoked.

Likewise, if the event Stop was invoked on Bob, then StopAi, StopAnimator, and StopAudio will be invoked.

using GlobalEvents;
using UnityEngine;
using UnityEngine.AI;

// Alice example
public class Alice : MonoBehaviour {
    private Animator anim;
    private NavMeshAgent agent;

    private void OnEnable() {
        RelativeEventHandler.Subscribe("Stop", this, "StopAI");
        RelativeEventHandler.Subscribe("Stop", this, "StopAnimator");
    }

    private void OnDisable() {
        RelativeEventHandler.Subscribe("Stop", this, "StopAI");
        RelativeEventHandler.Subscribe("Stop", this, "StopAnimator");
    }

    private void Start() {
        anim = GetComponent<Animator>();
        agent = GetComponent<NavMeshAgent>();
    }

    private void StopAI() {
        agent.isStopped = true;
    }

    private void StopAnimator() {
        anim.SetBool("Stop", true);
    }
}

public class Bob: MonoBehaviour {
    private Animator anim;
    private NavMeshAgent agent;
    private AudioSource source;

    private void OnEnable() {
        RelativeEventHandler.Subscribe("Stop", this, "StopAI");
        RelativeEventHandler.Subscribe("Stop", this, "StopAnimator");
        RelativeEventHandler.Subscribe("Stop", this, "StopAudio"); 
    }

    private void OnDisable() {
        RelativeEventHandler.Unsubscribe("Stop", this, "StopAI");
        RelativeEventHandler.Unsubscribe("Stop", this, "StopAnimator");
        RelativeEventHandler.Unsubscribe("Stop", this, "StopAudio");
    }

    private void Start() {
        anim = GetComponent<Animator>();
        agent = GetComponent<NavMeshAgent>();
        audio = GetComponent<AudioSource>();
    }

    private void StopAI() {
        agent.isStopped = true;
    }

    private void StopAnimator() {
        anim.SetBool("Stop", true);
    }

    private void StopAudio() {
        source.mute = true;
    }
}

.NET 4x Runtime (WIP)

To avoid using Reflection, the RelativeEventHandler, is a table of objects with their respective events and delegates. This is only supported in a .NET 4x environment found in Unity 2018.1. It is essentially the same as the .NET 3.5 environment with the following differences:

  • Subscribe methods as Delegate/Action<T1..T4>
    • Alternatively, lambda expressions can be subscribed
  • Overloaded methods must be explicitly subscribed

For a simple example of subscribing relative events, see below.

using GlobalEvents;
using UnityEngine;
using UnityEngine.AI;

public class Alice : MonoBehaviour {

    private AudioSource source;
    private NavMeshAgent agent;

    private void OnEnable() {
        // Subscribe the object, the event name, and the method
        RelativeEventHandler.SubscribeEvent(this, "Stop", StopAI)
    }

    private void Start() {
        agent = GetComponent<NavMeshAgent>();
        source = GetComponent<AudioSource>();

        // Or we can replace the explicit method with a lambda expresssion
        RelativeEventHandler.SubscribeEvent(this, "Stop", () => { 
            source.mute = true;
        };)
    }

    // We'll subscribe the method below.
    private void StopAI() {
        agent.isStopped = true;
    }
}

// In another class
public class AlertSystem : MonoBehaviour {
    // Assuming we have the instance of Alice stored in a field
    public Alice alice;

    private void Start() {
        // We can invoke the relative methods bound to Alice with an event Stop
        RelativeEventHandler.InvokeEvent(alice, "Stop");
    }
}

See the scripting api (coming soon) for details on subscription. In the meantime, the branch feature/relative-event-4.5 can be viewed for specific details of the RelativeEventHandler.