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

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

开始撰写

从基础分析篇我们得到了三个类,面板基类,管理类和面板子类

那就从面板基类开始,定义其基本行为

面板基类

基本方法都很简单,分别是首次加载并打开面板,关闭和重新打开

加载我就采用unity的资源加载Resources方法

Unity数据持久化 万物之源Resources动态资源加载_unity 动态加载资源-CSDN博客

但是需要考虑几个问题

0.需要一个面板预制体并放到对应路径下

我就将其放到Wnd下起名叫AnyWnd了

1.因为unity特性,面板加载出来需要放在Canvas下才会被显示

所以需要设置父物体为Canvas
2.放在Canvas下还需要设置位置

所以需要记录一下传入的面板的原来的位置

然后就可以写代码了

cs 复制代码
public abstract class BasePanel  {

    protected Transform tempTrans;//记录要打开窗口的位置

    //实例化窗口
    public void CreatWnd(string wndName,Transform canvas)
        {
        //加载
        GameObject wnd = Resources.Load<GameObject>("Wnd/"+wndName);
        GameObject temp =GameObject.Instantiate(wnd);
        temp.transform.SetParent(canvas,false);

        //将该窗口的位置记录下来,以便打开和关闭
        tempTrans = temp.transform;
    }
}

重新打开和关闭面板如下

cs 复制代码
    //打开窗口
    public void OpenWnd()
        {
        tempTrans.gameObject.SetActive(true);
    }
    //关闭窗口
    public void CloseWnd() {
        tempTrans.gameObject.SetActive(false);
    }

是不是非常简单!!!

面板子类

就是随便一个面板子类都可以继承基类,从而有基类的方法,这个我就不多说了

cs 复制代码
public class TestPanel:BasePanel
{
    //在这里可以写TestWnd自己的逻辑
}

面板管理类

因为面板基类的Creat方法要传入两个参数

所以我们就需,被实例化的面板的名字场景中Canvas的transform

cs 复制代码
public class PanelManager:MonoBehaviour
{
    public Transform canvesPos;
    public TestPanel testWnd;

    private void Start() {
        testWnd = new TestPanel();
        testWnd.CreatWnd("AnyWnd", canvesPos);
    }
    private void Update() {
        if(Input.GetKeyDown(KeyCode.W))
            {
            testWnd.OpenWnd();
        }
        if(Input.GetKeyDown(KeyCode.S))
            {
            testWnd.CloseWnd();
        }
    }
}

运行试一下效果

这样,我就让AnyWnd这个面板在没有挂载脚本的情况下

面板管理类可以控制所有面板

且,每一个子类对象都能控制其对应的实际面板

优化

面板基类

用作记录要打开窗口的位置的临时Transform

可以成一个属性,使得外部只能调用,不能修改

C# & Unity 面向对象补全计划 之 类class-CSDN博客

cs 复制代码
  protected Transform TempTrans { //记录要打开窗口的位置
        get;
        private set;
    }

先前的方法全部可以写成虚方法,另外添加一个抽象类Init方法,以便拓展子类的功能

C# & Unity 面向对象补全计划 之 初识继承方法与多态_unity 继承函数方法-CSDN博客

cs 复制代码
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);
        GameObject temp =GameObject.Instantiate(wnd);
        temp.transform.SetParent(canvas,false);

        //将该窗口的位置记录下来,以便打开和关闭
        TempTrans = temp.transform;
        //首次实例化不要直接打开
        CloseWnd();
    }
    //打开窗口
    public virtual void OpenWnd()
        {
        TempTrans.gameObject.SetActive(true);
    }
    //关闭窗口
    public virtual void CloseWnd() {
        TempTrans.gameObject.SetActive(false);
    }
    public abstract void Init();
}

面板管理类

面板管理类写具体控制逻辑(比如input.getkeydown......)就不太正确

一般都是外部的什么东西去调用面板管理类封装好的方法,如下图

况且,面板管理类突出一个管理功能,那我就将其功能贯彻到底

0.设置成单例模式

cs 复制代码
private static PanelManager instance;
public static PanelManager Instance=>instance;
private void Awake() {
    if(instance == null) {
     instance = this;
    DontDestroyOnLoad(gameObject);
    }
    else{
        Destroy(gameObject);
    }
}

1.对其两个参数进行优化,使其自动得到Canvas和需要管理的子类

2.如果面板很多的情况下,可以添加一个字典进行管理

cs 复制代码
    private Transform canvesPos;//场景中的Canvas位置
    /// <summary>
    /// string =子类面板名
    /// BasePanel 里氏替换原则,所有继承了面板基类的子类面板都可以用父类容器装
    /// </summary>
    private Dictionary<string, BasePanel> panles;//存储所有面板子类的字典

    //单例
    private static PanelManager instance;
    public static PanelManager Instance=>instance;
    private void Awake() {
      
        if(instance == null) {
         instance = this;
        DontDestroyOnLoad(gameObject);
        }
        else{
            Destroy(gameObject);
        }
        //初始化字典
        panles = new Dictionary<string, BasePanel>();
        panels.Clear();
        canvesPos = GameObject.Find("Canvas").transform;//虽然有性能消耗但是只用一次所以可以接受
}

3.对面板基类进行再封装,让其他模块用到的时候直接调用

cs 复制代码
    /// <summary>
    /// 加载面板
    /// </summary>
    /// <typeparam name="T">需要加载的子类面板脚本</typeparam>
    /// <param name="panelName">需要加载的面板名称</param>
    public void LoadPanel<T>(string panelName) where T:BasePanel,new ()
        { 
        T panel = new T();//实例化面板子类
        panels.Add(panelName, panel);
        panel.CreatWnd(panelName, canvesPos);
        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}****,请检查预制体路径或者查看是否有该预制体");  
    }

好了,这就是全部内容了,关于所有代码和扩展性请看下一篇:扩展与总结篇

相关推荐
tealcwu10 小时前
【Unity基础】Unity中的UI系统
ui·unity·lucene
北冥没有鱼啊12 小时前
UE5 射线折射
游戏·ue5·游戏引擎·ue4
※※冰馨※※13 小时前
Unity3D 鼠标移动到按钮上显示信息
开发语言·unity·c#
cl°14 小时前
【WPF】如何使用异步方法
经验分享·c#·wpf
孟章豪15 小时前
从零开始:在 .NET 中构建高性能的 Redis 消息队列
redis·c#
小吴同学·16 小时前
.NET Core WebApi第5讲:接口传参实现、数据获取流程、204状态码问题
c#·.net core
云围16 小时前
Gitlab 官方推荐自动化cache服务器Minio的安装
git·unity·ci/cd·自动化·gitlab·devops
gc_229916 小时前
C#实现简单的文件夹对比程序(续)
c#
时光追逐者18 小时前
一款基于.NET8开源且免费的中小型酒店管理系统
开发语言·后端·c#·.net
cl°19 小时前
WPF中视觉树和逻辑树的区别和联系
经验分享·学习·c#·wpf