赞
踩
想想我为什么要用UI框架,因为不用UI框架会导致游戏混乱,管理困难?
那么体现在什么方面呢?
一般在设计游戏的时候,会对各个UI面板进行相应的管理,保证同一时间,玩家只对一个UI面板进行操作,保证不会因为玩家乱点,而导致玩家不知道哪个是哪个,或者哪个在哪,还有就是说,让玩家需要哪个UI面板,玩家点击哪个面板的时候再进行相应的实例化加载,不是一股脑的上来全加载出来,等着玩家点按钮调用,那样性能上受不了。
再来想,在UGUI下,UIA和UIB堆在一起谁能显示出来?谁会被覆盖?这个取决于他们在Hierarchy面板的顺序,谁在下面,谁就能被看到,而另一个则会被这一个给覆盖住,而显示不出来。我每实例化出来一个UI面板,都会相应的覆盖住上一个UI面板,然后,当我不用这个UI面板的时候怎么办?我能想到的有三种选择,一个是移动到屏幕显示的外边,让玩家看不到它。二是直接销毁它。三是使用我们的UI框架的栈思想。
但是,第一个会存在什么问题,UI面板的显示完全依赖于Hierarchy面板的顺序,也就是说,每次游戏过程中,这些UI面板谁能遮挡住谁,是根据玩家点击顺序决定的,如果在允许玩家不关上当前窗口的时候进行其他操作的话,玩家夸夸夸的连续点击其他的UI面板,然后再跳出一堆其他的窗口,玩家再想在这些窗口里找到它想要的窗口的话,是非常困难的,因为实例化的顺序不一样,你得按照最上面的那个面板是啥,得一个个对应着关了,才能找到玩家想要的那个面板,再进行操作,当然如果能做好相应的措施还行,不过这么做在UI面板多的情况下,真的会很麻烦。
第二个则不会出现这种问题,但是第二个带来的问题是卡顿,玩过王者荣耀的应该知道,你再大厅界面,点击背包,如果你手机配置很高,则不会那么明显,这里说一般手机,当你刚刚打开游戏,点击背包按钮的时候,你的手机极有可能会顿那么一点几秒,这个过程就是在实例化背包的面板,但是当你关闭了背包之后,再打开,为什么就不卡了?因为背包面板已经被实例化出来了,你刚才将他关闭只是隐藏了它而已。但是如果王者荣耀采用第二种方式呢?当你需要频繁操作某个有很多数据的UI的时候,普通手机的体验会真的很不好。
第三个就牛逼多了。因为加入了类Windows的模态窗口的约束,所以不依赖于Hierarchy面板的顺序,该怎么显示就怎么显示,根据所需实例化所需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()
- {
-
- }
-
- }//类
-
- }//命名空间
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。