Advanced CSharp Messenger的使用

原文地址:

  http://wiki.unity3d.com/index.php?title=Advanced_CSharp_Messenger

  用法写的不是很清晰,用到的知识点:泛型委托。

目的:

  事件的产生与事件处理的分离。

需求:

  UI界面的某个Button点击触发装备升级事件(升级完毕后需要显示结果供玩家查看),点击后向服务器发送请求,服务器做完相应的逻辑处理后,返回一个装备升级完毕的数据包(假设此时的装备在服务器从1级升为4级)。这个返回给客户端的数据包并非由UI来处理的(分层的概念不赘述),我们交给网络接口来处理接收到的数据包,在网络接口我们将数据包解析后重新给客户端的这件装备赋值(客户端用来显示的装备对象也由1级变为4级)。此时再将装备强化的最终结果交给UI,让UI来显示,但是UI层并不确定网络接口什么时候处理完数据,也就是说UI层需要被通知装备等级已经被改变,并且在确定等级改变后显示最终的强化结果。

  此时就用到了我们的消息管理器,我们将UI的强化结果的显示(显示的方法)作为事件注册到消息管理器内(就是为一个泛型委托注册方法)。Button点击的时候向服务器发送请求,服务器返回强化后的数据包,网络接口接到服务器传递的数据包,解析完毕重新给客户端的装备等级赋值完毕后,通过消息管理器调用UI注册到消息管理的方法。需要说明的是,UI注册的时候需要指定消息的指令号,网络接口调用消息管理器的方法也是根据指令号来调用对应的事件。

问题:

  装备的升级按钮的实现(上面讲到的注册的方法)不能脱离unity主线程,需要特殊处理。

使用:

using UnityEngine;

/// <summary>
/// UI界面测试
/// </summary>
public class TestUI : MonoBehaviour
{
    void OnGUI()
    {
        if (GUI.Button(new Rect(0, 0, 100, 50), "UpEquip"))
        {
            //①调用网络接,网络接口会去请求服务器。
            //②添加到监听:口令/要监听的方法
            //此时方法并没有执行。只有当网络接口处理完所有的数据并填充完数据管理器的时候才会去调用(网络层来确定什么时候调用)
            Messenger.AddListener(00001, UpEquip);//添加监听(key,要监听的方法)
            Messenger.AddListener(00001, UpEquip);//添加两个的话,在事件表内部会存在两个相同KEY的事件,当广播的时候会广播两次,因此在添加的时候要注意,避免重复注册的情况。
            //注册监听的方法应该脱离按钮的点击事件,否则多次点击会多次注册,广播事件的时候也会广播多次。
            //【避免重复调用的问题。】//Messenger.AddListener<int>(00002, UpEquip2);//前面的泛型代表方法要传递的参数
        }
    }

    //显示界面的方法
    void UpEquip()
    {
        Debug.Log("Equip+1~~~~");
    }
   //void UpEquip2(int lv) //{ //Debug.log("强化结果:"+lv);
   //} }
using UnityEngine;
 
/// <summary>
/// 网络接口测试
/// </summary>
public class TestSer : MonoBehaviour
{
    void OnGUI()
    {
        if (GUI.Button(new Rect(200, 200, 200, 50), "broad"))
        {
          //当网络接口将所有的数据被处理完毕之后,调用 显示弟子列表的方法。
            Messenger.Broadcast(00001);
        }
    }
}

 

附代码:

  有所修改,因为项目要求指令号为int类型。需求即使不添加监听也可以广播,所以以下代码将指令号由原先的string变为int,将空广播的异常捕获去掉了。

 

Callback

public delegate void Callback();
public delegate void Callback<T>(T arg1);
public delegate void Callback<T, U>(T arg1, U arg2);
public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);

MessengerHelper

using UnityEngine;

/// <summary>
/// This manager will ensure that the messenger's eventTable will be cleaned up upon loading of a new level.
/// </summary>
public sealed class MessengerHelper : MonoBehaviour
{
    void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
    //Clean up eventTable every time a new level loads.
    public void OnDisable()
    {
        Messenger.Cleanup();
    }
}

Messenger

//#define LOG_ALL_MESSAGES
//#define LOG_ADD_LISTENER
//#define LOG_BROADCAST_MESSAGE
#define REQUIRE_LISTENER

using System;
using System.Collections.Generic;
using UnityEngine;

static internal class Messenger
{
#region 事件表/Messages #pragma warning disable 0414 private static MessengerHelper messengerHelper = (new GameObject("MessengerHelper")).AddComponent<MessengerHelper>(); #pragma warning restore 0414 public static Dictionary<int, Delegate> eventTable = new Dictionary<int, Delegate>(); public static List<int> permanentMessages = new List<int>(); #endregion #region Helper methods //标记一个确定的消息永久储存。 public static void MarkAsPermanent(int eventType) { #if LOG_ALL_MESSAGES Debug.Log("Messenger MarkAsPermanent \t\"" + eventType + "\""); #endif permanentMessages.Add(eventType); } public static void Cleanup() { #if LOG_ALL_MESSAGES Debug.Log("MESSENGER Cleanup. Make sure that none of necessary listeners are removed."); #endif List<int> messagesToRemove = new List<int>(); foreach (KeyValuePair<int, Delegate> pair in eventTable) { bool wasFound = false; foreach (int message in permanentMessages) { if (pair.Key == message) { wasFound = true; break; } } if (!wasFound) messagesToRemove.Add(pair.Key); } foreach (int message in messagesToRemove) { eventTable.Remove(message); } } public static void PrintEventTable() { Debug.Log("\t\t\t=== MESSENGER PrintEventTable ==="); foreach (KeyValuePair<int, Delegate> pair in eventTable) { Debug.Log("\t\t\t" + pair.Key + "\t\t" + pair.Value); } Debug.Log("\n"); } #endregion #region 添加监听的异常捕获 Message logging and exception throwing public static void OnListenerAdding(int eventType, Delegate listenerBeingAdded) { #if LOG_ALL_MESSAGES || LOG_ADD_LISTENER Debug.Log("MESSENGER OnListenerAdding \t\"" + eventType + "\"\t{" + listenerBeingAdded.Target + " -> " + listenerBeingAdded.Method + "}"); #endif if (!eventTable.ContainsKey(eventType)) { eventTable.Add(eventType, null); } Delegate d = eventTable[eventType]; if (d != null && d.GetType() != listenerBeingAdded.GetType()) { throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name)); } } public static void OnListenerRemoving(int eventType, Delegate listenerBeingRemoved) { #if LOG_ALL_MESSAGES Debug.Log("MESSENGER OnListenerRemoving \t\"" + eventType + "\"\t{" + listenerBeingRemoved.Target + " -> " + listenerBeingRemoved.Method + "}"); #endif if (eventTable.ContainsKey(eventType)) { Delegate d = eventTable[eventType]; if (d == null) { throw new ListenerException(string.Format("Attempting to remove listener with for event type \"{0}\" but current listener is null.", eventType)); } else if (d.GetType() != listenerBeingRemoved.GetType()) { throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name)); } } else { throw new ListenerException(string.Format("Attempting to remove listener for type \"{0}\" but Messenger doesn't know about this event type.", eventType)); } } public static void OnListenerRemoved(int eventType) { if (eventTable[eventType] == null) { eventTable.Remove(eventType); } } public static void OnBroadcasting(int eventType) { #if REQUIRE_LISTENER //if (!eventTable.ContainsKey(eventType)) //{ // throw new BroadcastException(string.Format("Broadcasting message \"{0}\" but no listener found. Try marking the message with Messenger.MarkAsPermanent.", eventType)); //} #endif } //public static BroadcastException CreateBroadcastSignatureException(int eventType) //{ // return null;//new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", eventType)); //} //public class BroadcastException : Exception //{ // public BroadcastException(string msg) // : base(msg) // { // } //} public class ListenerException : Exception { public ListenerException(string msg) : base(msg) { } } #endregion #region 添加监听 public static void AddListener(int eventType, Callback handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback)eventTable[eventType] + handler; } public static void AddListener<T>(int eventType, Callback<T> handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler; } public static void AddListener<T, U>(int eventType, Callback<T, U> handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T, U>)eventTable[eventType] + handler; } public static void AddListener<T, U, V>(int eventType, Callback<T, U, V> handler) { OnListenerAdding(eventType, handler); eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] + handler; } #endregion #region 删除监听 public static void RemoveListener(int eventType, Callback handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback)eventTable[eventType] - handler; OnListenerRemoved(eventType); } public static void RemoveListener<T>(int eventType, Callback<T> handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler; OnListenerRemoved(eventType); } public static void RemoveListener<T, U>(int eventType, Callback<T, U> handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback<T, U>)eventTable[eventType] - handler; OnListenerRemoved(eventType); } public static void RemoveListener<T, U, V>(int eventType, Callback<T, U, V> handler) { OnListenerRemoving(eventType, handler); eventTable[eventType] = (Callback<T, U, V>)eventTable[eventType] - handler; OnListenerRemoved(eventType); } #endregion #region 广播监听 public static void Broadcast(int eventType) { #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\""); #endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback callback = d as Callback; if (callback != null) { callback(); } //else //{ // throw CreateBroadcastSignatureException(eventType); //} Debug.Log("One"); } } public static void Broadcast<T>(int eventType, T arg1) { #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\""); #endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T> callback = d as Callback<T>; if (callback != null) { callback(arg1); } //else //{ // throw CreateBroadcastSignatureException(eventType); //} Debug.Log("Two"); } } public static void Broadcast<T, U>(int eventType, T arg1, U arg2) { #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\""); #endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T, U> callback = d as Callback<T, U>; if (callback != null) { callback(arg1, arg2); } //else //{ // throw CreateBroadcastSignatureException(eventType); //} Debug.Log("Three"); } } public static void Broadcast<T, U, V>(int eventType, T arg1, U arg2, V arg3) { #if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\""); #endif OnBroadcasting(eventType); Delegate d; if (eventTable.TryGetValue(eventType, out d)) { Callback<T, U, V> callback = d as Callback<T, U, V>; if (callback != null) { callback(arg1, arg2, arg3); } //else //{ // throw CreateBroadcastSignatureException(eventType); //} Debug.Log("Four"); } } #endregion }

 

posted @ 2013-06-18 14:01  贴心小冰棍  阅读(1940)  评论(0编辑  收藏  举报