遊戲UI框架設計(三) : 窗體的層級管理

遊戲UI框架設計(三)
程序員

---窗體的層級管理緩存


  UI框架中UI窗體的「層級管理」,最核心的問題是如何進行窗體的顯示管理。窗體(預設)的顯示咱們前面定義了三種類型: 普通、隱藏其餘、反向切換。代碼以下:數據結構

wKioL1i0FfzAMgD0AABi9OXpuqk291.jpg

    

    「普通顯示」模式容許多個窗體同時顯示,這種類型應用最多。例如RPG中的主城界面(見下圖)。框架

wKiom1i0FhvyYRavAADtDc2-IiM212.jpg


    「隱藏其餘界面」 模式通常應用於全局性的窗體。咱們在開發此類窗體時,爲了減小UI渲染壓力、提升Unity渲染效率,則設置被覆蓋的窗體爲「不可見」狀態。(即: this.gameObject.SetActive(false))。例如通常的登陸窗體、選擇英雄窗體等。ide

wKioL1i0Fj6Su9qqAAD8-iQZLbA253.jpg


  「反向切換」模式類型,通常都大量引用於「彈出窗體」中。此類窗體的特色是:顯示彈出窗體時不徹底覆蓋底層窗體,通常在屏幕的四周會露出底層窗體。之因此命名「反向切換」是由於: 程序員要維護一種「後進先出」的「棧」的數據結構特色,即咱們通常要求玩家必須先關閉彈出的頂層窗體,再依次關閉下一級窗體。以下圖所示。測試

wKioL1i0Fm2CHqPVAAY68LVdAME852.png


  上圖即一種典型的彈出窗體。通常咱們都要求玩家先處理彈出窗體中的信息,而後關閉此窗體。通常不容許在沒有關閉子窗體的狀況下,直接點擊父窗體。(關於彈出窗體時,不容許玩家點擊父窗體的功能實現,筆者在下節[「模態窗體管理」]一章着重講解)。
this

  以上說了這麼多了,咱們對於「層級管理」的核心代碼實現,基本都體如今「UI管理器腳本」 (UIManager.cs )中。如下給出具體實現代碼:spa


/***設計

 *   Title: "SUIFW" 框架技術3d

 *          主題: UI管理器    

 *   Description:

 *          功能:整個UI框架的核心,用戶程序經過調用本類,來調用本框架的大多數功能。 

 *          功能1:關於入「棧」與出「棧」的UI窗體4個狀態的定義邏輯

 *                 入棧狀態:

 *                     Freeze();   (上一個UI窗體)凍結

 *                     Display();  (本UI窗體)顯示

 *                 出棧狀態:

 *                     Hiding();    (本UI窗體) 隱藏

 *                     Redisplay(); (上一個UI窗體) 從新顯示

 *         功能2:增長「非棧」緩存集合。

 */

using UnityEngine;

usingUnityEngine.UI;

using System;

usingSystem.Collections.Generic;

 

namespace SUIFW

{

   publicclassUIManager : MonoBehaviour

   {

        /* 字段  */

        //本類實例

        privatestaticUIManager_Instance = null;

        //存儲全部「UI窗體預設(Prefab)」路徑

        //參數含義: 第1個string 表示「窗體預設」名稱,後一個string 表示對應的路徑

        privateDictionary<string,string> _DicUIFormsPaths;

        //緩存全部已經打開的「UI窗體預設(Prefab)」

        //參數含義: 第1個string 表示「窗體預設」名稱,後一個BaseUI 表示對應的「窗體預設」

        privateDictionary<string,BaseUIForms> _DicALLUIForms;

        //「棧」結構表示的「當前UI窗體」集合。

        privateStack<BaseUIForms>_StaCurrentUIForms;

        //當前顯示狀態的UI窗體集合

        privateDictionary<string,BaseUIForms> _DicCurrentShowUIForms;

        //UI根節點

        privateTransform _CanvasTransform = null;

        //普通全屏界面節點

        privateTransform _CanTransformNormal = null;

        //固定界面節點

        privateTransform _CanTransformFixed = null;

        //彈出模式節點

        privateTransform _CanTransformPopUp = null;

        //UI腳本節點(加載各類管理腳本的節點)

        privateTransform _CanTransformUIScripts = null;

 

 

 

 

        ///<summary>

        ///獲得本類實例

        ///</summary>

        ///<returns></returns>

        publicstaticUIManagerGetInstance()

        {

            if(_Instance == null)

            {

                _Instance = newGameObject("_UIManager").AddComponent<UIManager>();

            }

            return_Instance;

        }

 

        voidAwake()

        {

            //字段初始化

            _DicUIFormsPaths = newDictionary<string,string>();

            _DicALLUIForms = newDictionary<string,BaseUIForms>();

            _StaCurrentUIForms = newStack<BaseUIForms>();

            _DicCurrentShowUIForms = newDictionary<string,BaseUIForms>();

 

            //初始化項目開始必須的資源加載

           InitRootCanvasLoading();

 

            //獲得UI根節點、及其重要子節點                    

            _CanvasTransform = GameObject.FindGameObjectWithTag(SysDefine.SYS_TAG_CANVAS).transform;

            //獲得普通全屏界面節點、固定界面節點、彈出模式節點、UI腳本節點

            _CanTransformNormal = UnityHelper.FindTheChild(_CanvasTransform.gameObject,SysDefine.SYS_CANVAS_NORMAL_NODE_NAME);

            _CanTransformFixed = UnityHelper.FindTheChild(_CanvasTransform.gameObject,SysDefine.SYS_CANVAS_FIXED_NODE_NAME);

            _CanTransformPopUp = UnityHelper.FindTheChild(_CanvasTransform.gameObject,SysDefine.SYS_CANVAS_POPUP_NODE_NAME);

            _CanTransformUIScripts = UnityHelper.FindTheChild(_CanvasTransform.gameObject,SysDefine.SYS_CANVAS_UISCRIPTS_NODE_NAME);

 

            //把本腳本實例,做爲Canvas的子節點

            UnityHelper.AddChildToParent(_CanTransformUIScripts,this.gameObject.transform);

 

            //本UI節點信息,場景轉換時,不容許銷燬

           DontDestroyOnLoad(_CanvasTransform);

            //初始化「UI窗體預設」路徑數據

            InitUIFormsPathsData();

        }

 

        ///<summary>

        ///顯示UI窗體

        ///</summary>

        ///<param name="strUIFormName">UI窗體的名稱</param>

        publicvoid ShowUIForms(stringstrUIFormName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

 

            //參數檢查

            if(string.IsNullOrEmpty(strUIFormName)) return;

 

            //加載「UI窗體名稱」,到「全部UI窗體緩存」中

            baseUIForms =LoadUIFormsToAllUIFormsCatch(strUIFormName);

            if(baseUIForms == null) return;

 

            //判斷是否清空「棧」結構體集合

            if(baseUIForms.CurrentUIType.IsClearReverseChange)

            {

                ClearStackArray();

            }

 

            //判斷不一樣的窗體顯示模式,分別進行處理

            switch(baseUIForms.CurrentUIType.UIForms_ShowMode)

            {

                caseUIFormsShowMode.Normal:

                   EnterUIFormsCache(strUIFormName);

                    break;

                caseUIFormsShowMode.ReverseChange:

                    PushUIForms(strUIFormName);

                    break;

                caseUIFormsShowMode.HideOther:

                   EnterUIFormstToCacheHideOther(strUIFormName);

                    break;

                default:

                    break;

            }

        }

 

        ///<summary>

        ///關閉或返回上一個UI窗體(關閉當前UI窗體)

        ///</summary>

        publicvoid CloseOrReturnUIForms(stringstrUIFormName)

        {

            BaseUIFormsbaseUIForms = null;                   //UI窗體基類

 

            /* 參數檢查 */

            if(string.IsNullOrEmpty(strUIFormName)) return;

            //「全部UI窗體緩存」若是沒有記錄,則直接返回。

           _DicALLUIForms.TryGetValue(strUIFormName, outbaseUIForms);

            if(baseUIForms == null) return;

 

            /* 判斷不一樣的窗體顯示模式,分別進行處理 */

            switch(baseUIForms.CurrentUIType.UIForms_ShowMode)

            {

                caseUIFormsShowMode.Normal:

                   ExitUIFormsCache(strUIFormName);

                    break;

                caseUIFormsShowMode.ReverseChange:

                    PopUIForms();

                    break;

                caseUIFormsShowMode.HideOther:

                   ExitUIFormsFromCacheAndShowOther(strUIFormName);

                    break;

                default:

                    break;

            }

 

       }

 

        #region私有方法

        ///<summary>

        ///根據指定UI窗體名稱,加載到「全部UI窗體」緩存中。

        ///</summary>

        ///<param name="strUIFormName">UI窗體名稱</param>

        ///<returns></returns>

        privateBaseUIForms LoadUIFormsToAllUIFormsCatch(stringstrUIFormName)

        {

            BaseUIFormsbaseUI;                             //UI窗體

 

            //判斷「UI預設緩存集合」是否有指定的UI窗體,不然新加載窗體

           _DicALLUIForms.TryGetValue(strUIFormName, outbaseUI);

            if(baseUI == null)

            {

                //加載指定路徑的「UI窗體」

                baseUI =LoadUIForms(strUIFormName);

            }

 

            returnbaseUI;

        }

 

        ///<summary>

        ///加載UI窗體到「當前顯示窗體集合」緩存中。

        ///</summary>

        ///<param name="strUIFormsName"></param>

        privatevoid EnterUIFormsCache(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

            BaseUIFormsbaseUIFormsFromAllCache;            //"全部窗體集合"中的窗體基類

 

            //「正在顯示UI窗體緩存」集合裏有記錄,則直接返回。

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms != null) return;

 

            //把當前窗體,加載到「正在顯示UI窗體緩存」集合裏

           _DicALLUIForms.TryGetValue(strUIFormsName, outbaseUIFormsFromAllCache);

            if(baseUIFormsFromAllCache != null)

            {

               _DicCurrentShowUIForms.Add(strUIFormsName, baseUIFormsFromAllCache);

               baseUIFormsFromAllCache.Display();

            }

        }

 

        ///<summary>

        ///卸載UI窗體從「當前顯示窗體集合」緩存中。

        ///</summary>

        ///<paramname="strUIFormsName"></param>

        privatevoid ExitUIFormsCache(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

 

            //「正在顯示UI窗體緩存」集合沒有記錄,則直接返回。

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms == null) return;

 

            //指定UI窗體,運行隱藏狀態,且從「正在顯示UI窗體緩存」集合中移除。

            baseUIForms.Hiding();

           _DicCurrentShowUIForms.Remove(strUIFormsName);

        }

 

        ///<summary>

        ///加載UI窗體到「當前顯示窗體集合」緩存中,且隱藏其餘正在顯示的頁面

        ///</summary>

        ///<paramname="strUIFormsName"></param>

        privatevoid EnterUIFormstToCacheHideOther(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

            BaseUIFormsbaseUIFormsFromAllCache;            //"全部窗體集合"中的窗體基類

 

            //「正在顯示UI窗體緩存」集合裏有記錄,則直接返回。

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms != null) return;

 

            //「正在顯示UI窗體緩存」與「棧緩存」集合裏全部窗體進行隱藏處理。

            foreach(BaseUIForms baseUIFormsItem in_DicCurrentShowUIForms.Values)

            {

                baseUIFormsItem.Hiding();

            }

            foreach(BaseUIForms basUIFormsItem in_StaCurrentUIForms)

            {

                basUIFormsItem.Hiding();

            }

 

            //把當前窗體,加載到「正在顯示UI窗體緩存」集合裏

           _DicALLUIForms.TryGetValue(strUIFormsName,out baseUIFormsFromAllCache);

            if(baseUIFormsFromAllCache != null)

            {

               _DicCurrentShowUIForms.Add(strUIFormsName, baseUIFormsFromAllCache);

                baseUIFormsFromAllCache.Display();

            }

        }

 

        ///<summary>

        ///卸載UI窗體從「當前顯示窗體集合」緩存中,且顯示其餘本來須要顯示的頁面

        ///</summary>

        ///<paramname="strUIFormsName"></param>

        privatevoidExitUIFormsFromCacheAndShowOther(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

 

            //「正在顯示UI窗體緩存」集合沒有記錄,則直接返回。

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms == null) return;

 

            //指定UI窗體,運行隱藏狀態,且從「正在顯示UI窗體緩存」集合中移除。

            baseUIForms.Hiding();

           _DicCurrentShowUIForms.Remove(strUIFormsName);

 

            //「正在顯示UI窗體緩存」與「棧緩存」集合裏全部窗體進行再次顯示處理。

            foreach(BaseUIForms baseUIFormsItem in_DicCurrentShowUIForms.Values)

            {

                baseUIFormsItem.Redisplay();

            }

            foreach(BaseUIForms basUIFormsItem in_StaCurrentUIForms)

            {

                basUIFormsItem.Redisplay();

            }

        }

 

       ///<summary>

        ///UI窗體入棧

        ///功能1: 判斷棧裏是否已經有窗體,有則「凍結」

        ///     2: 先判斷「UI預設緩存集合」是否有指定的UI窗體,有則處理。

        ///     3: 指定UI窗體入"棧"

        ///</summary>

        ///<paramname="strUIFormsName"></param>

        privatevoid PushUIForms(stringstrUIFormsName)

        {

            BaseUIFormsbaseUI;                             //UI預設窗體

 

 

            //判斷棧裏是否已經有窗體,有則「凍結」

            if(_StaCurrentUIForms.Count > 0)

            {

                BaseUIFormstopUIForms = _StaCurrentUIForms.Peek();

                topUIForms.Freeze();

            }

 

            //先判斷「UI預設緩存集合」是否有指定的UI窗體,有則處理。

           _DicALLUIForms.TryGetValue(strUIFormsName, outbaseUI);

            if(baseUI != null)

            {

                baseUI.Display();

            }

            else

            {

                Log.Write(GetType()+ string.Format("/PushUIForms()/ baseUI==null! 核心錯誤,請檢查strUIFormsName={0}", strUIFormsName), Log.Level.High);

            }

 

            //指定UI窗體入"棧"

            _StaCurrentUIForms.Push(baseUI);

        }

 

        ///<summary>

        ///UI窗體出棧邏輯

        ///</summary>

        privatevoid PopUIForms()

        {

            if(_StaCurrentUIForms.Count >= 2)

            {

                /* 出棧邏輯 */

                BaseUIFormstopUIForms = _StaCurrentUIForms.Pop();

                //出棧的窗體,進行隱藏處理

                topUIForms.Hiding();

                //出棧窗體的下一個窗體邏輯

                BaseUIFormsnextUIForms = _StaCurrentUIForms.Peek();

                //下一個窗體"從新顯示"處理

                nextUIForms.Redisplay();

            }

            elseif (_StaCurrentUIForms.Count == 1)

            {

                /* 出棧邏輯 */

                BaseUIFormstopUIForms = _StaCurrentUIForms.Pop();

                //出棧的窗體,進行"隱藏"處理

                topUIForms.Hiding();

            }

        }

 

        ///<summary>

        ///加載與顯示UI窗體

        ///功能:

        ///    1:根據「UI窗體預設」名稱,加載預設克隆體。

        ///    2:預設克隆體添加UI「根節點」爲父節點。

        ///    3:隱藏剛建立的UI克隆體。

        ///    4:新建立的「UI窗體」,加入「UI窗體緩存」中

        ///</summary>

        privateBaseUIForms LoadUIForms(stringstrUIFormsName)

        {

            stringstrUIFormsPaths = null;                  //UI窗體的路徑

            GameObjectgoCloneUIPrefab = null;              //克隆的"窗體預設"

           BaseUIFormsbaseUIForm;                         //UI窗體

 

 

            //獲得UI窗體的路徑

           _DicUIFormsPaths.TryGetValue(strUIFormsName, outstrUIFormsPaths);

 

            //加載指定路徑的「UI窗體」

            if(!string.IsNullOrEmpty(strUIFormsPaths))

           {

                goCloneUIPrefab = ResourcesMgr.GetInstance().LoadAsset(strUIFormsPaths,false);

            }

 

            //設置「UI窗體」克隆體的父節點,以及隱藏處理與加入「UI窗體緩存」中

            if(_CanvasTransform != null&& goCloneUIPrefab != null)

            {

               baseUIForm = goCloneUIPrefab.GetComponent<BaseUIForms>();

                if(baseUIForm == null)

                {

                    Log.Write(GetType()+ string.Format("/LoadUIForms()/ baseUIForm==null!,請先確認克隆對象上是否加載了BaseUIForms的子類。參數 strUIFormsName='{0}' ", strUIFormsName), Log.Level.High);

                    returnnull;

                }

                switch(baseUIForm.CurrentUIType.UIForms_Type)

                {

                    caseUIFormsType.Normal:

                        goCloneUIPrefab.transform.SetParent(_CanTransformNormal,false);

                        break;

                    caseUIFormsType.Fixed:

                       goCloneUIPrefab.transform.SetParent(_CanTransformFixed, false);

                        break;

                    caseUIFormsType.PopUp:

                       goCloneUIPrefab.transform.SetParent(_CanTransformPopUp, false);

                        break;

                    default:

                        break;

                }

 

               goCloneUIPrefab.SetActive(false);

                //新建立的「UI窗體」,加入「UI窗體緩存」中

               _DicALLUIForms.Add(strUIFormsName, baseUIForm);

                returnbaseUIForm;

            }

            else

            {

                Log.Write(GetType()+ string.Format("/LoadUIForms()/‘_CanvasTransform’ Or ‘goCloneUIPrefab’==NULL!  , 方法參數strUIFormsName={0},請檢查!", strUIFormsName), Log.Level.High);

            }

 

            Log.Write(GetType()+ string.Format("/LoadUIForms()/ 出現不可預知錯誤,請檢查! 方法參數strUIFormsName={0}", strUIFormsName), Log.Level.High);

            returnnull;

        }

 

        ///<summary>

        ///初始化項目開始必須的資源加載

        ///</summary>

        privatevoid InitRootCanvasLoading()

        {

            if(UnityHelper.isFirstLoad)

            {

                ResourcesMgr.GetInstance().LoadAsset(SysDefine.SYS_PATH_CANVAS, false);

            }

        }

 

        ///<summary>

        ///初始化「UI窗體預設」路徑數據

        ///</summary>

        privatevoid InitUIFormsPathsData()

        {

            //測試也成功

            IConfigManagerconfigMgr = newConfigManagerByJson(SysDefine.SYS_PATH_UIFormConfigJson);

            if(_DicUIFormsPaths != null)

            {

                _DicUIFormsPaths =configMgr.AppSetting;

            }

        }

 

        ///<summary>

        ///清空「棧」結構體集合

        ///</summary>

        ///<returns></returns>

        privatebool ClearStackArray()

        {

            if(_StaCurrentUIForms != null&& _StaCurrentUIForms.Count >= 1)

            {

                _StaCurrentUIForms.Clear();

                returntrue;

            }

            returnfalse;

        }

 

        #endregion

 

   }//Class_end

}


以上代碼解釋:

    1: UIManager.cs  中定義的新的字段 ,「_StaCurrentUIForms」 就是一個「棧」數據類型,用於維護一種後進先出的數據結構。常見的方法以下:

      C#語言中提供 Stack<T> 泛型集合,來直接實現這種結構。
經常使用屬性與方法:

  •  Count 屬性  查詢棧內元素數量

  •  Push()      壓棧

  •  Pop()       出棧

  •  Peek()      查詢棧頂元素

  •  GetEnumerator() 遍歷棧中全部元素


   2: UIManager.cs 中的「ShowUIForms()」方法中的PushUIForms()與EnterUIFormstToCacheHideOther() 方法,就是專門處理「反向切換」與「隱藏其餘」窗體特性的實現方法。


    好了時間不早了就先寫到這吧,你們有什麼疑問能夠討論,這裏筆者也主要是想起到「拋磚引玉」的做用。


本篇就先寫到這,下篇 "遊戲UI框架設計(4)_模態窗體管理" 繼續。

相關文章
相關標籤/搜索