2017-02-03 39 views

回答

9

您可以使用Action这实际上是一种委托声明如下:

namespace System 
{ 
    public delegate void Action(); 
} 

.Replace所有UnityActionAction从使用委托System命名空间。

.Replace所有thisEvent.AddListener(listener);thisEvent += listener;

.Replace所有thisEvent.RemoveListener(listener);thisEvent -= listener;

这里是统一的originalEventManager移植到使用委托/动作的修改版本。

不带参数:

using System; 
using System.Collections; 
using System.Collections.Generic; 
using UnityEngine; 

public class EventManager : MonoBehaviour 
{ 

    private Dictionary<string, Action> 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>(); 
     } 
    } 

    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](); 
     } 
    } 
} 

测试脚本:

测试脚本以下测试通过触发事件每2秒的事件。

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!"); 
    } 
} 

随着参数:

从其他疑问,大多数人都在问如何支持参数。这里是。您可以使用class/struct作为参数,然后将所有要传递到该类/结构中的函数的变量添加到该函数中。我将以EventParam为例。在此代码结尾的事件EventParam结构中,可以随意添加/删除想要传递的变量。

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; 
} 

测试脚本:

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!"); 
    } 
} 
+2

你真棒! – ywj7931

+0

UnityEvent做了什么额外的工作会导致它变慢?基本上,我们通过使用'Action'和一个自定义事件管理器交易来获得更快的速度? –

+0

@ScottChamberlain内存分配+太多的反射使用。它的唯一优点是你可以在编辑器中公开它,并且从编辑器中将它分配给它,因为它是序列化的。它在其他所有方面都失败了,不应该用于真正的游戏。你可以自己测试它,或者你可以检查[this](https://www.reddit.com/r/Unity3D/comments/35sa5h/unityevent_vs_delegate_event_benchmark_for_those/#bottom-comments)和[this](http://jacksondunstan.com /用品/ 3335)。 – Programmer