为什么用消息机制?

三个字,解!!!!耦!!!!合!!!!。

我的框架中的消息机制用例:

1.接收者

  1. using UnityEngine;

  2. namespace QFramework.Example

  3. {
  4. ///
  5. /// 教程地址:http://liangxiegame.com/post/5/
  6. ///
  7. public class Receiver : MonoBehaviour, IMsgReceiver
  8. {
  9. // Use this for initialization
  10. private void Awake()
  11. {
  12. this.RegisterLogicMsg(“Receiver Show Sth”, ReceiveMsg);
  13. }

  14. private void ReceiveMsg(object[] args)

  15. {
  16. foreach (var arg in args)
  17. {
  18. Log.I(arg);
  19. }
  20. }
  21. }
  22. }

2.发送者

  1. using UnityEngine;

  2. namespace QFramework.Example

  3. {
  4. ///
  5. /// 教程地址:http://liangxiegame.com/post/5/
  6. ///
  7. public class Sender : MonoBehaviour, IMsgSender
  8. {
  9. void Update()
  10. {
  11. this.SendLogicMsg(“Receiver Show Sth”, “你好”, “世界”);
  12. }
  13. }
  14. }

3.运行结果

5.简易消息机制 - 图6使用起来几行代码的事情,实现起来就没这么简单了。

如何实现的?

可以看到接收者实现了接口IMsgReceiver,发送者实现了接口IMsgSender。那先看下这两个接口定义。

IMsgReceiver:

  1. namespace QFramework
  2. {
  3. public interface IMsgReceiver
  4. {
  5. }
  6. }

IMsgSender

  1. namespace QFramework
  2. {
  3. public interface IMsgSender
  4. {
  5. }
  6. }

毛都没有啊。也没有SendLogicMsg或者ReceiveLogicMsg方法的定义啊。

答案是使用C# this的扩展方式实现接口方法。

不清楚的童鞋请百度C# this扩展,有好多文章就不介绍了。

以上先告一段落,先介绍个重要的角色,MsgDispatcher(消息分发器)。

贴上第一部分代码:

  1. ///
  2. /// 消息分发器
  3. /// C# this扩展 需要静态类
  4. /// 教程地址:http://liangxiegame.com/post/5/
  5. public static class MsgDispatcher
  6. {
  7. ///
  8. /// 消息捕捉器
  9. ///
  10. private class LogicMsgHandler
  11. {
  12. public readonly IMsgReceiver Receiver;
  13. public readonly Action Callback;

  14. public LogicMsgHandler(IMsgReceiver receiver, Action callback)

  15. {
  16. Receiver = receiver;
  17. Callback = callback;
  18. }
  19. }

  20. ///

  21. /// 每个消息名字维护一组消息捕捉器。
  22. ///
  23. static readonly Dictionary> mMsgHandlerDict =
  24. new Dictionary>();

读注释!!!

贴上注册消息的代码

  1. ///
  2. /// 注册消息,
  3. /// 注意第一个参数,使用了C# this的扩展,
  4. /// 所以只有实现IMsgReceiver的对象才能调用此方法
  5. ///
  6. public static void RegisterLogicMsg(this IMsgReceiver self, string msgName, Action callback)
  7. {
  8. // 略过
  9. if (string.IsNullOrEmpty(msgName))
  10. {
  11. Log.W(“RegisterMsg:” + msgName + “ is Null or Empty”);
  12. return;
  13. }

  14. // 略过

  15. if (null == callback)
  16. {
  17. Log.W(“RegisterMsg:” + msgName + “ callback is Null”);
  18. return;
  19. }

  20. // 略过

  21. if (!mMsgHandlerDict.ContainsKey(msgName))
  22. {
  23. mMsgHandlerDict[msgName] = new List();
  24. }

  25. // 看下这里

  26. var handlers = mMsgHandlerDict[msgName];

  27. // 略过

  28. // 防止重复注册
  29. foreach (var handler in handlers)
  30. {
  31. if (handler.Receiver == self && handler.Callback == callback)
  32. {
  33. Log.W(“RegisterMsg:” + msgName + “ ayready Register”);
  34. return;
  35. }
  36. }

  37. // 再看下这里

  38. handlers.Add(new LogicMsgHandler(self, callback));
  39. }

为了节省您时间,略过部分的代码就不要看了,什么?!!你都看了!!!! 23333

发送消息相关的代码

  1. ///
  2. /// 发送消息
  3. /// 注意第一个参数
  4. ///
  5. public static void SendLogicMsg(this IMsgSender sender, string msgName, params object[] paramList)
  6. {
  7. // 略过,不用看
  8. if (string.IsNullOrEmpty(msgName))
  9. {
  10. Log.E(“SendMsg is Null or Empty”);
  11. return;
  12. }

  13. // 略过,不用看

  14. if (!mMsgHandlerDict.ContainsKey(msgName))
  15. {
  16. Log.W(“SendMsg is UnRegister”);
  17. return;
  18. }

  19. // 开始看!!!!

  20. var handlers = mMsgHandlerDict[msgName];
  21. var handlerCount = handlers.Count;

  22. // 之所以是从后向前遍历,是因为 从前向后遍历删除后索引值会不断变化

  23. // 参考文章,http://www.2cto.com/kf/201312/266723.html
  24. for (var index = handlerCount - 1; index >= 0; index—)
  25. {
  26. var handler = handlers[index];

  27. if (handler.Receiver != null)

  28. {
  29. Log.W(“SendLogicMsg:” + msgName + “ Succeed”);
  30. handler.Callback(paramList);
  31. }
  32. else
  33. {
  34. handlers.Remove(handler);
  35. }
  36. }
  37. }

OK主要的部分全都贴出来啦

可以改进的地方:

  • 目前整个游戏的消息都由一个字典维护,可以改进为每个模块维护一个字典或者其他方式。
  • 消息名字类型由字符串定义的,可以改成枚举转unsigned int方式。
  • 欢迎补充。

  • 如果是MonoBehaviour注册消息之后,GameObject Destroy之前一定要注销消息,之前的解决方案是,自定义一个基类来维护该对象已经注册的消息列表,然后在基类的OnDestory时候遍历卸载。
  • 欢迎补充。

相关链接:

我的框架地址:https://github.com/liangxiegame/QFramework

教程源码:https://github.com/liangxiegame/QFramework/tree/master/Assets/HowToWriteUnityGameFramework/

QFramework &游戏框架搭建QQ交流群: 623597263

转载请注明地址:凉鞋的笔记http://liangxiegame.com/

微信公众号:liangxiegame

5.简易消息机制 - 图7

如果有帮助到您:

如果觉得本篇教程对您有帮助,不妨通过以下方式赞助笔者一下,鼓励笔者继续写出更多高质量的教程,也让更多的力量加入 QFramework 。