对很早以前学习的到的内容做备忘。
利用delegate(C++的函数指针)的特性,可以实现游戏内的事件机制,即注册事件,注销事件,一个脚本注册事件后,在发生事件时,注册的脚本函数可以作相应处理,以及回调。
首先,一个Manager类,用于保存所有注册了对应事件的函数,并且将其挂在一个全局的GameObject上。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EventManager : MonoBehaviour {
/// <summary>
/// 该集合以一个k/v的形式保存事件集合
/// k为事件ID,v是对应事件的处理函数,注意,v可以是一个委托集合
/// </summary>
static private Dictionary<EventTypeDefine, Delegate> eventLst = new Dictionary<EventTypeDefine, Delegate>();
delegate void VoidlVoidDelegate();
delegate void VoidStringDelegate(string s);
/// <summary>
/// 注册一个事件对应的处理函数
/// </summary>
/// <param name="eventID"></param>
/// <param name="eventHandler"></param>
public static void RegisterEvent(EventTypeDefine eventID,Action eventHandler)
{
if (!OnRegisterEvent(eventID, eventHandler))
return;
//eventLst[eventID] += eventHandler;
//无返回类型的delegate可以作为Action,实际上在.net中,action就是对无返回值的delegate的封装
//因此在下面的代码中,保存delegate的lst也可以保存action
eventLst[eventID] = (Action)eventLst[eventID] + eventHandler;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="eventID"></param>
/// <param name="eventHandler"></param>
public static void RegisterEvent<T>(EventTypeDefine eventID, Action<T> eventHandler)
{
if (!OnRegisterEvent(eventID, eventHandler))
return;
eventLst[eventID] = (Action<T>)eventLst[eventID] + eventHandler;
}
public static void UnRegisterEvent(EventTypeDefine eventID, Action eventHandler)
{
if (!eventLst.ContainsKey(eventID))
return;
eventLst[eventID] = (Action)eventLst[eventID] - eventHandler;
}
public static void UnRegisterEvent<T>(EventTypeDefine eventID, Action<T> eventHandler)
{
if (!eventLst.ContainsKey(eventID))
return;
eventLst[eventID] = (Action<T>)eventLst[eventID] - eventHandler;
}
/// <summary>
/// 检查
/// </summary>
/// <param name="eventID"></param>
/// <param name="eventHandler"></param>
/// <returns></returns>
static bool OnRegisterEvent(EventTypeDefine eventID, Delegate eventHandler)
{
if (!eventLst.ContainsKey(eventID))//如果没有对应的事件ID,先把事件添加进去
eventLst.Add(eventID, null);
Delegate d = eventLst[eventID];
if (d != null && d.GetType() == eventHandler.GetType())//如果对应的时间已经有相应的处理函数,且两个handler相等,则代表该事件已经注册了这个处理函数,不用重复添加
return false;
return true;
}
public static void TriggerEvent(EventTypeDefine eventID)
{
Delegate d = null;
if (!eventLst.TryGetValue(eventID, out d))
return;
if (d == null)
return;
Delegate[] callBacks = d.GetInvocationList();
for (int i = 0; i < callBacks.Length; i++)
{
Action callBack = callBacks[i] as Action;
if (callBack == null)
continue;
callBack();
}
}
public static void TriggerEvent<T>(EventTypeDefine eventID,T arg1)
{
Delegate d = null;
if (!eventLst.TryGetValue(eventID, out d))
return;
if (d == null)
return;
Delegate[] callBacks = d.GetInvocationList();
for (int i = 0; i < callBacks.Length; i++)
{
Action<T> callBack = callBacks[i] as Action<T>;
if (callBack == null)
continue;
callBack(arg1);
}
}
}
对于要注册并且处理捕获/处理该事件的脚本,可以这样做:
这里把他放到一个button上做例子
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EventLogic : MonoBehaviour {
void OnEnable()
{
EventManager.RegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);//要处理的事件,对应的处理函数
EventManager.RegisterEvent(EventTypeDefine.LoginButton2Click, OnLoginButtonClick);
EventManager.RegisterEvent<string>(EventTypeDefine.LoginButton2Click, OnLoginButtonClick_2);
}
void OnDisable()
{
EventManager.UnRegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);
EventManager.UnRegisterEvent<string>(EventTypeDefine.LoginButton2Click, OnLoginButtonClick_2);
}
public void LoginClick()
{
//UGUI的点击处理,点击button后触发该事件,NGUI略有不同但大致一样
EventManager.TriggerEvent(EventTypeDefine.LoginButtonClick);
//EventManager.UnRegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);
}
public void LoginClick_2()
{
EventManager.TriggerEvent(EventTypeDefine.LoginButton2Click, "带参数的事件触发");
//EventManager.UnRegisterEvent(EventTypeDefine.LoginButtonClick, OnLoginButtonClick);
}
private void OnLoginButtonClick()
{
Debug.Log("click");
}
private void OnLoginButtonClick_2(string s)
{
Debug.Log("click,arg:" + s);
}
}
附上表示事件类型的枚举:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum EventTypeDefine
{
LoginButtonClick,
LoginButton2Click,
}