什么是消息機制?
23333333,讓我先笑一會。
為什么用消息機制?
三個字,解!!!!耦!!!!合!!!!。
我的框架中的消息機制用例:
1.接收者 Receiver.cs
using UnityEngine; namespace QFramework.Example { /// <summary> /// 教程地址:http://liangxiegame.com/post/5/ /// </summary> public class Receiver : MonoBehaviour, IMsgReceiver { // Use this for initialization private void Awake() { this.RegisterLogicMsg("Receiver Show Sth", ReceiveMsg); } private void ReceiveMsg(object[] args) { foreach (var arg in args) { Log.I(arg); } } } }
2.發送者
using UnityEngine; namespace QFramework.Example { /// <summary> /// 教程地址:http://liangxiegame.com/post/5/ /// </summary> public class Sender : MonoBehaviour, IMsgSender { void Update() { this.SendLogicMsg("Receiver Show Sth", "你好", "世界"); } } }
3.運行結果
使用起來幾行代碼的事情,實現起來就沒這么簡單了。
如何實現的?
可以看到接收者實現了接口IMsgReceiver,發送者實現了接口 IMsgSender。 那先看下這兩個接口定義。
IMsgReceiver.cs:
namespace QFramework
{
public interface IMsgReceiver { } }
IMsgSender.cs:
namespace QFramework
{
public interface IMsgSender { } }
毛都沒有啊。也沒有 SendLogicMsg 或者 ReceiveLogicMsg 方法的定義啊。
答案是使用 C# this 的擴展方式實現接口方法。
不清楚的童鞋請百度 C# this 擴展,有好多文章就不介紹了。
以上先告一段落,先介紹個重要的角色,MsgDispatcher (消息分發器)。
貼上第一部分代碼:
/// <summary> /// 消息分發器 /// C# this擴展 需要靜態類 /// 教程地址:http://liangxiegame.com/post/5/ public static class MsgDispatcher { /// <summary> /// 消息捕捉器 /// </summary> private class LogicMsgHandler { public readonly IMsgReceiver Receiver; public readonly Action<object[]> Callback; public LogicMsgHandler(IMsgReceiver receiver, Action<object[]> callback) { Receiver = receiver; Callback = callback; } } /// <summary> /// 每個消息名字維護一組消息捕捉器。 /// </summary> static readonly Dictionary<string, List<LogicMsgHandler>> mMsgHandlerDict = new Dictionary<string, List<LogicMsgHandler>>();
讀注釋!!!
貼上注冊消息的代碼
/// <summary> /// 注冊消息, /// 注意第一個參數,使用了C# this的擴展, /// 所以只有實現IMsgReceiver的對象才能調用此方法 /// </summary> public static void RegisterLogicMsg(this IMsgReceiver self, string msgName, Action<object[]> callback) { // 略過 if (string.IsNullOrEmpty(msgName)) { Log.W("RegisterMsg:" + msgName + " is Null or Empty"); return; } // 略過 if (null == callback) { Log.W("RegisterMsg:" + msgName + " callback is Null"); return; } // 略過 if (!mMsgHandlerDict.ContainsKey(msgName)) { mMsgHandlerDict[msgName] = new List<LogicMsgHandler>(); } // 看下這里 var handlers = mMsgHandlerDict[msgName]; // 略過 // 防止重復注冊 foreach (var handler in handlers) { if (handler.Receiver == self && handler.Callback == callback) { Log.W("RegisterMsg:" + msgName + " ayready Register"); return; } } // 再看下這里 handlers.Add(new LogicMsgHandler(self, callback)); }
為了節省您時間,略過部分的代碼就不要看了,什么?!!你都看了!!!! 23333
發送消息相關的代碼
/// <summary> /// 發送消息 /// 注意第一個參數 /// </summary> public static void SendLogicMsg(this IMsgSender sender, string msgName, params object[] paramList) { // 略過,不用看 if (string.IsNullOrEmpty(msgName)) { Log.E("SendMsg is Null or Empty"); return; } // 略過,不用看 if (!mMsgHandlerDict.ContainsKey(msgName)) { Log.W("SendMsg is UnRegister"); return; } // 開始看!!!! var handlers = mMsgHandlerDict[msgName]; var handlerCount = handlers.Count; // 之所以是從后向前遍歷,是因為 從前向后遍歷刪除后索引值會不斷變化 // 參考文章,http://www.2cto.com/kf/201312/266723.html for (var index = handlerCount - 1; index >= 0; index--) { var handler = handlers[index]; if (handler.Receiver != null) { Log.W("SendLogicMsg:" + msgName + " Succeed"); handler.Callback(paramList); } else { handlers.Remove(handler); } } }
OK 主要的部分全都貼出來啦。
可以改進的地方:
- 目前整個游戲的消息都由一個字典維護,可以改進為每個模塊維護一個字典或者其他方式。
- 消息名字類型由字符串定義的,可以改成枚舉轉 unsigned int 方式。
- 歡迎補充。
坑:
- 如果是 MonoBehaviour 注冊消息之后,GameObject Destroy 之前一定要注銷消息,之前的解決方案是,自定義一個基類來維護該對象已經注冊的消息列表,然后在基類的 OnDestory 時候遍歷卸載。
- 歡迎補充。
轉載請注明地址:涼鞋的筆記:liangxiegame.com
更多內容
-
QFramework 地址:https://github.com/liangxiegame/QFramework
-
QQ 交流群:623597263
-
Unity 進階小班:
- 主要訓練內容:
- 框架搭建訓練(第一年)
- 跟着案例學 Shader(第一年)
- 副業的孵化(第二年、第三年)
- 權益、授課形式等具體詳情請查看《小班產品手冊》:https://liangxiegame.com/master/intro
- 主要訓練內容:
-
關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。