遊戲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):資源國際化技術。