Unity 游戏框架搭建 (五) 简易消息机制 - 纳金网
联系我们

给我们留言

联系我们

地址:福建省晋江市青阳街道洪山路国际工业设计园纳金网

邮箱:info@narkii.com

电话:0595-82682267

(周一到周五, 周六周日休息)

当前位置:主页 > 3D教程 > 图文教程

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

来源: 未知 | 责任编辑:骆驼祥子 | 发布时间: 2017-07-05 14:43 | 浏览量:
本节汇宝盆为大家带来unity3d的游戏框架搭建(五)简易消息机制

3d素材Unity 游戏框架搭建 (一) 概述 http://www.narkii.com/club/thread-403704-1.html
3d素材unity 游戏框架搭建 (二) 单例的模板 http://www.narkii.com/club/thread-403705-1.html
3d素材unity游戏框架搭建 (三) MonoBehaviour单例的模板 http://www.narkii.com/club/thread-403706-1.html
3d素材unity 游戏框架搭建 (四) 简易有限状态机 http://www.narkii.com/club/thread-403707-1.html


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

为什么用消息机制?
  
三个字,解!!!!耦!!!!合!!!!。

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

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.运行结果
Unity 游戏框架搭建 (五) 简易消息机制
使用起来几行代码的事情,实现起来就没这么简单了。

如何实现的?
  可以看到接收者实现了接口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));
        }


发送消息相关的代码

        /// <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主要的部分全都贴出来啦
以上代码以全部上传到论坛上边
贴出代码地址:消息机制相关代码地址

可以改进的地方:

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



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


感谢凉鞋的笔记的分享,更多精彩内容尽在汇宝盆

相关文章
网友评论

您需要登录后才可以发帖 登录 | 立即注册

关闭

全部评论:1条

推荐
热门