UIFramework之事件系統實現
在Unity開發中,自定義消息系統經常會被用到,事件系統的實現主要是基於C#委託來完成的。下面介紹的兩種實現,一種是利用C#自帶的Action委託來實現;第二種是通過自定義一個信息類來作爲傳遞信息的載體,再通過自定義委託來實現的。
實現一:
首先在MessageSystem.cs中實現事件系統的基本功能:
/*
* Name: MessageSystem.cs
* Function: N/A
*
* Ver 變更日期 負責人 變更內容
* ──────────────────────────────────────────────────────────────────────
* V1.0.0 $time$ http://blog.csdn.net/husheng0
*
* Copyright (c). All rights reserved.
*/
using System;
using System.Collections.Generic;
using UnityEngine;
public static class MessageSystem<TKey> where TKey : struct
{
//MessageKey對應的註冊的委託
private static Dictionary<TKey, List<Delegate>> RegisterMessageDic
= new Dictionary<TKey, List<Delegate>>();
//移出對應的委託
public static void UnRegisterDelegate(TKey MessageKey)
{
RegisterMessageDic.Remove(MessageKey);
}
//清空事件系統已註冊事件
public static void CleanEvents()
{
RegisterMessageDic.Clear();
}
//能不能註冊該委託
private static bool IsCanRegister(TKey MessageKey, Delegate registerDelegate)
{
List<Delegate> registerDelegateList = null;
if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))
{
if (null == registerDelegateList || registerDelegateList.Count == 0)
return true;
foreach (Delegate dele in registerDelegateList)
{
if (dele == registerDelegate) return false;
}
}
else
{
RegisterMessageDic[MessageKey] = new List<Delegate>();
}
return true;
}
#region Action委託
/// <summary>
/// 註冊無參Action委託
/// </summary>
/// <param name="MessageKey"></param>
/// <param name="handler"></param>
public static void AddListener(TKey MessageKey, Action handler)
{
if (IsCanRegister(MessageKey, handler))
{
RegisterMessageDic[MessageKey].Add(handler);
Debug.Log("Register" + MessageKey.ToString() + "success");
}
else
{
Debug.LogError("Register" + MessageKey.ToString() + "failure");
}
}
/// <summary>
/// 移除無參Action委託
/// </summary>
/// <param name="MessageKey"></param>
/// <param name="handler"></param>
public static void RemoveListenerer(TKey MessageKey, Action handler)
{
if (!IsCanRegister(MessageKey, handler))
{
RegisterMessageDic[MessageKey].Remove(handler);
Debug.Log("Remove" + MessageKey.ToString() + "success");
}
else
{
Debug.LogError("Remove" + MessageKey.ToString() + "failure");
}
}
/// <summary>
/// 廣播無參Action委託
/// </summary>
/// <param name="MessageKey"></param>
public static void Broadcast(TKey MessageKey)
{
List<Delegate> registerDelegateList;
if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))
{
Action callback;
for (int i = 0; i < registerDelegateList.Count; ++i)
{
try
{
callback = (registerDelegateList[i]) as Action;
if (callback != null)
{
callback();
}
}
catch (Exception exp)
{
Debug.LogException(exp);
}
}
}
}
#endregion
#region Action<T>委託
/// <summary>
/// 註冊含一個參數的委託
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="MessageKey"></param>
/// <param name="handler"></param>
public static void AddListener<T>(TKey MessageKey, Action<T> handler)
{
if (IsCanRegister(MessageKey, handler))
{
RegisterMessageDic[MessageKey].Add(handler);
Debug.Log("Register" + MessageKey.ToString() + "success");
}
else
{
Debug.LogError("Register" + MessageKey.ToString() + "failure");
}
}
/// <summary>
/// 移除含一個參數的Action委託
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="MessageKey"></param>
/// <param name="handler"></param>
public static void RemoveListenerer<T>(TKey MessageKey, Action<T> handler)
{
if (!IsCanRegister(MessageKey, handler))
{
RegisterMessageDic[MessageKey].Remove(handler);
Debug.Log("Remove" + MessageKey.ToString() + "success");
}
else
{
Debug.LogError("Remove" + MessageKey.ToString() + "failure");
}
}
/// <summary>
/// 廣播含一個參數的Action委託
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="MessageKey"></param>
/// <param name="arg1"></param>
public static void Broadcast<T>(TKey MessageKey, T arg1)
{
List<Delegate> registerDelegateList;
if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))
{
Action<T> callback;
for (int i = 0; i < registerDelegateList.Count; ++i)
{
try
{
callback = (registerDelegateList[i]) as Action<T>;
if (callback != null)
{
callback(arg1);
}
}
catch (Exception exp)
{
Debug.LogException(exp);
}
}
}
}
#endregion
#region Action<T1,T2>委託
/// <summary>
/// 註冊含兩個參數的Action委託
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="MessageKey"></param>
/// <param name="handler"></param>
public static void AddListener<T1, T2>(TKey MessageKey, Action<T1, T2> handler)
{
if (IsCanRegister(MessageKey, handler))
{
RegisterMessageDic[MessageKey].Add(handler);
Debug.Log("Register" + MessageKey.ToString() + "success");
}
else
{
Debug.LogError("Register" + MessageKey.ToString() + "failure");
}
}
/// <summary>
/// 移除含兩個參數的Action委託
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="MessageKey"></param>
/// <param name="handler"></param>
public static void RemoveListenerer<T1, T2>(TKey MessageKey, Action<T1, T2> handler)
{
if (!IsCanRegister(MessageKey, handler))
{
RegisterMessageDic[MessageKey].Remove(handler);
Debug.Log("Remove" + MessageKey.ToString() + "success");
}
else
{
Debug.LogError("Remove" + MessageKey.ToString() + "failure");
}
}
/// <summary>
/// 廣播含兩個參數的Action委託
/// </summary>
/// <typeparam name="T1"></typeparam>
/// <typeparam name="T2"></typeparam>
/// <param name="MessageKey"></param>
/// <param name="arg1"></param>
/// <param name="arg2"></param>
public static void Broadcast<T1, T2>(TKey MessageKey, T1 arg1, T2 arg2)
{
List<Delegate> registerDelegateList;
if (RegisterMessageDic.TryGetValue(MessageKey, out registerDelegateList))
{
Action<T1, T2> callback;
for (int i = 0; i < registerDelegateList.Count; ++i)
{
try
{
callback = (registerDelegateList[i]) as Action<T1, T2>;
if (callback != null)
{
callback(arg1, arg2);
}
}
catch (Exception exp)
{
Debug.LogException(exp);
}
}
}
}
#endregion
}
下面使用兩個腳本進行簡單的測試:
/// <summary>
/// 全局事件
/// </summary>
public enum MsgTest
{
Test1,
Test2,
Test3
}
using UnityEngine;
using System.Collections;
public class MessageSystemTest : MonoBehaviour
{
void OnGUI()
{
if (GUI.Button(new Rect(50, 50, 200, 30), "Register Action"))
MessageSystem<MsgTest>.AddListener(MsgTest.Test1, Test1Func);
if (GUI.Button(new Rect(50, 100, 200, 30), "Broadcast Action"))
MessageSystem<MsgTest>.Broadcast(MsgTest.Test1);
if (GUI.Button(new Rect(50, 150, 200, 30), "Remove Action"))
MessageSystem<MsgTest>.RemoveListenerer(MsgTest.Test1, Test1Func);
if (GUI.Button(new Rect(50, 200, 200, 30), "Register Action<T>"))
MessageSystem<MsgTest>.AddListener<int>(MsgTest.Test2, Test2Func);
if (GUI.Button(new Rect(50, 250, 200, 30), "Broadcast Action<T>"))
MessageSystem<MsgTest>.Broadcast<int>(MsgTest.Test2,100);
if (GUI.Button(new Rect(50, 300, 200, 30), "Remove Action<T>"))
MessageSystem<MsgTest>.RemoveListenerer<int>(MsgTest.Test2, Test2Func);
if (GUI.Button(new Rect(50, 350, 200, 30), "Register Action<T1,T2>"))
MessageSystem<MsgTest>.AddListener<int,string>(MsgTest.Test3, Test3Func);
if (GUI.Button(new Rect(50, 400, 200, 30), "Broadcast Action<T1,T2>"))
MessageSystem<MsgTest>.Broadcast<int,string>(MsgTest.Test3,100,"test");
if (GUI.Button(new Rect(50, 450, 200, 30), "Remove Action<T1,T2>"))
MessageSystem<MsgTest>.RemoveListenerer<int,string>(MsgTest.Test3, Test3Func);
}
private void Test1Func()
{
Debug.LogError("--->Test1Func");
}
private void Test2Func(int i)
{
Debug.LogError("--->Test1Func"+i.ToString());
}
private void Test3Func(int i,string str)
{
Debug.LogError("--->Test1Func" + i.ToString()+" "+str);
}
}
測試結果如下圖所示:
實現二:
第二種是實現方式與第一種實現方式其實是大同小異:
using System;
using System.Collections.Generic;
using UnityEngine;
public static class MessageCenter
{
public delegate void MessageEvent(Message message);
private static Dictionary<string, List<MessageEvent>> MessageEventsDic =
new Dictionary<string, List<MessageEvent>>();
#region Add & Remove Listener
public static void AddListener(string messageName, MessageEvent messageEvent)
{
Debug.Log("AddListener Name : " + messageName);
List<MessageEvent> list = null;
if (MessageEventsDic.ContainsKey(messageName))
{
list = MessageEventsDic[messageName];
}
else
{
list = new List<MessageEvent>();
MessageEventsDic.Add(messageName, list);
}
if (!list.Contains(messageEvent))
{
list.Add(messageEvent);
}
}
public static void RemoveListener(string messageName, MessageEvent messageEvent)
{
Debug.Log("RemoveListener Name : " + messageName);
if (MessageEventsDic.ContainsKey(messageName))
{
List<MessageEvent> list = MessageEventsDic[messageName];
if (list.Contains(messageEvent))
{
list.Remove(messageEvent);
}
if (list.Count <= 0)
{
MessageEventsDic.Remove(messageName);
}
}
}
public static void RemoveAllListener()
{
MessageEventsDic.Clear();
}
#endregion
#region Send Message
public static void SendMessage(Message message)
{
DoMessageDispatcher(message);
}
public static void SendMessage(string name, object sender)
{
SendMessage(new Message(name, sender));
}
public static void SendMessage(string name, object sender, object content)
{
SendMessage(new Message(name, sender, content));
}
public static void SendMessage(string name, object sender, object content, params object[] dicParams)
{
SendMessage(new Message(name, sender, content, dicParams));
}
private static void DoMessageDispatcher(Message message)
{
Debug.Log("DoMessageDispatcher Name : " + message.Name);
if (MessageEventsDic == null || !MessageEventsDic.ContainsKey(message.Name))
return;
List<MessageEvent> list = MessageEventsDic[message.Name];
for (int i = 0; i < list.Count; i++)
{
MessageEvent messageEvent = list[i];
if (null != messageEvent)
{
messageEvent(message);
}
}
}
#endregion
}
using System;
using System.Collections;
using System.Collections.Generic;
public class Message : IEnumerable<KeyValuePair<string, object>>
{
private Dictionary<string, object> DatasDic = null;
public string Name { get; private set; }
public object Sender { get; private set; }
public object Content { get; set; }
/// <summary>
/// 索引器
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object this[string key]
{
get
{
if (null == DatasDic || !DatasDic.ContainsKey(key))
return null;
return DatasDic[key];
}
set
{
if (null == DatasDic)
DatasDic = new Dictionary<string, object>();
if (DatasDic.ContainsKey(key))
DatasDic[key] = value;
else
DatasDic.Add(key, value);
}
}
#region IEnumerable implementation
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
if (null == DatasDic)
yield break;
foreach (KeyValuePair<string, object> kvp in DatasDic)
{
yield return kvp;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return DatasDic.GetEnumerator();
}
#endregion
#region Message Construction Function
public Message(string name, object sender)
{
Name = name;
Sender = sender;
Content = null;
}
public Message(string name, object sender, object content)
{
Name = name;
Sender = sender;
Content = content;
}
public Message(string name, object sender, object content, params object[] _dicParams)
{
Name = name;
Sender = sender;
Content = content;
if (_dicParams.GetType() == typeof(Dictionary<string, object>))
{
foreach (object _dicParam in _dicParams)
{
foreach (KeyValuePair<string, object> kvp in _dicParam as Dictionary<string, object>)
{
//DatasDic[kvp.Key] = kvp.Value; //error
this[kvp.Key] = kvp.Value;
}
}
}
}
public Message(Message message)
{
Name = message.Name;
Sender = message.Sender;
Content = message.Content;
foreach (KeyValuePair<string, object> kvp in message.DatasDic)
{
this[kvp.Key] = kvp.Value;
}
}
#endregion
#region Add & Remove
public void Add(string key, object value)
{
this[key] = value;
}
public void Remove(string key)
{
if (null != DatasDic && DatasDic.ContainsKey(key))
{
DatasDic.Remove(key);
}
}
#endregion
#region Send
public void Send()
{
MessageCenter.SendMessage(this);
}
#endregion
}
該事件系統的關鍵字就是通過創建的Message裏的Name來判斷的,所以要注意Name防止重複。
測試文件如下:
using UnityEngine;
using System.Collections;
public class MessageCenterTest : MonoBehaviour {
private readonly string test = "test";
void Awake()
{
MessageCenter.AddListener(test,OnMessageCome);
}
private void OnMessageCome(Message message)
{
Debug.LogError("--->" + message["gold"]);
}
void OnGUI()
{
if (GUI.Button(new Rect(50, 50, 150, 30), "OnMessageCome"))
{
Message message = new Message(test,this);
message["gold"] = 100;
message.Send();
}
}
}
=====================================================================
結束。