Unity 从零开始搭建一套简单易用的UGUI小框架 扩展与优化篇(完结)

一个通用的UGUI小框架就算是写完了,下面是一步步的思考与优化过程

Unity 从零开始搭建一套简单易用的UGUI小框架 基础分析篇-CSDN博客

Unity 从零开始搭建一套简单易用的UGUI小框架 功能撰写与优化篇-CSDN博客

从使用者的角度来整理一下可能会发出的疑问

0. PanelManager.Instance.LoadPanel<TestPanel>("AnyWnd");

其中TestPanel和AnyWnd都代表了什么?

AnyWnd:面板预制体

TestPanel:面板预制体的脚本

我特意将二者分开就是让你理清思路,知道加载的是什么东西

其实二者可以合二为一,只需要让脚本名和预制体名一致,再修改LoadPanel中传入的名字即可

1.面板管理类的单例是如何创建的面板?

是通过对面板基类的封装,直接F12一步一步地向上阅读即可明白

2.为什么首次调用要清空面板字典?可不可以不清除?

防止重复添加,确保数据一致,避免内存泄漏

可以不清除,关键是要确保字典中的数据始终是有效且一致

3.是不是还可以继续优化?

是的,比如采用异步加载的方式?

比如通过代码设置面板的层级?

比如在面板子类中对UI的显示隐藏的动画修改?

因为我将面板基类写成了虚函数,所以你可以对其在子类中修改加载打开和关闭

甚至直接修改面板基类也没什么不可能的

面板管理类

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UIElements;

public class PanelManager:MonoBehaviour
{
    private Transform canvasPos;//场景中的Canvas位置
    /// <summary>
    /// string =子类面板名
    /// BasePanel 里氏替换原则,所有继承了面板基类的子类面板都可以用父类容器装
    /// </summary>
    private Dictionary<string, BasePanel> panels;//存储所有面板子类的字典

    //单例
    private static PanelManager instance;
    public static PanelManager Instance => instance;
    private void Awake() {
      
        if(instance == null) {
         instance = this;
        DontDestroyOnLoad(gameObject);
        }
        else{
            Destroy(gameObject);
        }
        //初始化字典
        panels = new Dictionary<string, BasePanel>();
        panels.Clear();

        canvasPos = GameObject.Find("Canvas").transform;//虽然有性能消耗但是只用一次所以可以接受
}
    
    /// <summary>
    /// 加载面板
    /// </summary>
    /// <typeparam name="T">需要加载的子类面板脚本</typeparam>
    /// <param name="panelName">需要加载的面板名称</param>
    public void LoadPanel<T>(string panelName) where T:BasePanel,new ()
        { 
        T panel = new T();//实例化面板子类 

        if(canvasPos!=null)
        panel.CreatWnd(panelName, canvasPos);
        else
            Debug.Log("没有找到Canvas");

        panels.Add(panelName, panel);
        panel.Init();//子类重写的抽象方法,用于执行自己的逻辑
    }
    public void OpenPanel(string panelName)
    { 
        if (panels.TryGetValue(panelName, out BasePanel curPanel)){
                 curPanel.OpenWnd(); }           
        else            
        Debug.Log($"没有找到正确的面板****{panelName}****,请检查预制体路径或者查看是否有该预制体");
            
    }
    public void ClosePanel(string panelName) {
        if (panels.TryGetValue(panelName, out BasePanel panel)) {
            panel.CloseWnd(); }       
        else           
        Debug.Log($"没有找到正确的面板****{panelName}****,请检查预制体路径或者查看是否有该预制体");  
    }
}

面板基类

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class BasePanel  {

    protected Transform TempTrans { //记录要打开窗口的位置
        get;
        private set;
    }
       
    //实例化窗口
    public virtual void CreatWnd(string wndName,Transform canvas)
        {
        //加载
        GameObject wnd = Resources.Load<GameObject>("Wnd/"+wndName);
        if( wnd!=null){
        GameObject temp =GameObject.Instantiate(wnd); 
        temp.transform.SetParent(canvas,false);

        //将该窗口的位置记录下来,以便打开和关闭
        TempTrans = temp.transform;
        CloseWnd(); //首次实例化不要直接打开
        }   
        else{
            Debug.Log("没有正确加载到面板");
        }
    }
    //打开窗口
    public virtual void OpenWnd()
        {
        TempTrans.gameObject.SetActive(true);
    }
    //关闭窗口
    public virtual void CloseWnd() {
        TempTrans.gameObject.SetActive(false);
    }
    public abstract void Init();
}

面板子类示例

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestPanel : BasePanel {
    //在这里可以写TestWnd自己的逻辑
    public override void Init() {
        Debug.Log("子类可以在此进行自己的逻辑撰写");
    }
}

使用示例

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ctrl : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        PanelManager.Instance.LoadPanel<TestPanel>("AnyWnd");
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.O))
            {
        
            PanelManager.Instance.OpenPanel("AnyWnd");
        }
        if (Input.GetKeyDown(KeyCode.P)) {
            PanelManager.Instance.ClosePanel("AnyWnd");
        }
    }
}
相关推荐
向宇it2 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
_oP_i3 小时前
unity webgl部署到iis报错
unity
Go_Accepted3 小时前
Unity全局雾效
unity
向宇it3 小时前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
哑巴语天雨3 小时前
React+Vite项目框架
前端·react.js·前端框架
码农老起4 小时前
掌握 React:组件化开发与性能优化的实战指南
react.js·前端框架
每日出拳老爷子6 小时前
【图形渲染】【Unity Shader】【Nvidia CG】有用的参考资料链接
unity·游戏引擎·图形渲染
北海65167 小时前
Dots 常用操作
unity
撸码到无法自拔8 小时前
React:组件、状态与事件处理的完整指南
前端·javascript·react.js·前端框架·ecmascript
坐井观老天8 小时前
在C#中使用资源保存图像和文本和其他数据并在运行时加载
开发语言·c#