游戏UI框架设计(6): 消息传递中心
游戏UI框架设计(6)
--消息传递中心
最近一直忙于一个益智类游戏的研发工作,所以博客有段时间没有更新了。经过朋友的督促,决定这两天立刻完成最后的两篇博客讲解(UI框架)。
说起“消息传递中心”,或者是“消息中心”,熟悉一些客户端架构设计的朋友一定不陌生。这种技术的来源就是为了解决脚本、类之间紧耦合的问题,而诞生的一种开发思想。目前基于Unity技术的游戏与项目研发,目前官方提供的消息传递方式种类少,且耦合性很高。
例如以下三种常用数据传递方式:
- 1: 脚本组件公共方法、字段的相互调用。
eg: GetComponnet<Scripts>().TestMethod();
这种方式是Unity提供初学者最简单,易用的方式,但是缺点很明显。
1> 写法麻烦,效率低。
2> 脚本之间存在强耦合性。
- 2: 单例模式数据传递。
使用“单例模式”做脚本(类)之间的数据传递,例如本UI框架中的UIMaskMgr.cs ResourcesMgr.cs 脚本都应用了单例。此种模式优劣分析如下:
1> 突出优点:脚本(类)之间可以非常简单方便的进行数据互相调用,且效率高。
2> 缺点: 脚本之间的强耦合性。
本数据传递方式,一般大家都在设计框架的内部应用,一般不会应用在实战项目中。(因为框架内部相对稳定,而实战项目需求经常变化)
- 3:SendMesage 技术。
SendMessage 是Unity 官方推荐的一种数据低耦合方式,但用过的朋友知道这种方式使用麻烦、适用范围狭小、且存在一定耦合性。
所以开发一种低耦合性,无需考虑脚本(类)内部差异(脚本名称、组件名称)的技术非常有价值。于是笔者基于观察者设计模式,利用委托与事件的基本机制原理,进一步封装重构了一个 MessageCenter.cs 的核心类。
- /***
- *
- * Title: "SUIFW" UI框架项目
- * 主题: 消息(传递)中心
- * Description:
- * 功能: 负责UI框架中,所有UI窗体中间的数据传值。
- *
- * Date: 2017
- * Version: 0.1版本
- * Modify Recoder:
- *
- *
- */
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace SUIFW
- {
- public class MessageCenter {
- //委托:消息传递
- public delegate void DelMessageDelivery(KeyValuesUpdate kv);
- //消息中心缓存集合
- //<string : 数据大的分类,DelMessageDelivery 数据执行委托>
- public static Dictionary<string, DelMessageDelivery> _dicMessages = new Dictionary<string, DelMessageDelivery>();
- /// <summary>
- /// 增加消息的监听。
- /// </summary>
- /// <param name="messageType">消息分类</param>
- /// <param name="handler">消息委托</param>
- public static void AddMsgListener(string messageType,DelMessageDelivery handler)
- {
- if (!_dicMessages.ContainsKey(messageType))
- {
- _dicMessages.Add(messageType,null);
- }
- _dicMessages[messageType] += handler;
- }
- /// <summary>
- /// 取消消息的监听
- /// </summary>
- /// <param name="messageType">消息分类</param>
- /// <param name="handele">消息委托</param>
- public static void RemoveMsgListener(string messageType,DelMessageDelivery handele)
- {
- if (_dicMessages.ContainsKey(messageType))
- {
- _dicMessages[messageType] -= handele;
- }
- }
- /// <summary>
- /// 取消所有指定消息的监听
- /// </summary>
- public static void ClearALLMsgListener()
- {
- if (_dicMessages!=null)
- {
- _dicMessages.Clear();
- }
- }
- /// <summary>
- /// 发送消息
- /// </summary>
- /// <param name="messageType">消息的分类</param>
- /// <param name="kv">键值对(对象)</param>
- public static void SendMessage(string messageType,KeyValuesUpdate kv)
- {
- DelMessageDelivery del; //委托
- if (_dicMessages.TryGetValue(messageType,out del))
- {
- if (del!=null)
- {
- //调用委托
- del(kv);
- }
- }
- }
- }
- /// <summary>
- /// 键值更新对
- /// 功能: 配合委托,实现委托数据传递
- /// </summary>
- public class KeyValuesUpdate
- { //键
- private string _Key;
- //值
- private object _Values;
- /* 只读属性 */
- public string Key
- {
- get { return _Key; }
- }
- public object Values
- {
- get { return _Values; }
- }
- public KeyValuesUpdate(string key, object valueObj)
- {
- _Key = key;
- _Values = valueObj;
- }
- }
- }
以上核心原理解释如下:
- 定义消息体的委托:public delegate void DelMessageDelivery(KeyValuesUpdate kv); 其中 KeyValuesUpdate 是一个简单的“键值对”类。
- 定义“字典集合”,string 参数表示消息的分类与名称, DelMessagDelivery 表示对应消息名称的委托。
public static Dictionary<string, DelMessageDelivery> _dicMessages = new Dictionary<string, DelMessageDelivery>();
为了进一步简化与方便消息传递的使用,笔者又对MessageCenter 类中的部分核心方法,做了进一步封装:
- /// <summary>
- /// 发送消息
- /// </summary>
- /// <param name="msgType">消息的类型</param>
- /// <param name="msgName">消息名称</param>
- /// <param name="msgContent">消息内容</param>
- protected void SendMessage(string msgType,string msgName,object msgContent)
- {
- KeyValuesUpdate kvs = new KeyValuesUpdate(msgName,msgContent);
- MessageCenter.SendMessage(msgType, kvs);
- }
- /// <summary>
- /// 接收消息
- /// </summary>
- /// <param name="messagType">消息分类</param>
- /// <param name="handler">消息委托</param>
- public void ReceiveMessage(string messagType,MessageCenter.DelMessageDelivery handler)
- {
- MessageCenter.AddMsgListener(messagType, handler);
- }
以上的代码被定义在“BaseUIForm”脚本中,前面介绍过这个脚本。 具体的“消息中心”应用示例如下:
本项目中当玩家点击“商城系统”中的最左边道具,系统会弹窗显示“神杖”道具,如果点击左边第2个道具图标,则系统显示“战靴”道具,具体见下图:
以上功能的实现代码如下:
- /***
- *
- * Title: "SUIFW" UI框架项目
- * 主题: “商城窗体”
- * Description:
- * 功能:
- *
- * Date: 2017
- * Version: 0.1版本
- * Modify Recoder:
- *
- *
- */
- using System.Collections;
- using System.Collections.Generic;
- using SUIFW;
- using UnityEngine;
- namespace DemoProject
- {
- public class MarketUIFrom : BaseUIForm
- {
- void Awake ()
- {
- //窗体性质
- CurrentUIType.UIForms_Type = UIFormType.PopUp; //弹出窗体
- CurrentUIType.UIForm_LucencyType = UIFormLucenyType.Translucence;
- CurrentUIType.UIForms_ShowMode = UIFormShowMode.ReverseChange;
- //注册按钮事件:退出
- RigisterButtonObjectEvent("Btn_Close",
- P=> CloseUIForm()
- );
- //注册道具事件:神杖
- RigisterButtonObjectEvent("BtnTicket",
- P =>
- {
- //打开子窗体
- OpenUIForm(ProConst.PRO_DETAIL_UIFORM);
- //传递数据
- string[] strArray = new string[] { "神杖详情", "神杖详细介绍。。。" };
- SendMessage("Props", "ticket", strArray);
- }
- );
- //注册道具事件:战靴
- RigisterButtonObjectEvent("BtnShoe",
- P =>
- {
- //打开子窗体
- OpenUIForm(ProConst.PRO_DETAIL_UIFORM);
- //传递数据
- string[] strArray = new string[] { "战靴详情", "战靴详细介绍。。。" };
- SendMessage("Props", "shoes", strArray);
- }
- );
- //注册道具事件:盔甲
- RigisterButtonObjectEvent("BtnCloth",
- P =>
- {
- //打开子窗体
- OpenUIForm(ProConst.PRO_DETAIL_UIFORM);
- //传递数据
- string[] strArray = new string[] { "盔甲详情", "盔甲详细介绍。。。" };
- SendMessage("Props", "cloth", strArray);
- }
- );
- }
- /***
- *
- * Title: "SUIFW" UI框架项目
- * 主题: 道具详细信息窗体
- * Description:
- * 功能: 显示各种道具信息
- *
- * Date: 2017
- * Version: 0.1版本
- * Modify Recoder:
- *
- *
- */
- using System.Collections;
- using System.Collections.Generic;
- using System.Net.Mime;
- using SUIFW;
- using UnityEngine;
- using UnityEngine.UI;
- namespace DemoProject
- {
- public class PropDetailUIForm : BaseUIForm
- {
- public Text TxtName; //窗体显示名称
- void Awake ()
- {
- //窗体的性质
- CurrentUIType.UIForms_Type = UIFormType.PopUp;
- CurrentUIType.UIForms_ShowMode = UIFormShowMode.ReverseChange;
- CurrentUIType.UIForm_LucencyType = UIFormLucenyType.Translucence;
- /* 按钮的注册 */
- RigisterButtonObjectEvent("BtnClose",
- p=>CloseUIForm()
- );
- /* 接受信息 */
- ReceiveMessage("Props",
- p =>
- {
- if (TxtName)
- {
- string[] strArray = p.Values as string[];
- TxtName.text = strArray[0];
- //print("测试道具的详细信息: "+strArray[1]);
- }
- }
- );
- }//Awake_end
- }
- }
好了就先讲到这里,大家如有疑问,可以直接留言。下次讲解本框架项目的最后一篇: 游戏UI框架设计(7):资源国际化技术。
游戏UI框架设计(6): 消息传递中心的更多相关文章
- 游戏UI框架设计(一) : 架构设计理论篇
游戏UI框架设计(一) ---架构设计理论篇 前几天(2017年2月)看到一篇文章,国内王健林.马云等大咖们看好的未来十大最有"钱途"产业中,排名第一的就是"泛娱乐&qu ...
- 游戏UI框架设计(五): 配置管理与应用
游戏UI框架设计(五) --配置管理与应用 在开发企业级游戏/VR/AR产品时候,我们总是希望可以总结出一些通用的技术体系,框架结构等,为简化我们的开发起到"四两拨千金"的作用.所 ...
- 游戏UI框架设计(二) : 最简版本设计
游戏UI框架设计(二) --最简版本设计 为降低难度决定先讲解一个最简版本,阐述UI框架的核心设计理念.这里先定义三个核心功能: 1:UI窗体的自动加载功能. 2:缓存UI窗体. 3:窗体生命周期(状 ...
- 游戏UI框架设计(三) : 窗体的层级管理
游戏UI框架设计(三) ---窗体的层级管理 UI框架中UI窗体的"层级管理",最核心的问题是如何进行窗体的显示管理.窗体(预设)的显示我们前面定义了三种类型: 普通.隐藏其他.反 ...
- 游戏UI框架设计(四) : 模态窗体管理
游戏UI框架设计(四) --模态窗体管理 我们在开发UI窗体时,对于"弹出窗体"往往因为需要玩家优先处理弹出小窗体,则要求玩家不能(无法)点击"父窗体",这种窗 ...
- 游戏UI框架设计(7): 资源国际化技术
游戏UI框架设计(7) --资源国际化技术 说起"资源国际化"技术,个人认为可以追述到微软Window2000 PC操作系统的发布,在这之前windows98操作系统的开发都是先由 ...
- 《开源框架那些事儿22》:UI框架设计实战
UI是User Interface的缩写.通常被觉得是MVC中View的部分,作用是提供跟人机交互的可视化操作界面. MVC中Model提供内容给UI进行渲染,用户通过UI框架产生响应,一般而言会由控 ...
- 自己动手设计并实现一个linux嵌入式UI框架(设计)
看了"自己动手设计并实现一个linux嵌入式UI框架"显然没有尽兴,因为还没有看到庐山真面目,那我今天继续,先来说说,我用到了哪些知识背景.如:C语言基础知识,尤其是指针.函数指针 ...
- Cocos Creator 通用框架设计 —— 资源管理优化
接着<Cocos Creator 通用框架设计 -- 资源管理>聊聊资源管理框架后续的一些优化: 通过论坛和github的issue,收到了很多优化或bug的反馈,基本上抽空全部处理了,大 ...
随机推荐
- 前后台分离部署时,Niginx上的部署
upstream bowenpay_backend { server 127.0.0.1:9002; } server { listen 80; server_name wx.bowenpay.com ...
- 基于分支限界法的旅行商问题(TSP)二
和上篇一样,考前写写伪代码,考完了补上具体的解释和代码. 状态{矩阵,结果集,下界} 全局结果集列表,全局上界初始为Infinite 建立一个heap,存储状态,出堆规则为拥有最小的下界. 利用red ...
- Flask入门之Virtualvenv的安装及使用(windows)
Virtualvenv 提供一个特定的Python虚拟环境(沙盒),以便于那些要求特定版本的模块的脚本能够顺利运行. 因为在Virtualvenv中,我们可以使用 pip install -r req ...
- C语言中变量的存储方式
变量可以分为全局变量.静态全局变量.局部变量和静态局部变量变量的声明有两种情况:1)一种是需要建立存储空间的(定义性声明).例如int a 在生命的时候就已经建立了存储空间.2)另一种是不需要建立存储 ...
- nexus私服搭建及maven生命周期
一.maven找库流程 从流程上看创建nexus私服,能够优化流程,而且更加快速 二.nexus下载.安装 1.nexus下载地址 https://sonatype-download.global.s ...
- ansj原子切分和全切分
ansj第一步会进行原子切分和全切分,并且是在同时进行的.所谓原子,是指短句中不可分割的最小语素单位.例如,一个汉字就是一个原子.全切分,就是把一句话中的所有词都找出来,只要是字典中有的就找出来.例如 ...
- ES6-LET,变量提升,函数提升
1:let命令 ①类似var,但只在let所在代码块内有效 ②不存在变量提升 ③暂时性死区(TDZ)—有let命令时,在此命令前都没法使用此变量 ④不允许重复声明 ⑤ES6允许块级作用域任意嵌套 ⑥E ...
- 关于linux find命令的使用
find 和 xargs xargs和find 在 使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行.但有些系统对能够传递给exec的命令 ...
- ASP.NET Core 2 学习笔记(一)
来势汹汹的.NET Core似乎要取代.NET Framework,ASP.NET也随之发布.NET Core版本.虽然名称沿用ASP.NET,但相对于ASP.NET确实有许多架构上的差异,可以说除了 ...
- 深入理解SpringCloud之分布式配置
Spring Cloud Config Server能够统一管理配置,我们绝大多数情况都是基于git或者svn作为其配置仓库,其实SpringCloud还可以把数据库作为配置仓库,今天我们就来了解一下 ...