ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 什么是消息机制? ![DraggedImage.png](http://file.liangxiegame.com/ad1c0af2-96e1-4374-9c3e-e1f181bc5556.png) ![DraggedImage-1.png](http://file.liangxiegame.com/3b5aa31e-f683-494d-992e-bbab6d784a00.png) ![DraggedImage-2.png](http://file.liangxiegame.com/9145ef5a-3b78-4682-9fad-a2bbfc5a9059.png) ![DraggedImage-3.png](http://file.liangxiegame.com/d814d606-01bc-4977-9cac-b74dda7dd6f7.png) ![DraggedImage-4.png](http://file.liangxiegame.com/310a81a6-fad6-48ff-b43c-fc718aa86b68.png) 23333333,让我先笑一会。 ## 为什么用消息机制? 三个字,解!!!!耦!!!!合!!!!。 ## 我的框架中的消息机制用例: 1.接收者 Receiver.cs ```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.发送者 ```cs 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.运行结果 ![v2-4de41c395a2b7db148bee4cec926411e_hd.jpg](http://file.liangxiegame.com/bb135a17-5926-4c9a-93fb-6eef82810347.png) 使用起来几行代码的事情,实现起来就没这么简单了。 ## 如何实现的? 可以看到接收者实现了接口IMsgReceiver,发送者实现了接口 IMsgSender。 那先看下这两个接口定义。 IMsgReceiver.cs: ```cs namespace QFramework { public interface IMsgReceiver { } } ``` IMsgSender.cs: ```cs namespace QFramework { public interface IMsgSender { } } ``` 毛都没有啊。也没有 SendLogicMsg 或者 ReceiveLogicMsg 方法的定义啊。 答案是使用 C# this 的扩展方式实现接口方法。 不清楚的童鞋请百度 C# this 扩展,有好多文章就不介绍了。 以上先告一段落,先介绍个重要的角色,MsgDispatcher (消息分发器)。 贴上第一部分代码: ```cs /// <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>>(); ``` 读注释!!! 贴上注册消息的代码 ```cs /// <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 发送消息相关的代码 ```cs /// <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](http://liangxiegame.com) ## 更多内容 * QFramework 地址:[https://github.com/liangxiegame/QFramework](https://github.com/liangxiegame/QFramework) * QQ 交流群:[623597263](http://shang.qq.com/wpa/qunwpa?idkey=706b8eef0fff3fe4be9ce27c8702ad7d8cc1bceabe3b7c0430ec9559b3a9ce66) * **Unity 进阶小班**: * 主要训练内容: * 框架搭建训练(第一年) * 跟着案例学 Shader(第一年) * 副业的孵化(第二年、第三年) * 权益、授课形式等具体详情请查看[《小班产品手册》](https://liangxiegame.com/master/intro):https://liangxiegame.com/master/intro * 关注公众号:liangxiegame 获取第一时间更新通知及更多的免费内容。 ![](http://file.liangxiegame.com/38eccb55-40b2-4845-93d6-f5fb50ff9492.png)