Unity 游戏框架搭建 (五) 简易消息机制

什么是消息机制?

5.简易消息机制  - 图1

5.简易消息机制  - 图2

5.简易消息机制  - 图3

5.简易消息机制  - 图4

5.简易消息机制  - 图5

23333333,让我先笑一会。

为什么用消息机制?

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

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

1.接收者

  1. using UnityEngine;
  2.  
  3. namespace QFramework.Example
  4. {
  5. /// <summary>
  6. /// 教程地址:http://liangxiegame.com/post/5/
  7. /// </summary>
  8. public class Receiver : MonoBehaviour, IMsgReceiver
  9. {
  10. // Use this for initialization
  11. private void Awake()
  12. {
  13. this.RegisterLogicMsg("Receiver Show Sth", ReceiveMsg);
  14. }
  15.  
  16. private void ReceiveMsg(object[] args)
  17. {
  18. foreach (var arg in args)
  19. {
  20. Log.I(arg);
  21. }
  22. }
  23. }
  24. }

2.发送者

  1. using UnityEngine;
  2.  
  3. namespace QFramework.Example
  4. {
  5. /// <summary>
  6. /// 教程地址:http://liangxiegame.com/post/5/
  7. /// </summary>
  8. public class Sender : MonoBehaviour, IMsgSender
  9. {
  10. void Update()
  11. {
  12. this.SendLogicMsg("Receiver Show Sth", "你好", "世界");
  13. }
  14. }
  15. }

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. /// <summary>
  2. /// 消息分发器
  3. /// C# this扩展 需要静态类
  4. /// 教程地址:http://liangxiegame.com/post/5/
  5. public static class MsgDispatcher
  6. {
  7. /// <summary>
  8. /// 消息捕捉器
  9. /// </summary>
  10. private class LogicMsgHandler
  11. {
  12. public readonly IMsgReceiver Receiver;
  13. public readonly Action<object[]> Callback;
  14.  
  15. public LogicMsgHandler(IMsgReceiver receiver, Action<object[]> callback)
  16. {
  17. Receiver = receiver;
  18. Callback = callback;
  19. }
  20. }
  21.  
  22. /// <summary>
  23. /// 每个消息名字维护一组消息捕捉器。
  24. /// </summary>
  25. static readonly Dictionary<string, List<LogicMsgHandler>> mMsgHandlerDict =
  26. new Dictionary<string, List<LogicMsgHandler>>();

读注释!!!

贴上注册消息的代码

  1. /// <summary>
  2. /// 注册消息,
  3. /// 注意第一个参数,使用了C# this的扩展,
  4. /// 所以只有实现IMsgReceiver的对象才能调用此方法
  5. /// </summary>
  6. public static void RegisterLogicMsg(this IMsgReceiver self, string msgName, Action<object[]> callback)
  7. {
  8. // 略过
  9. if (string.IsNullOrEmpty(msgName))
  10. {
  11. Log.W("RegisterMsg:" + msgName + " is Null or Empty");
  12. return;
  13. }
  14.  
  15. // 略过
  16. if (null == callback)
  17. {
  18. Log.W("RegisterMsg:" + msgName + " callback is Null");
  19. return;
  20. }
  21.  
  22. // 略过
  23. if (!mMsgHandlerDict.ContainsKey(msgName))
  24. {
  25. mMsgHandlerDict[msgName] = new List<LogicMsgHandler>();
  26. }
  27.  
  28. // 看下这里
  29. var handlers = mMsgHandlerDict[msgName];
  30.  
  31. // 略过
  32. // 防止重复注册
  33. foreach (var handler in handlers)
  34. {
  35. if (handler.Receiver == self && handler.Callback == callback)
  36. {
  37. Log.W("RegisterMsg:" + msgName + " ayready Register");
  38. return;
  39. }
  40. }
  41.  
  42. // 再看下这里
  43. handlers.Add(new LogicMsgHandler(self, callback));
  44. }

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

发送消息相关的代码

  1. /// <summary>
  2. /// 发送消息
  3. /// 注意第一个参数
  4. /// </summary>
  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. // 略过,不用看
  15. if (!mMsgHandlerDict.ContainsKey(msgName))
  16. {
  17. Log.W("SendMsg is UnRegister");
  18. return;
  19. }
  20.  
  21. // 开始看!!!!
  22. var handlers = mMsgHandlerDict[msgName];
  23. var handlerCount = handlers.Count;
  24.  
  25. // 之所以是从后向前遍历,是因为 从前向后遍历删除后索引值会不断变化
  26. // 参考文章,http://www.2cto.com/kf/201312/266723.html
  27. for (var index = handlerCount - 1; index >= 0; index--)
  28. {
  29. var handler = handlers[index];
  30.  
  31. if (handler.Receiver != null)
  32. {
  33. Log.W("SendLogicMsg:" + msgName + " Succeed");
  34. handler.Callback(paramList);
  35. }
  36. else
  37. {
  38. handlers.Remove(handler);
  39. }
  40. }
  41. }

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 。