遊戲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 官方推薦的一種數據低耦合方式,但用過的朋友知道這種方式使用麻煩、適用範圍狹小、且存在必定耦合性。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 delegate void DelMessageDelivery(KeyValuesUpdate kv);    其中 KeyValuesUpdate 是一個簡單的「鍵值對」類。
  •       定義「字典集合」,string 參數表示消息的分類與名稱, DelMessagDelivery 表示對應消息名稱的委託。

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

相關文章
相關標籤/搜索