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