您好,登錄后才能下訂單哦!
游戲UI框架設計(三)
---窗體的層級管理
UI框架中UI窗體的“層級管理”,最核心的問題是如何進行窗體的顯示管理。窗體(預設)的顯示我們前面定義了三種類型: 普通、隱藏其他、反向切換。代碼如下:
“普通顯示”模式允許多個窗體同時顯示,這種類型應用最多。例如RPG中的主城界面(見下圖)。
“隱藏其他界面” 模式一般應用于全局性的窗體。我們在開發此類窗體時,為了減少UI渲染壓力、提高Unity渲染效率,則設置被覆蓋的窗體為“不可見”狀態。(即: this.gameObject.SetActive(false))。例如一般的登錄窗體、選擇英雄窗體等。
“反向切換”模式類型,一般都大量引用于“彈出窗體”中。此類窗體的特點是:顯示彈出窗體時不完全覆蓋底層窗體,一般在屏幕的四周會露出底層窗體。之所以命名“反向切換”是因為: 程序員要維護一種“后進先出”的“棧”的數據結構特點,即我們一般要求玩家必須先關閉彈出的頂層窗體,再依次關閉下一級窗體。如下圖所示。
上圖即一種典型的彈出窗體。一般我們都要求玩家先處理彈出窗體中的信息,然后關閉此窗體。一般不允許在沒有關閉子窗體的情況下,直接點擊父窗體。(關于彈出窗體時,不允許玩家點擊父窗體的功能實現,筆者在下節[“模態窗體管理”]一章著重講解)。
以上說了這么多了,我們對于“層級管理”的核心代碼實現,基本都體現在“UI管理器腳本” (UIManager.cs )中。以下給出具體實現代碼:
/***
* Title: "SUIFW" 框架技術
* 主題: 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)_模態窗體管理" 繼續。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。