Compilation of Unity-Basic UI Framework

Table of contents

Part 1: UIFrame_1.0

1. Build UI interface and requirements

Second, realize the shortcomings in the above function code:

1. Find Canvas in BagPanel to call RolePanel, with high coupling

2. At first, RolePanel is in a hidden state, and there is a probability that the object cannot be found by using transform.Find()

3. Improvement: Set up a UIManager to control and manage the status of each Panel

Fourth, there are still shortcomings in UIFrame1.0:

1. The reference of each panel needs to be written separately, and it is difficult to deal with the complexity of the project

2. It will cause the memory to skyrocket, and the unified shutdown is less efficient

3. Each panel needs to write a function separately, and the later expansion is too poor

The second part: UIFrame_2.0

1. New requirements:


Preface: Need foundation: MVC idea, UGUI, XML foundation

Small knowledge points:

1.Resources: During the packaging process, no matter whether the resources in the folder are useful or not, they will be packaged. After packaging, this folder will exist in a compressed form and cannot be found in the packaged files (there is an upper limit, Only 4G files can be stored at most)

2. Generic constraints

struct, class, class name, interface name (inheritance constraints), new(): must have a public parameterless constructor

 3. UI components - Grid Layout Group

Part 1: UIFrame_1.0

1. Build UI interface and requirements

1. Click the icon in the lower right corner to display a panel

 2. There is a cross ❌ in the panel, click ❌ to close the panel

3. There needs to be a button in the backpack panel. Click the button to open the character attribute panel and view the character attribute (RolePanel)

 Implementation code: MainPanel

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MainPanel : MonoBehaviour
{
    Button btn_setting;
    Button btn_skill;
    Button btn_bag;
    Button btn_role;

    GameObject mainPanel;
    GameObject rolePanel;
    GameObject bagPanel;
    GameObject settingPanel;
    GameObject skillPanel;

    Transform BtnGroup;
    Transform Canvas;


    void Awake()
    {
        BtnGroup = transform.Find("BtnGroup");
        Canvas = transform.parent;
        Debug.Log(Canvas);

        btn_setting = BtnGroup.Find("Btn_Setting").GetComponent<Button>();
        btn_skill = BtnGroup.Find("Btn_Skill").GetComponent<Button>();
        btn_bag = BtnGroup.Find("Btn_Bag").GetComponent<Button>();
        btn_role = BtnGroup.Find("Btn_Role").GetComponent<Button>();

        settingPanel = Canvas.Find("SettingPanel").gameObject;
        skillPanel = Canvas.Find("SkillPanel").gameObject;
        bagPanel = Canvas.Find("BagPanel").gameObject;
        rolePanel = Canvas.Find("RolePanel").gameObject;


    }

    // Start is called before the first frame update
    void Start()
    {

        btn_setting.onClick.AddListener(() => { settingPanel.SetActive(!settingPanel.activeSelf); });
        btn_skill.onClick.AddListener(() => { skillPanel.SetActive(!skillPanel.activeSelf); });
        btn_bag.onClick.AddListener(() => { bagPanel.SetActive(!bagPanel.activeSelf); });
        btn_role.onClick.AddListener(() => { rolePanel.SetActive(!rolePanel.activeSelf); });

    }

    // Update is called once per frame
    void Update()
    {

    }
}

BagPanel:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class BagPanel : MonoBehaviour
{
    Transform RolePanel;
    Button btn_RolePanel;
    Transform Canvas;

    Transform Btn_close;
    Button btn_close;

    private void Awake()
    {
        Canvas = transform.parent;
        RolePanel = Canvas.Find("RolePanel");
        btn_RolePanel = transform.Find("Btn_RolePanel").GetComponent<Button>();

        Btn_close = GameObject.Find("Btn_close").transform;
        btn_close = Btn_close.GetComponent<Button>();   
            
    }
    // Start is called before the first frame update
    void Start()
    {
        btn_close.onClick.AddListener(() => {gameObject.SetActive(false); });
        btn_RolePanel.onClick.AddListener(() => { RolePanel.gameObject.SetActive(true); });
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

Second, realize the shortcomings in the above function code:

1. Find Canvas in BagPanel to call RolePanel, with high coupling

2. At first, RolePanel is in a hidden state, and there is a probability that the object cannot be found by using transform.Find()

3. Improvement: Set up a UIManager to control and manage the status of each Panel

UIManager script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIManager : MonoBehaviour
{
    //UIManager一般会绑定在GameRoot脚本上面
    GameObject Canvas;
    GameObject mainPanel;
    GameObject rolePanel;
    GameObject bagPanel;
    GameObject settingPanel;
    GameObject skillPanel;

    Button btn_setting;
    Button btn_skill;
    Button btn_bag;
    Button btn_role;

    Transform BtnGroup;

    private static UIManager _instance;
    public static UIManager Instance
    {
        get
        {
            return _instance;
        }
    }

    private void Awake()
    {
        _instance = this;

        Canvas = GameObject.Find("Canvas");
        mainPanel = Canvas.transform.Find("MainPanel").gameObject;
        settingPanel = Canvas.transform.Find("SettingPanel").gameObject;
        skillPanel = Canvas.transform.Find("SkillPanel").gameObject;
        bagPanel = Canvas.transform.Find("BagPanel").gameObject;
        rolePanel = Canvas.transform.Find("RolePanel").gameObject;

        BtnGroup = mainPanel.transform.Find("BtnGroup");
        btn_setting = BtnGroup.Find("Btn_Setting").GetComponent<Button>();
        btn_skill = BtnGroup.Find("Btn_Skill").GetComponent<Button>();
        btn_bag = BtnGroup.Find("Btn_Bag").GetComponent<Button>();
        btn_role = BtnGroup.Find("Btn_Role").GetComponent<Button>();

    }

    public void showSettingPanel()
    {
        btn_setting.onClick.AddListener(() => { settingPanel.SetActive(!settingPanel.activeSelf); });
    }

    public void showMainPanel()
    {

    }

    public void showSkillPanel()
    {
        btn_skill.onClick.AddListener(() => { skillPanel.SetActive(!skillPanel.activeSelf); });
    }
    public void showBagPanel()
    {
        btn_bag.onClick.AddListener(() => { bagPanel.SetActive(!bagPanel.activeSelf); });
    }

    public void showRollPanel(bool isShowRollPanel)
    {
        if (isShowRollPanel)
        {
            //btn_role.onClick.AddListener(() => { rolePanel.SetActive(true); });
            rolePanel.SetActive(true);
            return;
        }
        else
        btn_role.onClick.AddListener(() => { rolePanel.SetActive(!rolePanel.activeSelf); });
        
        
    }

    // Start is called before the first frame update
    void Start()
    {
        rolePanel.SetActive(false);
        bagPanel.SetActive(false);
        settingPanel.SetActive(false);
        skillPanel.SetActive(false);

    }

    // Update is called once per frame
    void Update()
    {

    }
}

running result:

UIManager1

Fourth, there are still shortcomings in UIFrame1.0:

1. The reference of each panel needs to be written separately, and it is difficult to deal with the complexity of the project

Solution: Each reference is stored in a container, and it is taken out of the container when it is needed

2. It will cause the memory to skyrocket, and the unified shutdown is less efficient

In order to be able to be found at the beginning, each panel needs to be opened at the beginning, and then closed after finding it, which will cause the memory to skyrocket when the game starts running, and the efficiency is poor when it is closed uniformly.

Solution: When the game starts running, do not open all the panels, but make each panel a prefab, load it when it is needed for the first time, and store it in the container, and then use it again from the container take out

3. Each panel needs to write a function separately, and the later expansion is too poor

Solution: Use the container lookup method to correspond to specific references for operations

The second part: UIFrame_2.0

1. New requirements:

1. Realize different opening and closing effects for each UI panel (translate to open, rotate to open, zoom in and out and shake to open, etc.)

2. Open the backpack panel => attribute panel = "fire attribute panel in the attribute panel, and then click a close button to close the fire attribute panel in the attribute panel =" attribute panel = "backpack panel

3. Improve the problem in UIFrame_1.0, make the panel into a prefab loading method, and use the container to store it

4. After clicking an icon in the lower right corner, the rest of the icons are grayed out and cannot be clicked

Note: Where should the xml be placed when reading the xml file in Unity? Under the Assets folder? Need to read the file with Application.Datapath?

When the project is packaged, the Assets folder will be packaged as a binary file by Unity, so Application.DataPath will not find the xml file under the Assets folder; it should be placed in the Resources folder.

code part:

File loading module: load xml configuration files

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public static class ResourcesManager
{

    public static Dictionary<string,GameObject> ResourcesDic = new Dictionary<string,GameObject>();
   /// <summary>
   /// 加载资源:加载预制体
   /// 1、判断容器中是否存在该路径,
   /// 2、如果有的话,直接返回GameObj-------------ect
   /// 3、如果没有的话,调用Resources.Load()加载资源,然后再存入在存入到容器中
   /// </summary>
   /// <param name="path"> 传入一个资源路径 </param>
   /// <returns></returns>
    public static GameObject Load(string path)
    {
        if (ResourcesDic.ContainsKey(path))
        {
            return ResourcesDic[path];
        }
        GameObject gobj= Resources.Load(path) as GameObject;
        //ResourcesDic.Add(path, gobj);
        //索引器
        ResourcesDic[path] = gobj;
        return gobj;
    }

    /// <summary>
    /// 重载:加载非预制体的资源
    /// </summary>
    /// <typeparam name="Object"></typeparam>
    /// <param name="path"></param>
    /// <returns></returns>
    /// Hashtable : 非泛型键值对容器,键名和键值都可以是任意的数据类型
    public static Hashtable ResHtb = new Hashtable();
    //泛型函数
    public static T Load<T>(string path) where T : Object
    {
        if (ResHtb.ContainsKey(path))
        {
            //as:只能是引用类型之间的转换,这里必须约束T为引用类型 
            return ResHtb[path] as T ;
        }
        //Resources.Load()方法能返回的东西必须继承自Object:需要保证T可以隐式转换为Object
        T t= Resources.Load<T>(path);
        ResHtb[path] = t;
        return t;
    }
}

MyUIManager: Manage the opening and closing of all UI interfaces, which is equivalent to the control layer in MVC.

using System.Collections;
using System.Collections.Generic;
using System.Xml;
using UnityEngine;

public enum MyUIEnum
{
    MainPanel=1,
    RolePanel,
    SkillPanel,
    BagPanel,
    SettingPanel
}

/// <summary>
/// 管理所有UI界面的开启和关闭
/// </summary>
public static class MyUIManager 
{
    public static Transform canvas = null;

    public static Transform ThisCanvas
    {
        get 
        {
            if (canvas ==null)
            {
                canvas = GameObject.Find("Canvas").transform;
            }  
            return canvas;  
        }

    }

    //
    private static Dictionary<MyUIEnum, string> prefabDic = new Dictionary<MyUIEnum, string>();

    private static Dictionary<MyUIEnum, BasePanel> panelDic = new Dictionary<MyUIEnum, BasePanel>();

    private static Stack<BasePanel> UIStack = new Stack<BasePanel>();
    /// <summary>
    /// 一开始的时候,从xml中读取所有UI预制体的地址和枚举类型的对应关系
    /// </summary>
    public static void OnloadXml()
    {
        //TextAsset所有外部加载的文本,使用这个数据类型保存
        TextAsset xml = Resources.Load<TextAsset>("Configs/UIPanel");

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(xml.text);//加载xml文件中的内容
        XmlNodeList list = xmlDoc.SelectSingleNode("root").ChildNodes;

        foreach (XmlElement item in list)
        {   
            MyUIEnum  uiEnum =(MyUIEnum) int.Parse(item.GetAttribute("id"));
            string path ="Prefabs/"+ item.GetAttribute("path");
            prefabDic.Add(uiEnum, path);

        }

    }

    /// <summary>
    /// 根据枚举(编号)拿到对应的ui预制体
    /// </summary>
    /// <param name="uiEnum"></param>
    /// <returns></returns>
    static BasePanel GetPanel(MyUIEnum uiEnum,Transform parent=null)
    {
        if (panelDic.ContainsKey(uiEnum))
        {
            return panelDic[uiEnum];
        }
        //如果这个界面从来没有被打开过
        string path = prefabDic[uiEnum];
        GameObject prefab = ResourcesManager.Load(path);
        GameObject go = GameObject.Instantiate(prefab);//拿到并实例化预制体
        if (parent ==null)
        {
            parent = ThisCanvas;
        }
        go.transform.SetParent(parent);
        BasePanel panel = go.GetComponent<BasePanel>();
        panelDic.Add(uiEnum, panel);
        return panel;
    }

    public static void Load(MyUIEnum uiEnum,Transform parent = null)
    {
        if (UIStack.Count>0)
        {
            BasePanel topPanel = UIStack.Peek();//拿到栈顶元素但不出栈
            topPanel.Pause();
        }
        BasePanel panel = GetPanel(uiEnum,parent);
        UIStack.Push(panel);
        panel.Enter();

    }

    public static void UnLoad()
    {
        if (UIStack.Count<=0)
        {
            return;
        }
        BasePanel topPanel = UIStack.Pop();
        topPanel.Close();
        if (UIStack.Count > 0)
        {
            BasePanel resumePanel = UIStack.Peek();
            resumePanel.Resume();
        }
    }

    public static void Clear()
    {
        canvas = null;
        UIStack.Clear();
    }

}

Guess you like

Origin blog.csdn.net/qq_53663718/article/details/127717650