Unity EventManager with delegate instead of UnityEvent

后端 未结 3 1963
小鲜肉
小鲜肉 2020-11-29 11:08

I am looking for c# delegate version of this Manager using UnityEvent. I don\'t want to use this because UnityEvent is slower than C# event at most time.

Any clue on

3条回答
  •  囚心锁ツ
    2020-11-29 11:25

    You can use Action which is actually a delegate declared like this:

    namespace System
    {
        public delegate void Action();
    }
    

    1.Replace all the UnityAction with Action from the System namespace which uses delegates.

    2.Replace all thisEvent.AddListener(listener); with thisEvent += listener;

    3.Replace all thisEvent.RemoveListener(listener); with thisEvent -= listener;

    Here is the modified version of Unity's original EventManager ported to use delegate/Action.

    Without Parameter:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class EventManager : MonoBehaviour
    {
    
        private Dictionary 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();
            }
        }
    
        public static void StartListening(string eventName, Action listener)
        {
            Action 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 listener)
        {
            if (eventManager == null) return;
            Action 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)
        {
            Action thisEvent = null;
            if (instance.eventDictionary.TryGetValue(eventName, out thisEvent))
            {
                thisEvent.Invoke();
                // OR USE instance.eventDictionary[eventName]();
            }
        }
    }
    

    Test script:

    The test script below test the event by triggering events every 2 seconds.

    public class TestScript: MonoBehaviour
    {
        private Action someListener;
    
        void Awake()
        {
            someListener = new Action(SomeFunction);
            StartCoroutine(invokeTest());
        }
    
        IEnumerator invokeTest()
        {
            WaitForSeconds waitTime = new WaitForSeconds(2);
            while (true)
            {
                yield return waitTime;
                EventManager.TriggerEvent("test");
                yield return waitTime;
                EventManager.TriggerEvent("Spawn");
                yield return waitTime;
                EventManager.TriggerEvent("Destroy");
            }
        }
    
        void OnEnable()
        {
            EventManager.StartListening("test", someListener);
            EventManager.StartListening("Spawn", SomeOtherFunction);
            EventManager.StartListening("Destroy", SomeThirdFunction);
        }
    
        void OnDisable()
        {
            EventManager.StopListening("test", someListener);
            EventManager.StopListening("Spawn", SomeOtherFunction);
            EventManager.StopListening("Destroy", SomeThirdFunction);
        }
    
        void SomeFunction()
        {
            Debug.Log("Some Function was called!");
        }
    
        void SomeOtherFunction()
        {
            Debug.Log("Some Other Function was called!");
        }
    
        void SomeThirdFunction()
        {
            Debug.Log("Some Third Function was called!");
        }
    }
    

    With Parameter:

    From other questions, most people are asking how to support parameter. Here it is. You can use class/struct as parameter then add all the variables you want to pass into the function inside this class/struct. I will use EventParam as an example. Feel free to add/remove variables you want to pass in the event EventParam structure at the end of this code.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class EventManager : MonoBehaviour
    {
    
        private Dictionary> 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>();
            }
        }
    
        public static void StartListening(string eventName, Action listener)
        {
            Action 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 listener)
        {
            if (eventManager == null) return;
            Action 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 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;
    }
    

    Test script:

    public class Test : MonoBehaviour
    {
        private Action someListener1;
        private Action someListener2;
        private Action someListener3;
    
        void Awake()
        {
            someListener1 = new Action(SomeFunction);
            someListener2 = new Action(SomeOtherFunction);
            someListener3 = new Action(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!");
        }
    }
    

提交回复
热议问题