我正在寻找Manager using UnityEvent的c#委托版本。我不想使用它,因为UnityEvent在大多数时间比C#事件要慢。使用委托而不是UnityEvent的Unity EventManager
关于如何实现这一点的任何线索?
我正在寻找Manager using UnityEvent的c#委托版本。我不想使用它,因为UnityEvent在大多数时间比C#事件要慢。使用委托而不是UnityEvent的Unity EventManager
关于如何实现这一点的任何线索?
您可以使用Action
这实际上是一种委托声明如下:
namespace System
{
public delegate void Action();
}
.Replace所有UnityAction
与Action
从使用委托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!");
}
}
你真棒! – ywj7931
UnityEvent做了什么额外的工作会导致它变慢?基本上,我们通过使用'Action'和一个自定义事件管理器交易来获得更快的速度? –
@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