天天看點

unity-消息的注冊,監聽,回調

最近在空閑時間準備做個小遊戲,先把一些基本架構搭建好,本次記錄的是消息的注冊,監聽和回調等

其實這些就是基于C#的委托(delegate)

第一步:定義一些委托

namespace Common.Messenger
{
    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);
    public delegate void Callback<T, U, V, W>(T arg1, U arg2, V arg3, W arg4);
    public delegate void Callback<T, U, V, W, X>(T arg1, U arg2, V arg3, W arg4, X arg5);
    public delegate void Callback<T, U, V, W, X, Y>(T arg1, U arg2, V arg3, W arg4, X arg5, Y arg6);

    public delegate T CallbackReturn<T>();
    public delegate T CallbackReturn<T, U>(U arg1);
}
      

  用泛型的方式靈活運用各種消息處理

第二步:定義兩個Message類,用于add/remove/brocast消息

namespace Common.Messenger
{
    public enum MessengerMode : byte
    {
        DONT_REQUIRE_LISTENER,
        REQUIRE_LISTENER,
    }
    private static internal class MessengerInternal
   {
       //......
   }
   public static class Messenger
   {  
       //....
   }
}
      

  

MessengerInternal類:用于存放消息類型,結構Dictionary<string,Delegate>

static internal class MessengerInternal
    {
        public static Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
        public static readonly MessengerMode DEFAULT_MODE = MessengerMode.DONT_REQUIRE_LISTENER;

        public static void OnListenerAdding(string eventType, Delegate listenerBeingAdded)
        {
            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 OnListenerMoving(string eventType,Delegate listenerBeingRemoved)
        {
            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(string eventType)
        {
            if (eventTable[eventType] == null)
                eventTable.Remove(eventType);
        }

        public static void OnBroadcasting(string eventType, MessengerMode mode)
        { 
            if(mode==MessengerMode.REQUIRE_LISTENER&&!eventTable.ContainsKey(eventType))
                throw new MessengerInternal.BroadcastException(string.Format("Broadcasting message {0} but no listener found.", eventType));
        }

        static public BroadcastException CreateBroadcastSignatureException(string eventType)
        {
            return 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)
            { 
                
            }
        }
    }
      

 Messenger類:Public類型,用于外界的調用,封裝了AddListener/Remove/Brocast的方法

public static class Messenger
    {
        private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;

        public static void AddListener(string eventType,Callback handler)
        {
            MessengerInternal.OnListenerAdding(eventType, handler);
            eventTable[eventType] = (Callback)eventTable[eventType] + handler;
        }
        public static void RemoveListener(string eventType, Callback handler)
        {
            MessengerInternal.OnListenerMoving(eventType, handler);
            eventTable[eventType] = (Callback)eventTable[eventType] - handler;
            MessengerInternal.OnListenerRemoved(eventType);
        }
        public static void Broadcast(string eventType)
        {
            Broadcast(eventType, MessengerInternal.DEFAULT_MODE);
        }

        public static void Broadcast(string eventType, MessengerMode mode)
        {
            MessengerInternal.OnBroadcasting(eventType, mode);
            Delegate d;
            if (eventTable.TryGetValue(eventType, out d))
            {
                Callback callback = d as Callback;
                if (callback != null)
                    callback();
                else
                    throw MessengerInternal.CreateBroadcastSignatureException(eventType);
            }
        }
    }
      

  Messenger<T>類:含參數的擴充類

public static class Messenger<T>
    {
        private static Dictionary<string, Delegate> eventTable = MessengerInternal.eventTable;
        public static void AddListener(string eventType, Callback<T> handler)
        {
            MessengerInternal.OnListenerAdding(eventType, handler);
            eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
        }
        public static void RemoveListener(string eventType, Callback<T> handler)
        {
            MessengerInternal.OnListenerMoving(eventType, handler);
            eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
        }

        public static void Broadcast(string eventType, T arg1)
        {
            Broadcast(eventType, arg1, MessengerInternal.DEFAULT_MODE);
        }
        public static void Broadcast(string eventType, T arg1, MessengerMode mode)
        {
            MessengerInternal.OnBroadcasting(eventType, mode);
            Delegate d;
            if (eventTable.TryGetValue(eventType,out d))
            {
                Callback<T> callback = d as Callback<T>;
                if (callback != null)
                    callback(arg1);
            }
            else
                throw MessengerInternal.CreateBroadcastSignatureException(eventType);
            
        }
    }
      

  Messenger<T, U>:同上

舉例:下面是一個消息彈窗例子

UI層調用

void OnStartClick(GameObject go)
        {
            UIMessageMgr.ShowMessBox("?????", () => { Debug.Log("Success"); });
        }
      

UIMessageMgr:

public static void ShowMessBox(string content, Callback ok)
    {
        Messenger<string, Callback>.Broadcast(MessengerEventDef.ShowMessBox, content, ok);
        //MessengerEventDef.ShowMessBox 是一個string,也就是Dictionary<>中的key
    }
      

注冊:

public override void RegisterMessage()
        {
            Messenger<string, Callback>.AddListener(MessengerEventDef.ShowMessBox, ShowMessBox);
        }
      

移除監聽:

public override void RemoveMessage()
        {
            Messenger<string, Callback>.RemoveListener(MessengerEventDef.ShowMessBox, ShowMessBox);
        }
      

  

以上功能就是通過消息來顯示提示框,使用的Message<T,U>,普通的消息可以用Message<T>

Client和Server之間的協定通信也用消息,Message<協定類>

//Message<協定類>.AddListener("這是一個字元串",回調方法)  
//回調方法  
//function(協定類)
//{
//  執行内容
//}
//Remove同上

//分發消息在接收到server的消息時把消息brocast
//function(協定類)
//{
//   Message<協定類>.Brocast("這是一個字元串",協定類)  
//}