UI框架—基于UGUI(学习笔记)

UI框架—基于UGUI

一、需求分析

(一)、需求分析UML图

1、通过UIManger来自作解析json文件。

2、UML各种关系

在这里插入图片描述

二、知识点

(一)、原理知识

1、单例模式

  • 定义一个静态的对象 在外界访问 在内部构造。

  • 构造方法私有化。

     public static UIManager _instance;
    
        public static UIManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UIManager();
                }
                return _instance;
            }
        }
    

(二)、插件知识

1、使用DOTween插件来制作panel出现和现实的动画

  • 导入插件,注意命名空间的引入
  • 其他的根据需求来制作

(三)、操作知识

1、场景的搭建

  • 注意文字格式要设置为跟随屏幕自适应而改变其大小
  • 在这里插入图片描述

(四)、代码相关

1、编写json信息

  • 编写json相关信息

  • 因为使用了unity自带的两个json类来解析json所以要把一个整体包装成另一个整体来读取

  • json信息如下

    {
    "infoList":
    [
    {"panelTypeString":"ItemMessage",
    "path":"UIPanel/ItemMessagePanel"},
    
    {"panelTypeString":"Knapsack",
    "path":"UIPanel/KnapsackPanel"},
    
    {"panelTypeString":"MainMenu",
    "path":"UIPanel/MainMenuPanel"},
    
    {"panelTypeString":"Shop",
    "path":"UIPanel/ShopPanel"},
    
    {"panelTypeString":"Skill",
    "path":"UIPanel/SkillPanel"},
    
    {"panelTypeString":"System",
    "path":"UIPanel/SystemPanel"},
    
    {"panelType":"Task",
    "path":"UIPanel/TaskPanel"}
    ]
    }
    

2、解析json信息

  • 使用unity自带的json解析类来解析

  • 使用两个字典来存储Panel跟路径

     private Dictionary<UIPanelType, string> panelPathDict;//存储所有面板的Prefab的路径
        private Dictionary<UIPanelType, BasePanel> panelDict;//保存所有实例化面板的游戏物体BasePanel组件
        private Stack<BasePanel> panelStack;
    
        [Serializable]
        class UIPanelTypeJson
        {
            public List<UIPanelInfo> infoList;
        }
        /// <summary>
        /// 解析Json信息
        /// </summary>
        private void ParseUIPanelTypeJson()
        {
            panelPathDict = new Dictionary<UIPanelType, string>();
    
            TextAsset ta = Resources.Load<TextAsset>("UIPanelType");
            UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);
            foreach (UIPanelInfo info in jsonObject.infoList)
            {
                panelPathDict.Add(info.panelType,info.path);//保存读取后的名字跟路径
            }
        }
    
    • UIPanelInfo来读取里面的信息
    using System;
    using System.Collections;
    using UnityEngine;
    
    [Serializable]
    public class UIPanelInfo : ISerializationCallbackReceiver
    {
        [NonSerialized] //不进行读取
        public UIPanelType panelType;
        public string panelTypeString;  //用来存储读取json里面的地址字符串
    
        public string path;
        /// <summary>
        /// 实现接口,读取json里面的信息
        /// 反序列化  从文本信息到对象
        /// </summary>
        public void OnAfterDeserialize()
        {
            UIPanelType type = (UIPanelType) System.Enum.Parse(typeof(UIPanelType), panelTypeString);
            panelType = type;
        }
        public void OnBeforeSerialize()
        {
            
        }
    }
    

3、扩展Dictionary类里面的方法

  • 原理:有些类是系统定义好的不能修改其中的东西,只能对其中一些东西进行扩展,向现有类型“添加”方法,而不创建派生类,

  • 扩展类和扩展方法都必须是static的,如果扩展方法该类型中定义的方法具有相同的名字,则扩展方法不会被调用

  • 如果扩展的父类型更改了,扩展方法也失效

    using System.Collections.Generic;
    /// <summary>
    /// 对Dictionary的扩展
    /// 必须是静态方法和静态类
    /// </summary>
    public static class DictionaryExtension
    {
        /// <summary>
        /// 尝试根据key得到value,得到了的话直接返回value,没有得到直接返回null
        /// this Dictionary<Tkey,Tvalue>dict 这个字典表示我们要获取值的字典
        /// </summary>
        /// <typeparam name="Tkey">泛型一</typeparam>
        /// <typeparam name="Tvalue">泛型二</typeparam>
        /// <param name="dict">方法对象</param>
        /// <param name="key">获取的值</param>
        /// <returns>value的值</returns>
        public static Tvalue  TryGet<Tkey,Tvalue>(this Dictionary<Tkey,Tvalue>dict,Tkey key)
        {
            Tvalue value;
            dict.TryGetValue(key, out value);
            return value;
        }
    }
    

4、通过CanvasGroup来控制panel的显示和交互

  • 里面有一个alpha值来控制显示和隐藏

  • BlockRaycasts 来控制能不能进行交互

    private CanvasGroup canvasGroup;
    
        void Start()
        {
            if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>();
    
        }
    
        public override void OnEnter()
        {
            if (canvasGroup == null) canvasGroup = GetComponent<CanvasGroup>();
            canvasGroup.alpha = 1;
            canvasGroup.blocksRaycasts = true;
    
            Vector3 temp = transform.localPosition;
            temp.x = 600;
            transform.localPosition = temp;
            transform.DOLocalMoveX(0, 0.5f);
        }
    
        public override void OnExit()
        {
            canvasGroup.blocksRaycasts = false;
            transform.DOLocalMoveX(600, 0.5f).OnComplete(() => canvasGroup.alpha = 0);
        }
    
        public override void OnPause()
        {
            canvasGroup.blocksRaycasts = false;
        }
    
        public override void OnResume()
        {
            canvasGroup.blocksRaycasts = true;
        }
    
        public void OnClosePanel()
        {
            UIManager.Instance.PopPanel();
        }
    
        public void OnItemButtonClick()
        {
            UIManager.Instance.PushPanel(UIPanelType.ItemMessage);
        }
    

5、根据面板类型来实例化面板

  • 实例化面板所需要的参数自行设置

    // <summary>
        /// 根据面板类型,得到实例化的面板
        /// </summary>
        /// <param name = "panelType" > 面板的名字 </ param >
        /// < returns ></ returns >
        public BasePanel GetPanel(UIPanelType panelType)
        {
            if (panelDict == null)
            {
                panelDict = new Dictionary<UIPanelType, BasePanel>();
            }
    
            BasePanel panel = panelDict.TryGet(panelType);
            if (panel == null)
            {
               // 乳沟找不到,那么就找这个面板的prefab的路径,然后去根据prefab去实例化面板
                string path = panelPathDict.TryGet(panelType);
                GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;
                instPanel.transform.SetParent(CanvasTransform, false);
                panelDict.Add(panelType, instPanel.GetComponent<BasePanel>());
                return instPanel.GetComponent<BasePanel>();
            }
            else
            {
                return panel;
            }
        }
    

6、通过栈来控制面板的进入和移出

  • 把每个panel看做是一个整体进行栈操作。需要的时候进栈,不需要的时候出栈

  • 入栈和入栈

    private Stack<BasePanel> panelStack;  //栈用来存放panel组件
    /// <summary>
        /// 把某个页面入栈,把某个页面显示在界面上
        /// </summary>
        /// <param name = "panelType" > 页面的名字 </ param >
        public void PushPanel(UIPanelType panelType)
        {
            if (panelStack == null)
                panelStack = new Stack<BasePanel>();
            //判断一下栈里面是否有页面
            if (panelStack.Count > 0)
            {
                BasePanel topPanel = panelStack.Peek();
                topPanel.OnPause();
            }
            BasePanel panel = GetPanel(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) return;
            BasePanel topPanel2 = panelStack.Peek();
            topPanel2.OnResume();
        }
    

7、构建BasePanel 基类来进行面板操作

  • 让其他Panel来继承BasePanel

  • 里面有四个方法,每个方法之间的关系不一样,详细查看UML图

三、遇到的问题

(一)、老师错误

1、Json解析出现报错

  • Json文件重复了

  • Json文件没有按照Unity里面的Json解析需求来编辑

(二)、自己的错误

1、运行的时候发现报错,提示Dictionary重复。

  • 描述:Dictionary重复
  • 原因:Json文件不对,有重复的内容
  • 解决:验证Json文件的正确性,在重新读取
  • 注意:以后如果还是类似问题要优先考虑是文件读取的问题。

2、关闭面板不能关闭,也就是不能出栈

  • 描述:关闭面板不能关闭,也就是不能出栈

  • 原因:有一句判断写错了

    if (panelStack.Count > 0) return;//错误代码
    if (panelStack.Count <= 0) return; //正确代码
    
  • 解决:根据出现问题检查代码,步骤如下

    • 先检查按钮点击事件看看是否正确。

    • 在查看关闭按钮调用的是什么方法

  • 注意:写代码的时候要小心一点,特别是相关if判断的时候

3、点击商店报错

  • 描述:要实例化的对象是null。
  • 原因:不知道
  • 解决:从小制作商店Panel
  • 注意:有时候找不到问题就关闭软件,或者解除组件然后再装上试试,或者重新制作游戏物体看看。

四、最后总结

1、UI框架可以为大型一点的游戏开发出UI所需的框架,而且框架内容写完以后,每个panel之间的制作就根据具体的开发需求来制作。可以快速的分工制作

2、通过解析Json文件来读取需求,能根据需求的变化来进行开发的扩展。

3、主要学习了Json的编写和解析、通过栈来管理Panel、使用CanvasGroup来管理Panel的显示和交互、还学习了扩展方法来拓展Dictionary类、也了解了单例模式、以及DOTeen插件来制作动画。

猜你喜欢

转载自blog.csdn.net/Momorey/article/details/84968157
今日推荐