溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

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

發(fā)布時間:2020-07-08 22:19:31 來源:網(wǎng)絡(luò) 閱讀:3489 作者:Liu_guozhu 欄目:開發(fā)技術(shù)

游戲UI框架設(shè)計(三)

---窗體的層級管理


  UI框架中UI窗體的“層級管理”,最核心的問題是如何進行窗體的顯示管理。窗體(預(yù)設(shè))的顯示我們前面定義了三種類型: 普通、隱藏其他、反向切換。代碼如下:

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

    

    “普通顯示”模式允許多個窗體同時顯示,這種類型應(yīng)用最多。例如RPG中的主城界面(見下圖)。

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


    “隱藏其他界面” 模式一般應(yīng)用于全局性的窗體。我們在開發(fā)此類窗體時,為了減少UI渲染壓力、提高Unity渲染效率,則設(shè)置被覆蓋的窗體為“不可見”狀態(tài)。(即: this.gameObject.SetActive(false))。例如一般的登錄窗體、選擇英雄窗體等。

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


  “反向切換”模式類型,一般都大量引用于“彈出窗體”中。此類窗體的特點是:顯示彈出窗體時不完全覆蓋底層窗體,一般在屏幕的四周會露出底層窗體。之所以命名“反向切換”是因為: 程序員要維護一種“后進先出”的“?!钡臄?shù)據(jù)結(jié)構(gòu)特點,即我們一般要求玩家必須先關(guān)閉彈出的頂層窗體,再依次關(guān)閉下一級窗體。如下圖所示。

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


  上圖即一種典型的彈出窗體。一般我們都要求玩家先處理彈出窗體中的信息,然后關(guān)閉此窗體。一般不允許在沒有關(guān)閉子窗體的情況下,直接點擊父窗體。(關(guān)于彈出窗體時,不允許玩家點擊父窗體的功能實現(xiàn),筆者在下節(jié)[“模態(tài)窗體管理”]一章著重講解)。

  以上說了這么多了,我們對于“層級管理”的核心代碼實現(xiàn),基本都體現(xiàn)在“UI管理器腳本” (UIManager.cs )中。以下給出具體實現(xiàn)代碼:


/***

 *   Title: "SUIFW" 框架技術(shù)

 *          主題: UI管理器    

 *   Description:

 *          功能:整個UI框架的核心,用戶程序通過調(diào)用本類,來調(diào)用本框架的大多數(shù)功能。 

 *          功能1:關(guān)于入“棧”與出“?!钡腢I窗體4個狀態(tài)的定義邏輯

 *                 入棧狀態(tài):

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

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

 *                 出棧狀態(tài):

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

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

 *         功能2:增加“非?!本彺婕稀?

 */

using UnityEngine;

usingUnityEngine.UI;

using System;

usingSystem.Collections.Generic;

 

namespace SUIFW

{

   publicclassUIManager : MonoBehaviour

   {

        /* 字段  */

        //本類實例

        privatestaticUIManager_Instance = null;

        //存儲所有“UI窗體預(yù)設(shè)(Prefab)”路徑

        //參數(shù)含義: 第1個string 表示“窗體預(yù)設(shè)”名稱,后一個string 表示對應(yīng)的路徑

        privateDictionary<string,string> _DicUIFormsPaths;

        //緩存所有已經(jīng)打開的“UI窗體預(yù)設(shè)(Prefab)”

        //參數(shù)含義: 第1個string 表示“窗體預(yù)設(shè)”名稱,后一個BaseUI 表示對應(yīng)的“窗體預(yù)設(shè)”

        privateDictionary<string,BaseUIForms> _DicALLUIForms;

        //“?!苯Y(jié)構(gòu)表示的“當(dāng)前UI窗體”集合。

        privateStack<BaseUIForms>_StaCurrentUIForms;

        //當(dāng)前顯示狀態(tài)的UI窗體集合

        privateDictionary<string,BaseUIForms> _DicCurrentShowUIForms;

        //UI根節(jié)點

        privateTransform _CanvasTransform = null;

        //普通全屏界面節(jié)點

        privateTransform _CanTransformNormal = null;

        //固定界面節(jié)點

        privateTransform _CanTransformFixed = null;

        //彈出模式節(jié)點

        privateTransform _CanTransformPopUp = null;

        //UI腳本節(jié)點(加載各種管理腳本的節(jié)點)

        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根節(jié)點、及其重要子節(jié)點                    

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

            //得到普通全屏界面節(jié)點、固定界面節(jié)點、彈出模式節(jié)點、UI腳本節(jié)點

            _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的子節(jié)點

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

 

            //本UI節(jié)點信息,場景轉(zhuǎn)換時,不允許銷毀

           DontDestroyOnLoad(_CanvasTransform);

            //初始化“UI窗體預(yù)設(shè)”路徑數(shù)據(jù)

            InitUIFormsPathsData();

        }

 

        ///<summary>

        ///顯示UI窗體

        ///</summary>

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

        publicvoid ShowUIForms(stringstrUIFormName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

 

            //參數(shù)檢查

            if(string.IsNullOrEmpty(strUIFormName)) return;

 

            //加載“UI窗體名稱”,到“所有UI窗體緩存”中

            baseUIForms =LoadUIFormsToAllUIFormsCatch(strUIFormName);

            if(baseUIForms == null) return;

 

            //判斷是否清空“?!苯Y(jié)構(gòu)體集合

            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>

        ///關(guān)閉或返回上一個UI窗體(關(guān)閉當(dāng)前UI窗體)

        ///</summary>

        publicvoid CloseOrReturnUIForms(stringstrUIFormName)

        {

            BaseUIFormsbaseUIForms = null;                   //UI窗體基類

 

            /* 參數(shù)檢查 */

            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>

        ///根據(jù)指定UI窗體名稱,加載到“所有UI窗體”緩存中。

        ///</summary>

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

        ///<returns></returns>

        privateBaseUIForms LoadUIFormsToAllUIFormsCatch(stringstrUIFormName)

        {

            BaseUIFormsbaseUI;                             //UI窗體

 

            //判斷“UI預(yù)設(shè)緩存集合”是否有指定的UI窗體,否則新加載窗體

           _DicALLUIForms.TryGetValue(strUIFormName, outbaseUI);

            if(baseUI == null)

            {

                //加載指定路徑的“UI窗體”

                baseUI =LoadUIForms(strUIFormName);

            }

 

            returnbaseUI;

        }

 

        ///<summary>

        ///加載UI窗體到“當(dāng)前顯示窗體集合”緩存中。

        ///</summary>

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

        privatevoid EnterUIFormsCache(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

            BaseUIFormsbaseUIFormsFromAllCache;            //"所有窗體集合"中的窗體基類

 

            //“正在顯示UI窗體緩存”集合里有記錄,則直接返回。

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms != null) return;

 

            //把當(dāng)前窗體,加載到“正在顯示UI窗體緩存”集合里

           _DicALLUIForms.TryGetValue(strUIFormsName, outbaseUIFormsFromAllCache);

            if(baseUIFormsFromAllCache != null)

            {

               _DicCurrentShowUIForms.Add(strUIFormsName, baseUIFormsFromAllCache);

               baseUIFormsFromAllCache.Display();

            }

        }

 

        ///<summary>

        ///卸載UI窗體從“當(dāng)前顯示窗體集合”緩存中。

        ///</summary>

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

        privatevoid ExitUIFormsCache(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

 

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

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms == null) return;

 

            //指定UI窗體,運行隱藏狀態(tài),且從“正在顯示UI窗體緩存”集合中移除。

            baseUIForms.Hiding();

           _DicCurrentShowUIForms.Remove(strUIFormsName);

        }

 

        ///<summary>

        ///加載UI窗體到“當(dāng)前顯示窗體集合”緩存中,且隱藏其他正在顯示的頁面

        ///</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();

            }

 

            //把當(dāng)前窗體,加載到“正在顯示UI窗體緩存”集合里

           _DicALLUIForms.TryGetValue(strUIFormsName,out baseUIFormsFromAllCache);

            if(baseUIFormsFromAllCache != null)

            {

               _DicCurrentShowUIForms.Add(strUIFormsName, baseUIFormsFromAllCache);

                baseUIFormsFromAllCache.Display();

            }

        }

 

        ///<summary>

        ///卸載UI窗體從“當(dāng)前顯示窗體集合”緩存中,且顯示其他原本需要顯示的頁面

        ///</summary>

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

        privatevoidExitUIFormsFromCacheAndShowOther(stringstrUIFormsName)

        {

            BaseUIFormsbaseUIForms;                        //UI窗體基類

 

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

           _DicCurrentShowUIForms.TryGetValue(strUIFormsName, outbaseUIForms);

            if(baseUIForms == null) return;

 

            //指定UI窗體,運行隱藏狀態(tài),且從“正在顯示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: 判斷棧里是否已經(jīng)有窗體,有則“凍結(jié)”

        ///     2: 先判斷“UI預(yù)設(shè)緩存集合”是否有指定的UI窗體,有則處理。

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

        ///</summary>

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

        privatevoid PushUIForms(stringstrUIFormsName)

        {

            BaseUIFormsbaseUI;                             //UI預(yù)設(shè)窗體

 

 

            //判斷棧里是否已經(jīng)有窗體,有則“凍結(jié)”

            if(_StaCurrentUIForms.Count > 0)

            {

                BaseUIFormstopUIForms = _StaCurrentUIForms.Peek();

                topUIForms.Freeze();

            }

 

            //先判斷“UI預(yù)設(shè)緩存集合”是否有指定的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:根據(jù)“UI窗體預(yù)設(shè)”名稱,加載預(yù)設(shè)克隆體。

        ///    2:預(yù)設(shè)克隆體添加UI“根節(jié)點”為父節(jié)點。

        ///    3:隱藏剛創(chuàng)建的UI克隆體。

        ///    4:新創(chuàng)建的“UI窗體”,加入“UI窗體緩存”中

        ///</summary>

        privateBaseUIForms LoadUIForms(stringstrUIFormsName)

        {

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

            GameObjectgoCloneUIPrefab = null;              //克隆的"窗體預(yù)設(shè)"

           BaseUIFormsbaseUIForm;                         //UI窗體

 

 

            //得到UI窗體的路徑

           _DicUIFormsPaths.TryGetValue(strUIFormsName, outstrUIFormsPaths);

 

            //加載指定路徑的“UI窗體”

            if(!string.IsNullOrEmpty(strUIFormsPaths))

           {

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

            }

 

            //設(shè)置“UI窗體”克隆體的父節(jié)點,以及隱藏處理與加入“UI窗體緩存”中

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

            {

               baseUIForm = goCloneUIPrefab.GetComponent<BaseUIForms>();

                if(baseUIForm == null)

                {

                    Log.Write(GetType()+ string.Format("/LoadUIForms()/ baseUIForm==null!,請先確認(rèn)克隆對象上是否加載了BaseUIForms的子類。參數(shù) 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);

                //新創(chuàng)建的“UI窗體”,加入“UI窗體緩存”中

               _DicALLUIForms.Add(strUIFormsName, baseUIForm);

                returnbaseUIForm;

            }

            else

            {

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

            }

 

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

            returnnull;

        }

 

        ///<summary>

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

        ///</summary>

        privatevoid InitRootCanvasLoading()

        {

            if(UnityHelper.isFirstLoad)

            {

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

            }

        }

 

        ///<summary>

        ///初始化“UI窗體預(yù)設(shè)”路徑數(shù)據(jù)

        ///</summary>

        privatevoid InitUIFormsPathsData()

        {

            //測試也成功

            IConfigManagerconfigMgr = newConfigManagerByJson(SysDefine.SYS_PATH_UIFormConfigJson);

            if(_DicUIFormsPaths != null)

            {

                _DicUIFormsPaths =configMgr.AppSetting;

            }

        }

 

        ///<summary>

        ///清空“棧”結(jié)構(gòu)體集合

        ///</summary>

        ///<returns></returns>

        privatebool ClearStackArray()

        {

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

            {

                _StaCurrentUIForms.Clear();

                returntrue;

            }

            returnfalse;

        }

 

        #endregion

 

   }//Class_end

}


以上代碼解釋:

    1: UIManager.cs  中定義的新的字段 ,“_StaCurrentUIForms” 就是一個“棧”數(shù)據(jù)類型,用于維護一種后進先出的數(shù)據(jù)結(jié)構(gòu)。常見的方法如下:

      C#語言中提供 Stack<T> 泛型集合,來直接實現(xiàn)這種結(jié)構(gòu)。
常用屬性與方法:

  •  Count 屬性  查詢棧內(nèi)元素數(shù)量

  •  Push()      壓棧

  •  Pop()       出棧

  •  Peek()      查詢棧頂元素

  •  GetEnumerator() 遍歷棧中所有元素


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


    好了時間不早了就先寫到這吧,大家有什么疑問可以討論,這里筆者也主要是想起到“拋磚引玉”的作用。


本篇就先寫到這,下篇 "游戲UI框架設(shè)計(4)_模態(tài)窗體管理" 繼續(xù)。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI