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");
        }
    }
}
相关推荐
红绿鲤鱼6 分钟前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
ZwaterZ32 分钟前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
大眼睛姑娘2 小时前
Unity3d场景童话梦幻卡通Q版城镇建筑植物山石3D模型游戏美术素材
unity·游戏美术
zhenryx3 小时前
前端-react(class组件和Hooks)
前端·react.js·前端框架
ZwaterZ3 小时前
el-table-column自动生成序号&&在序号前插入图标
前端·javascript·c#·vue
Thomas游戏开发4 小时前
Unity3D 逻辑服的Entity, ComponentData与System划分详解
前端框架·unity3d·游戏开发
SRC_BLUE_175 小时前
SQLI LABS | Less-55 GET-Challenge-Union-14 Queries Allowed-Variation 2
oracle·c#·less
yngsqq6 小时前
037集——JoinEntities连接多段线polyline和圆弧arc(CAD—C#二次开发入门)
开发语言·c#·swift
Zԅ(¯ㅂ¯ԅ)6 小时前
C#桌面应用制作计算器进阶版01
开发语言·c#
鹿野素材屋6 小时前
Unity Dots下的动画合批工具:GPU ECS Animation Baker
unity·游戏引擎