There is a Unity EventManager
class from Unity tutorial that allows events to be registered, unregistered and invoked. The bad side of that EventManager
code is that it uses UnityEvent
which is slow and it does not take parameter.
I decided to rewrite it with Action
from C# instead of Unity's UnityEvent
and also added support for parameter. Below is the new EventManager
I modified that uses Action
and it also allows any amount of parameter to be passed to the event.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EventManager : MonoBehaviour
{
private Dictionary<string, Action<EventParam>> eventDictionary;
private static EventManager eventManager;
public static EventManager instance
{
get
{
if (!eventManager)
{
eventManager = FindObjectOfType(typeof(EventManager)) as EventManager;
if (!eventManager)
{
Debug.LogError("There needs to be one active EventManger script on a GameObject in your scene.");
}
else
{
eventManager.Init();
}
}
return eventManager;
}
}
void Init()
{
if (eventDictionary == null)
{
eventDictionary = new Dictionary<string, Action<EventParam>>();
}
}
public static void StartListening(string eventName, Action<EventParam> listener)
{
Action<EventParam> thisEvent;
if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
{
//Add more event to the existing one
thisEvent += listener;
//Update the Dictionary
instance.eventDictionary[eventName] = thisEvent;
}
else
{
//Add event to the Dictionary for the first time
thisEvent += listener;
instance.eventDictionary.Add(eventName, thisEvent);
}
}
public static void StopListening(string eventName, Action<EventParam> listener)
{
if (eventManager == null) return;
Action<EventParam> thisEvent;
if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
{
//Remove event from the existing one
thisEvent -= listener;
//Update the Dictionary
instance.eventDictionary[eventName] = thisEvent;
}
}
public static void TriggerEvent(string eventName, EventParam eventParam)
{
Action<EventParam> thisEvent = null;
if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
{
thisEvent.Invoke(eventParam);
// OR USE instance.eventDictionary[eventName](eventParam);
}
}
}
//Re-usable structure/ Can be a class to. Add all parameters you need inside it
public struct EventParam
{
public string param1;
public int param2;
public float param3;
public bool param4;
}
USAGE:
public class Test : MonoBehaviour
{
private Action<EventParam> someListener1;
private Action<EventParam> someListener2;
private Action<EventParam> someListener3;
void Awake()
{
someListener1 = new Action<EventParam>(SomeFunction);
someListener2 = new Action<EventParam>(SomeOtherFunction);
someListener3 = new Action<EventParam>(SomeThirdFunction);
StartCoroutine(invokeTest());
}
IEnumerator invokeTest()
{
WaitForSeconds waitTime = new WaitForSeconds(0.5f);
//Create parameter to pass to the event
EventParam eventParam = new EventParam();
eventParam.param1 = "Hello";
eventParam.param2 = 99;
eventParam.param3 = 43.4f;
eventParam.param4 = true;
while (true)
{
yield return waitTime;
EventManager.TriggerEvent("test", eventParam);
yield return waitTime;
EventManager.TriggerEvent("Spawn", eventParam);
yield return waitTime;
EventManager.TriggerEvent("Destroy", eventParam);
}
}
void OnEnable()
{
//Register With Action variable
EventManager.StartListening("test", someListener1);
EventManager.StartListening("Spawn", someListener2);
EventManager.StartListening("Destroy", someListener3);
//OR Register Directly to function
EventManager.StartListening("test", SomeFunction);
EventManager.StartListening("Spawn", SomeOtherFunction);
EventManager.StartListening("Destroy", SomeThirdFunction);
}
void OnDisable()
{
//Un-Register With Action variable
EventManager.StopListening("test", someListener1);
EventManager.StopListening("Spawn", someListener2);
EventManager.StopListening("Destroy", someListener3);
//OR Un-Register Directly to function
EventManager.StopListening("test", SomeFunction);
EventManager.StopListening("Spawn", SomeOtherFunction);
EventManager.StopListening("Destroy", SomeThirdFunction);
}
void SomeFunction(EventParam eventParam)
{
Debug.Log("Some Function was called!");
}
void SomeOtherFunction(EventParam eventParam)
{
Debug.Log("Some Other Function was called!");
}
void SomeThirdFunction(EventParam eventParam)
{
Debug.Log("Some Third Function was called!");
}
}
It's working fine.I know I can use the params
keyword to receive multiple arguments but I am trying to avoid using the params
keyword as it also creates garbage during run-time so I used a struct
called "EventParam
" to hold and pass all my parameters.
I want to know if there is anything to improve in this script and if there is any other better way to handle parameter other than the current way I am currently doing it.
UnityEvent
and usingAction
. I don't useUnityEvent
\$\endgroup\$