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

devtools/2024/10/18 3:34:48/

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

开始撰写 

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

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

面板基类

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

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

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

但是需要考虑几个问题

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

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

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

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

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

然后就可以写代码了

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;}
}

重新打开和关闭面板如下

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

 是不是非常简单!!!

面板子类

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

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

面板管理类

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

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

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博客

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

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

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

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.设置成单例模式

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.如果面板很多的情况下,可以添加一个字典进行管理

    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.对面板基类进行再封装,让其他模块用到的时候直接调用

    /// <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}****,请检查预制体路径或者查看是否有该预制体");  }

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

 


http://www.ppmy.cn/devtools/126632.html

相关文章

Flume面试整理-常见的Channel类型

Apache Flume提供了多种Channel(通道)类型,作为Source(源)和Sink(汇)之间的缓冲区,确保数据的可靠传输。不同类型的Channel提供了不同的性能和可靠性,适用于不同的应用场景。以下是Flume中常见的Channel类型及其特点: 1. Memory Channel ● 描述:Memory Channel将数…

Spring Boot知识管理:提升信息检索效率

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

Linux云计算 |【第四阶段】RDBMS2-DAY3

主要内容&#xff1a; 分库分表概述、Mycat中间件部署、分片规则&#xff08;枚举法、求模法、全局表&#xff09; 一、分库分表概述 关系型数据库本身比较容易成为系统瓶颈&#xff0c;单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后&#xff0c…

2-laravel-路由配置

文章目录 定义控制器设计控制器设置路由启动服务 基本路由视图路由建立视图路由建立视图文件 控制器视图路由创建视图二级目录控制器 定义控制器 打开laravel 工程 建立一个 Demo 名字的控制器去集成 模板控制器 安装两个插件 设计控制器 <?phpnamespace App\Http\…

el-select 下拉框选项文字过长解决方案

首先给下拉框设置类名&#xff0c;即popper-class属性&#xff0c;并且给el-option增加title属性 <el-selectv-model"item.portrayalItem"v-loadmore"{ method: lazyItemList, item, index }"multiplefilterableremotepopper-class"dropDown-sele…

PHP语言调用翔云身份证实名认证接口

身份证实名认证接口是一种用于验证用户身份的在线服务。它通过接收用户提供的身份证号码和姓名&#xff0c;与权威的数据进行比对&#xff0c;以确认用户的身份是否真实有效。 使用该接口时&#xff0c;通常需要向服务提供商提供以下信息&#xff1a; 用户的姓名 用户的身份证号…

Wireshark数据包分析教程

Wireshark数据包分析教程 本教程将基于Wireshark工具捕获的数据包&#xff0c;逐步讲解网络数据帧中的各项信息&#xff0c;帮助你了解每个字段的含义及其作用。我们将从最基础的帧&#xff08;Frame&#xff09;信息开始&#xff0c;逐层解释包括以太网、IP、TCP、HTTP和JSON…

IOS每次查询数据时,当前滚动的位置会跑到底部?

场景:(移动端)A模块内容在当前界面最后面展示时,若需要选择相应条件或切换页签时,IOS会一直显示在页面最底部,不会保留之前的位置? 问题出现在每次切换条件时会先清空数组,然后等接口请求回来后重新赋值,这样就会导致dom重新加载,界面内容重新刷新 解决这个问题其实可以利用…