Unity基于UGUI的UI框架

首先

想想我为什么要用UI框架,因为不用UI框架会导致游戏混乱,管理困难?

那么体现在什么方面呢?

一般在设计游戏的时候,会对各个UI面板进行相应的管理,保证同一时间,玩家只对一个UI面板进行操作,保证不会因为玩家乱点,而导致玩家不知道哪个是哪个,或者哪个在哪,还有就是说,让玩家需要哪个UI面板,玩家点击哪个面板的时候再进行相应的实例化加载,不是一股脑的上来全加载出来,等着玩家点按钮调用,那样性能上受不了。

再来想,在UGUI下,UIA和UIB堆在一起谁能显示出来?谁会被覆盖?这个取决于他们在Hierarchy面板的顺序,谁在下面,谁就能被看到,而另一个则会被这一个给覆盖住,而显示不出来。我每实例化出来一个UI面板,都会相应的覆盖住上一个UI面板,然后,当我不用这个UI面板的时候怎么办?我能想到的有三种选择,一个是移动到屏幕显示的外边,让玩家看不到它。二是直接销毁它。三是使用我们的UI框架的栈思想。

但是,第一个会存在什么问题,UI面板的显示完全依赖于Hierarchy面板的顺序,也就是说,每次游戏过程中,这些UI面板谁能遮挡住谁,是根据玩家点击顺序决定的,如果在允许玩家不关上当前窗口的时候进行其他操作的话,玩家夸夸夸的连续点击其他的UI面板,然后再跳出一堆其他的窗口,玩家再想在这些窗口里找到它想要的窗口的话,是非常困难的,因为实例化的顺序不一样,你得按照最上面的那个面板是啥,得一个个对应着关了,才能找到玩家想要的那个面板,再进行操作,当然如果能做好相应的措施还行,不过这么做在UI面板多的情况下,真的会很麻烦。

第二个则不会出现这种问题,但是第二个带来的问题是卡顿,玩过王者荣耀的应该知道,你再大厅界面,点击背包,如果你手机配置很高,则不会那么明显,这里说一般手机,当你刚刚打开游戏,点击背包按钮的时候,你的手机极有可能会顿那么一点几秒,这个过程就是在实例化背包的面板,但是当你关闭了背包之后,再打开,为什么就不卡了?因为背包面板已经被实例化出来了,你刚才将他关闭只是隐藏了它而已。但是如果王者荣耀采用第二种方式呢?当你需要频繁操作某个有很多数据的UI的时候,普通手机的体验会真的很不好。

第三个就牛逼多了。因为加入了类Windows的模态窗口的约束,所以不依赖于Hierarchy面板的顺序,该怎么显示就怎么显示,根据所需实例化所需UI面板,然后需要显示就入栈,需要隐藏就依次出栈,而这些只需要在框架搭好后的几句代码,即可实现,而且只在需要的时候加载对应的UI面板,并存起来,需要的时候再让它显示出来,不浪费性能。

 

UI框架的思想: 

           和栈的思想基本相同,在开发Winform程序和MFC程序的时候,肯定遇到过模态窗口和非模态窗口这个概念,

           定义:对话框分为模态对话框和非模态对话框两种。二者的区别在于当对话框打开时,是否允许用户进行其他对象的操作。

草图构思:

 

也是就说要实现下面这样的功能:

当我点击一个按钮,出现对应模块的时候,我必须关闭这个模块,才能对其他的模块进行操作。

也就是先进后出,我必须倒序的关闭我打开的一切窗口,才能对其他模块进行操作。也就是不断的进行Push操作和Pop操作。

 下面来看下代码实现:

这个是UIManager类 ,整个框架的核心,包含了读取Json数据,到实例化UI面板,再到隐藏UI面板的一切功能。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;
using System;
/*
*作者:琦玉老师的二弟子
*/
namespace JumpAgent
{
    public class UIManager
    {
        private GameObject ShowCanvas;
        /// <summary>
        /// 单例模式
        /// </summary>
        private static UIManager _instance;
        /// <summary>
        /// 存储所有UI面板的路径的字典
        /// </summary>
        private Dictionary<UIPanelType, string> panelPathDict;
        /// <summary>
        /// 保存所有实例化出来的UI面板游戏物体身上的BasePanel组件
        /// </summary>
        private Dictionary<UIPanelType, BasePanel> panelDict;
        /// <summary>
        /// UI面板栈,所有入栈的都是显示出来的
        /// </summary>
        private Stack<BasePanel> panelStack;
        /// <summary>
        /// 构造方法,读取数据
        /// </summary>
        private UIManager()
        {
            ShowCanvas = GameObject.Find("Canvas");
            ParseUIPanelTypeJson();
        }
        /// <summary>
        /// 取得单例
        /// </summary>
        public static UIManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UIManager();
                }
                return _instance;
            }
        }
        /// <summary>
        /// 把Json转化成数据
        /// </summary>
        private void ParseUIPanelTypeJson()
        {
            //初始化UI面板字典
            panelPathDict = new Dictionary<UIPanelType, string>();
            //加载Json文件
            TextAsset ta = Resources.Load<TextAsset>("UIPanelType");
            //取得Json数据转换成的对象,存到集合里面
            List<UIPanleInfo> panleInfoList = JsonMapper.ToObject<List<UIPanleInfo>>(ta.text);
            //把集合里的对象存到UIPanel的字典里
            foreach (UIPanleInfo info in panleInfoList)
            {
                panelPathDict.Add(info.panelType, info.path);
            }
        }
        /// <summary>
        /// 得到一个UI面板,如果该UI面板没有被实例化过,则创建
        /// </summary>
        /// <param name="panelType"></param>
        public BasePanel GetUIPanel(UIPanelType panelType)
        {
            if (panelDict==null)
            {
                panelDict = new Dictionary<UIPanelType, BasePanel>();
            }
            //BasePanel basePanel;
            //panelDict.TryGetValue(panelType, out basePanel);
            //扩展方法
            BasePanel basePanel = panelDict.TryGet(panelType);

            if (basePanel==null)
            {
                string path;
                panelPathDict.TryGetValue(panelType, out path);
                GameObject InsPanel=(GameObject)GameObject.Instantiate(Resources.Load(path));
                InsPanel.transform.SetParent(ShowCanvas.gameObject.transform,false);
                panelDict.Add(panelType, InsPanel.GetComponent<BasePanel>());
                return InsPanel.GetComponent<BasePanel>();
            }
            else
            {
                return basePanel;
            }

        }

        /// <summary>
        /// 入栈,把某个页面显示在界面上
        /// </summary>
        public void PushPanel(UIPanelType panelType)
        {
            if (panelStack==null)
            {
                panelStack = new Stack<BasePanel>();
            }

            if (panelStack.Count>0)
            {
                BasePanel topPanel = panelStack.Peek();
                topPanel.OnPause();
            }


            BasePanel panel = GetUIPanel(panelType);
            panel.OnEnter();
            panelStack.Push(panel);
        }
        /// <summary>
        /// 出栈,把某个页面从界面上移除
        /// </summary>
        public void PopPanel()
        {
            if (panelStack == null)
            {
                panelStack = new Stack<BasePanel>();
            }
            if (panelStack.Count==0)
            {
                return;
            }
            //关闭栈顶页面的显示
            BasePanel topPanel = panelStack.Pop();
            topPanel.OnExit();
            if (panelStack.Count != 0)
            {
                BasePanel nextPanel = panelStack.Peek();
                nextPanel.OnResume();
            }
        }


        /// <summary>
        /// 测试方法
        /// </summary>
        public void Test()
        {
            foreach (var item in panelPathDict)
            {
                Debug.Log("Panel类型为:" + item.Key + "__路径为:" + item.Value);
            }
        }

    }//类

}//命名空间

再然后是所有BasePanel,即所有UI面板的基类:继承这个基类的子类UI面板需要重写里面的这四个虚方法,以供我们的UIManager调用。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
/*
作者:琦玉老师的二弟子
*/
namespace JumpAgent{

public class BasePanel : MonoBehaviour
{
        /// <summary>
        /// 显示界面
        /// </summary>
        public virtual void OnEnter()
        {

        }
        /// <summary>
        /// 界面暂停
        /// </summary>
        public virtual void OnPause()
        {

        }
        /// <summary>
        /// 界面继续
        /// </summary>
        public virtual void OnResume()
        {

        }
        /// <summary>
        /// 界面推出
        /// </summary>
        public virtual void OnExit()
        {

        }

}//类

}//命名空间

 

  • 7
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值