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");
        }
    }
}
相关推荐
CoderIsArt5 小时前
参数系统的基类Parameter抽象类
c#
盛夏绽放7 小时前
Python字符串常用方法详解
开发语言·python·c#
WarPigs7 小时前
Unity光照笔记
笔记·unity·游戏引擎
Tummer836311 小时前
C#+WPF+prism+materialdesign创建工具主界面框架
开发语言·c#·wpf
神码编程11 小时前
【Unity】 HTFramework框架(六十五)ScrollList滚动数据列表
unity·游戏引擎·ugui
ghost14311 小时前
C#学习第23天:面向对象设计模式
开发语言·学习·设计模式·c#
DanmF--12 小时前
Protobuf工具
网络·unity·游戏引擎·游戏程序
yngsqq12 小时前
(for 循环) VS (LINQ) 性能比拼 ——c#
c#·solr·linq
想做后端的小C13 小时前
C# 面向对象 构造函数带参无参细节解析
开发语言·c#·面向对象
炯哈哈13 小时前
【上位机——WPF】App.xml和Application类简介
xml·开发语言·c#·wpf·上位机