游戏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)_模态窗体管理" 继续。

相关文章
相关标签/搜索