游戏UI框架设计(6)设计模式
--消息传递中心缓存
最近一直忙于一个益智类游戏的研发工做,因此博客有段时间没有更新了。通过朋友的督促,决定这两天马上完成最后的两篇博客讲解(UI框架)。
提及“消息传递中心”,或者是“消息中心”,熟悉一些客户端架构设计的朋友必定不陌生。这种技术的来源就是为了解决脚本、类之间紧耦合的问题,而诞生的一种开发思想。目前基于Unity技术的游戏与项目研发,目前官方提供的消息传递方式种类少,且耦合性很高。
例如如下三种经常使用数据传递方式:架构
eg: GetComponnet<Scripts>().TestMethod();
这种方式是Unity提供初学者最简单,易用的方式,可是缺点很明显。
1> 写法麻烦,效率低。
2> 脚本之间存在强耦合性。框架
使用“单例模式”作脚本(类)之间的数据传递,例如本UI框架中的UIMaskMgr.cs ResourcesMgr.cs 脚本都应用了单例。此种模式优劣分析以下:
1> 突出优势:脚本(类)之间能够很是简单方便的进行数据互相调用,且效率高。
2> 缺点: 脚本之间的强耦合性。
本数据传递方式,通常你们都在设计框架的内部应用,通常不会应用在实战项目中。(由于框架内部相对稳定,而实战项目需求常常变化)测试
SendMessage 是Unity 官方推荐的一种数据低耦合方式,但用过的朋友知道这种方式使用麻烦、适用范围狭小、且存在必定耦合性。spa
因此开发一种低耦合性,无需考虑脚本(类)内部差别(脚本名称、组件名称)的技术很是有价值。因而笔者基于观察者设计模式,利用委托与事件的基本机制原理,进一步封装重构了一个 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 static Dictionary<string, DelMessageDelivery> _dicMessages = new Dictionary<string, DelMessageDelivery>();
为了进一步简化与方便消息传递的使用,笔者又对MessageCenter 类中的部分核心方法,作了进一步封装:code
/// <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”脚本中,前面介绍过这个脚本。 具体的“消息中心”应用示例以下:orm
本项目中当玩家点击“商城系统”中的最左边道具,系统会弹窗显示“神杖”道具,若是点击左边第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):资源国际化技术。