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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM