EventManager (UnityEvent)
好处:一个UnityEvent可以便捷添加与删除多个函数
坏处:不正确地被外部调用,外部调用一次,相应的函数可能会触发两次
多次触发的原因与UnityAction有关,UnityEvent本身被外部调用的时候只会触发一次,但是因为UnityEvent本身由UnityAction组成,所以即使UnityEvent本身只被调用了一次,UnityEvent中的UnityAction被调用多次,相应的函数也会被调用多次
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class EventManager
{
private static EventManager _instance = null;
public static EventManager GetInstance
{
get
{
if (_instance == null)
_instance = new EventManager();
return _instance;
}
}
private Dictionary<string, UnityEvent> eventData = new Dictionary<string, UnityEvent>();
private Dictionary<string, UnityEvent<float[]>> eventSetData = new Dictionary<string, UnityEvent<float[]>>();
/// <summary>
/// 提供给外部使用的添加监听升级事件
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void AddListener(string eventName, UnityAction function)
{
if (!eventData.ContainsKey(eventName))
{
UnityEvent @event = new UnityEvent();
@event.AddListener(function);
eventData.Add(eventName, @event);
//Debug.Log("AddListener" + eventName);
}
if (eventData.ContainsKey(eventName) && !eventData[eventName].Equals(function))
{
eventData[eventName].AddListener(function);
//Debug.Log("AddListener" + eventName);
}
}
/// <summary>
/// 提供给外部使用的移除升级事件监听
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void RemoveListener(string eventName, UnityAction function)
{
if (eventData.ContainsKey(eventName) && eventData[eventName].Equals(function))
{
eventData[eventName].RemoveListener(function);
}
if (eventData[eventName] == null)
{
eventData.Remove(eventName);
}
}
/// <summary>
/// 提供给外部使用的添加监听改变数值的事件
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void AddSetListener(string eventName, UnityAction<int[]> function)
{
if (!eventSetData.ContainsKey(eventName))
{
UnityEvent<float[]> @event = new UnityEvent<float[]>();
@event.AddListener(function);
eventSetData.Add(eventName, @event);
//Debug.Log("AddSetListener" + eventName);
}
if (eventSetData.ContainsKey(eventName) && !eventSetData[eventName].Equals(function))
{
eventSetData[eventName].AddListener(function);
//Debug.Log("AddSetListener" + eventName);
}
}
/// <summary>
/// 提供给外部使用的移除升级事件监听
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void RemoveSetListener(string eventName, UnityAction<int[]> function)
{
if (eventSetData.ContainsKey(eventName) &&
eventSetData[eventName].Equals(function))
eventSetData[eventName].RemoveListener(function);
if (eventSetData[eventName] == null)
{
eventSetData.Remove(eventName);
}
}
/// <summary>
/// 触发事件
/// </summary>
/// <param name="eventName">监听的事件名字</param>
public void TriggerEvent(string eventName)
{
if (eventData[eventName] != null)
eventData[eventName].Invoke();
}
/// <summary>
/// 触发事件
/// </summary>
/// <param name="eventName">监听的事件名字</param>
public void TriggerSetEvent(string eventName, int[] model)
{
if (eventSetData[eventName] != null)
eventSetData[eventName].Invoke(model);
}
public void ClearEvent(string name)
{
if (eventData.ContainsKey(name))
{
eventData.Remove(name);
}
if (eventSetData.ContainsKey(name))
{
eventSetData.Remove(name);
}
}
public void ClearAllEvents()
{
if (eventData.Count != 0)
{
eventData.Clear();
}
if (eventSetData.Count != 0)
{
eventSetData.Clear();
}
}
}
EventManager (Delegate)
好处:能够正确地被外部调用,外部调用一次,相应的函数只会触发一次
坏处:如果Remove函数使用的是只删除该key值中一个事件的版本,很难在脚本生命周期的更替中妥善管理非静态方法(如果Remove函数使用的是删除该key值中所有函数的版本,则可以在脚本生命周期中较好的控制所有的事件 前提是一个事件对应一个key)
(不过如果能够了解每个添加进来的监听事件,在监听事件所在脚本生命周期结束前Remove并且保证不需要这个事件有跨生命周期的部分的话,还是可以使用的)
*当然,使用UnityEvent实现的Remove方法(只删除一个key下的某一个监听事件)也会有无法准确通过key值进行管理的问题
*因为TriggerEvent与ClearEvent的方式与UnityEvent相同,就不在此赘述了
delegate void DeleFunc();
delegate void DeleFuncFloat(float[] f);
private Dictionary<string, DeleFunc> eventData = new Dictionary<string, DeleFunc>();
private Dictionary<string, DeleFuncFloat> eventSetData = new Dictionary<string, DeleFuncFloat>();
/// <summary>
/// 提供给外部使用的添加监听事件
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void AddSetListener(string eventName, UnityAction<float[]> function)
{
DeleFuncFloat deleFunc = new DeleFuncFloat(function);
if (!eventSetData.ContainsKey(eventName))
{
eventSetData.Add(eventName, deleFunc);
//Debug.Log("AddSetListener" + eventName);
}
if (eventSetData.ContainsKey(eventName) && !eventSetData[eventName].Equals(deleFunc))
{
eventSetData[eventName] += deleFunc;
//Debug.Log("AddSetListener" + eventName);
}
}
/// <summary>
/// 提供给外部使用的移除事件监听
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void RemoveSetListener(string eventName, UnityAction<float[]> function)
{
if (!eventSetData.ContainsKey(eventName)) return;
#region 移除该key值下某个具体的监听事件,在脚本生命周期的改变中可能会出错(无法定位某一脚本的某一事件)
//foreach(DeleFuncFloat deleFuncFloat in eventSetData[eventName].GetInvocationList())
//{
// if (deleFuncFloat.Equals(function))
// {
// eventSetData[eventName] -= deleFuncFloat;
// if (eventSetData[eventName] == null)
// {
// eventSetData.Remove(eventName);
// Debug.Log("RemoveAll" + eventName);
// }
// }
//}
#endregion
#region 移除改key值下的所有事件,可通过key值准确的跨生命周期管理各个事件,推荐
//Debug.Log("Remove" + eventName);
{
eventSetData.Remove(eventName);
Debug.Log("RemoveAll" + eventName);
}
#endregion
}
/// <summary>
/// 提供给外部使用的添加监听事件
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void AddListener(string eventName, UnityAction function)
{
DeleFunc deleFunc = new DeleFunc(function);
if (!eventData.ContainsKey(eventName))
{
eventData.Add(eventName, deleFunc);
//Debug.Log("AddListener" + eventName);
}
if (eventData.ContainsKey(eventName) && !eventData[eventName].Equals(deleFunc))
{
eventData[eventName] += deleFunc;
//Debug.Log("AddListener" + eventName);
}
}
/// <summary>
/// 提供给外部使用的移除事件监听
/// </summary>
/// <param name="eventName">监听的事件名字</param>
/// <param name="function">监听的函数</param>
public void RemoveListener(string eventName, UnityAction function)
{
if (!eventData.ContainsKey(eventName)) return;
#region 移除该key值下某个具体事件,在脚本生命周期的改变中可能会出错(无法定位某一脚本的某一事件)
//foreach(DeleFunc deleFunc in eventData[eventName].GetInvocationList())
//{
// if (deleFunc.Equals(function))
// {
// eventData[eventName] -= deleFunc;
// if (eventData[eventName] == null)
// {
// eventData.Remove(eventName);
// Debug.Log("RemoveAll" + eventName);
// }
// }
//}
#endregion
#region 移除改key值下的所有事件,可通过key值准确的跨生命周期管理各个事件,推荐
//Debug.Log("Remove" + eventName);
{
eventData.Remove(eventName);
Debug.Log("RemoveAll" + eventName);
}
#endregion
}
相关文档
本文的MVE方法参考了这篇文章,不了解MVE的朋友可以看看这篇了解一下。