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

转载请注明地址:凉鞋的笔记

什么是消息机制?

让我先笑一会。(上一章说了)。

01.png
02.png
03.png
04.png
05.png

为什么用消息机制?

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

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

1.接收者

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.发送者

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.运行结果

06.png

使用起来几行代码的事情,实现起来就没这么简单了。

如何实现的?

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

IMsgReceiver:

using UnityEngine;  
using System.Collections;

namespace QFramework {

public interface IMsgReceiver  {


  }
}
IMsgSender

using UnityEngine;  
using System.Collections;

namespace QFramework {

public interface IMsgSender  {

  }
}

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

答案是使用C# this的扩展方式实现接口方法。 不清楚的童鞋请百度C# this扩展,有好多文章就不介绍了。 以上先告一段落,先介绍个重要的角色,MsgDispatcher(消息分发器)。

贴上第一部分代码:

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>> ();

读注释!!!

贴上注册消息的代码

    /// <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

发送消息相关的代码

    /// <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上边
贴出代码地址:消息机制相关代码地址

可以改进的地方:

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

坑:

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,376评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • 最近慢慢找回自己的状态,其实忙碌的工作,充实了生活,更丰富了内心。 就这样,每天有小收获和小进步,挺好的。 该来的...
    他说他的不说阅读 115评论 0 0
  • 寝室的条件很局限,但我们也要尽量准备一些用得上的东西,这些东西都已经被证实是寝室可以承受并且有用或必需的。 加热设...
    A7TuG3阅读 917评论 0 2
  • 其实我们正在丧失人类倾听的能力。特别是我们都已经开始习惯了用手机开始了解这个世界,而不是透过人人与之间的交往。而我...
    公子量阅读 344评论 0 0