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

时间:2022-10-30 18:38:55
什么是消息机制?
Unity 游戏框架搭建 (五) 简易消息机制
Unity 游戏框架搭建 (五) 简易消息机制
Unity 游戏框架搭建 (五) 简易消息机制
Unity 游戏框架搭建 (五) 简易消息机制
Unity 游戏框架搭建 (五) 简易消息机制
23333333,让我先笑一会。

为什么用消息机制?
  三个字,解!!!!耦!!!!合!!!!。
我的框架中的消息机制用例:
1.接收者

[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using UnityEngine; 
using System.Collections;
 
using QFramework;
 
/// <summary>
/// 1.接收者需要实现IMsgReceiver接口。
/// 2.使用this.RegisterLogicMsg注册消息和回调函数。
/// </summary>
public class Receiver : MonoBehaviour,IMsgReceiver {
 
     void Awake()
     {
         this .RegisterLogicMsg ( "Receiver Show Sth" , ReceiverMsg);
 
//        this.UnRegisterLogicMsg ("Receiver Show Sth", ReceiverMsg);
 
     }
 
 
     void ReceiverMsg( params object [] paramList)
     {
         foreach (var sth in paramList) {
             QPrint.Warn (sth.ToString());
         }
     }
}
2.发送者

[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
using UnityEngine;
using System.Collections;
using QFramework;
 
/// <summary>
/// 1.发送者需要,实现IMsgSender接口
/// 2.调用this.SendLogicMsg发送Receiver Show Sth消息,并传入两个参数
/// </summary>
public class Sender : MonoBehaviour,IMsgSender {
 
     // Update is called once per frame
     void Update () {
         this .SendLogicMsg ( "Receiver Show Sth" , "你好" , "世界" );
     }
}

3.运行结果
Unity 游戏框架搭建 (五) 简易消息机制


使用起来几行代码的事情,实现起来就没这么简单了。
如何实现的?
  可以看到接收者实现了接口IMsgReceiver,发送者实现了接口IMsgSender。 那先看下这两个接口定义。
IMsgReceiver:


[C#]  纯文本查看  复制代码
?
 
1
2
3
4
5
6
7
8
9
using UnityEngine; 
using System.Collections;
 
namespace QFramework {
 
     public interface IMsgReceiver  {
 
 
     }
}

IMsgSender:

[C#]  纯文本查看  复制代码
?
 
1
2
3
4
5
6
7
8
using UnityEngine; 
using System.Collections;
 
namespace QFramework {
 
     public interface IMsgSender  {
 
     }
}


毛都没有啊。也没有SendLogicMsg或者ReceiveLogicMsg方法的定义啊。
答案是使用C# this的扩展方式实现接口方法。 不清楚的童鞋请百度C# this扩展,有好多文章就不介绍了。 以上先告一段落,先介绍个重要的角色,MsgDispatcher(消息分发器)。
贴上第一部分代码:

[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
namespace QFramework { 
     /// <summary>
     /// 消息分发器
     /// C# this扩展 需要静态类
     /// </summary>
     public static class QMsgDispatcher  {
 
         /// <summary>
         /// 消息捕捉器
         /// </summary>
         class LogicMsgHandler {
 
             public IMsgReceiver receiver;
             public  VoidDelegate.WithParams callback;
 
             /*
              * VoidDelegate.WithParams 是一种委托 ,定义是这样的
              *
              *  public class VoidDelegate{
              *      public delegate void WithParams(params object[] paramList);
              *  }
              */
             public LogicMsgHandler(IMsgReceiver receiver,VoidDelegate.WithParams callback)
             {
                 this .receiver = receiver;
                 this .callback = callback;
             }
         }
 
         /// <summary>
         /// 每个消息名字维护一组消息捕捉器。
         /// </summary>
         static Dictionary< string ,List<LogicMsgHandler>> mMsgHandlerDict = new Dictionary< string ,List<LogicMsgHandler>> ();

读注释!!!

贴上注册消息的代码

[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/// <summary>
/// 注册消息,
/// 注意第一个参数,使用了C# this的扩展,
/// 所以只有实现IMsgReceiver的对象才能调用此方法
/// </summary>
public static void RegisterLogicMsg( this IMsgReceiver self, string msgName,VoidDelegate.WithParams callback)
{
     // 略过
     if ( string .IsNullOrEmpty(msgName)) {
         QPrint.FrameworkWarn( "RegisterMsg:" + msgName + " is Null or Empty" );
         return ;
     }
 
     // 略过
     if ( null == callback) {
         QPrint.FrameworkWarn ( "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) {
             QPrint.FrameworkWarn ( "RegisterMsg:" + msgName + " ayready Register" );
             return ;
         }
     }
 
     // 再看下这里
     handlers.Add ( new LogicMsgHandler (self, callback));
}



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

[C#]  纯文本查看  复制代码
?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/// <summary>
/// 发送消息
/// 注意第一个参数
/// </summary>
public static void SendLogicMsg( this IMsgSender sender, string msgName, params object [] paramList )
{
     // 略过,不用看
     if ( string .IsNullOrEmpty(msgName)) {
         QPrint.FrameworkError( "SendMsg is Null or Empty" );
         return ;
     }
 
     // 略过,不用看
     if (!mMsgHandlerDict.ContainsKey(msgName)){
         QPrint.FrameworkWarn( "SendMsg is UnRegister" );
         return ;
     }
 
     // 开始看!!!!
     var handlers = mMsgHandlerDict[msgName];
 
 
     var handlerCount = handlers.Count;
 
     // 之所以是从后向前遍历,是因为  从前向后遍历删除后索引值会不断变化
     // 参考文章,http://www.2cto.com/kf/201312/266723.html
     for ( int index = handlerCount - 1;index >= 0;index--)
     {
         var handler = handlers[index];
 
         if (handler.receiver != null ) {
             QPrint.FrameworkLog ( "SendLogicMsg:" + msgName + " Succeed" );
             handler.callback (paramList);
         } else {
             handlers.Remove (handler);
         }
     }
}

OK主要的部分全都贴出来啦
以上代码以全部上传到Github上边
贴出代码地址:消息机制相关代码地址:https://github.com/liangxiegame/QFramework/tree/master/Script/Event


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

    1.如果是MonoBehaviour注册消息之后,GameObject Destroy之前一定要注销消息,之前的解决方案是,自定义一个基类来维护该对象已经注册的消息列表,然后在基类的OnDestory时候遍历卸载。
    2.欢迎补充。
附:我的框架地址:https://github.com/liangxiegame/QFramework
转载请注明地址:凉鞋的笔记:http://liangxiegame.com/