首页 > 其他分享 >Unity框架(UI框架)基础版

Unity框架(UI框架)基础版

时间:2024-09-08 12:49:25浏览次数:6  
标签:框架 panelName panelDic Unity UI private using 面板

目的

当游戏开发者再创建UI面板的时候一般是有一套流程的

而为了简化这个流程演化出UI框架

1、制作UI面板基类

帮助我们自动化的查找组件,监听事件,无需每次写大量冗余代码

2、制作UI管理器

管理所有UI面板,UI面板的显示隐藏都通过UI管理器来进行管理

基础版代码:

UI基类:

using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public abstract class BasePanel : MonoBehaviour
{
    /// <summary>
    /// 用于存储所有要用到的UI控件,用历史替换原则 父类装子类
    /// </summary>
    protected Dictionary<string, UIBehaviour> controlDic = new Dictionary<string, UIBehaviour>();

    /// <summary>
    /// 控件默认名字 如果得到的控件名字存在于这个容器 意味着我们不会通过代码去使用它 它只会是起到显示作用的控件
    /// </summary>
    private static List<string> defaultNameList = new List<string>() { "Image",
                                                                   "Text (TMP)",
                                                                   "RawImage",
                                                                   "Background",
                                                                   "Checkmark",
                                                                   "Label",
                                                                   "Text (Legacy)",
                                                                   "Arrow",
                                                                   "Placeholder",
                                                                   "Fill",
                                                                   "Handle",
                                                                   "Viewport",
                                                                   "Scrollbar Horizontal",
                                                                   "Scrollbar Vertical"};


    protected virtual void Awake()
    {
        //为了避免 某一个对象上存在两种控件的情况
        //我们应该优先查找重要的组件
        FindChildrenControl<Button>();
        FindChildrenControl<Toggle>();
        FindChildrenControl<Slider>();
        FindChildrenControl<InputField>();
        FindChildrenControl<ScrollRect>();
        FindChildrenControl<Dropdown>();
        //即使对象上挂在了多个组件 只要优先找到了重要组件
        //之后也可以通过重要组件得到身上其他挂载的内容
        FindChildrenControl<Text>();
        FindChildrenControl<TextMeshPro>();
        FindChildrenControl<Image>();
    }

    /// <summary>
    /// 面板显示时会调用的逻辑
    /// </summary>
    public abstract void ShowMe();

    /// <summary>
    /// 面板隐藏时会调用的逻辑
    /// </summary>
    public abstract void HideMe();

    /// <summary>
    /// 获取指定名字以及指定类型的组件
    /// </summary>
    /// <typeparam name="T">组件类型</typeparam>
    /// <param name="name">组件名字</param>
    /// <returns></returns>
    public T GetControl<T>(string name) where T:UIBehaviour
    {
        if(controlDic.ContainsKey(name))
        {
            T control = controlDic[name] as T;
            if (control == null)
                Debug.LogError($"不存在对应名字{name}类型为{typeof(T)}的组件");
            return control;
        }
        else
        {
            Debug.LogError($"不存在对应名字{name}的组件");
            return null;
        }
    }

    protected virtual void ClickBtn(string btnName)
    {

    }

    protected virtual void SliderValueChange(string sliderName, float value)
    {

    }

    protected virtual void ToggleValueChange(string sliderName, bool value)
    {

    }

    private void FindChildrenControl<T>() where T:UIBehaviour
    {
        T[] controls = this.GetComponentsInChildren<T>(true);
        for (int i = 0; i < controls.Length; i++)
        {
            //获取当前控件的名字
            string controlName = controls[i].gameObject.name;
            //通过这种方式 将对应组件记录到字典中
            if (!controlDic.ContainsKey(controlName))
            {
                if(!defaultNameList.Contains(controlName))
                {
                    controlDic.Add(controlName, controls[i]);
                    //判断控件的类型 决定是否加事件监听
                    if(controls[i] is Button)
                    {
                        (controls[i] as Button).onClick.AddListener(() =>
                        {
                            ClickBtn(controlName);
                        });
                    }
                    else if(controls[i] is Slider)
                    {
                        (controls[i] as Slider).onValueChanged.AddListener((value) =>
                        {
                            SliderValueChange(controlName, value);
                        });
                    }
                    else if(controls[i] is Toggle)
                    {
                        (controls[i] as Toggle).onValueChanged.AddListener((value) =>
                        {
                            ToggleValueChange(controlName, value);
                        });
                    }
                }
                    
            }
        }
    }
}

UI管理器:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

/// <summary>
/// 层级枚举
/// </summary>
public enum E_UILayer
{
    /// <summary>
    /// 最底层
    /// </summary>
    Bottom,
    /// <summary>
    /// 中层
    /// </summary>
    Middle,
    /// <summary>
    /// 高层
    /// </summary>
    Top,
    /// <summary>
    /// 系统层 最高层
    /// </summary>
    System,
}

/// <summary>
/// 管理所有UI面板的管理器
/// 注意:面板预设体名要和面板类名一致!!!!!
/// </summary>
public class UIMgr : BaseManager<UIMgr>
{
    private Camera uiCamera;
    private Canvas uiCanvas;
    private EventSystem uiEventSystem;

    //层级父对象
    private Transform bottomLayer;
    private Transform middleLayer;
    private Transform topLayer;
    private Transform systemLayer;

    /// <summary>
    /// 用于存储所有的面板对象
    /// </summary>
    private Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();

    private UIMgr()
    {
        //动态创建唯一的Canvas和EventSystem(摄像机)
        uiCamera = GameObject.Instantiate(ResMgr.Instance.Load<GameObject>("UI/UICamera")).GetComponent<Camera>();
        //ui摄像机过场景不移除 专门用来渲染UI面板
        GameObject.DontDestroyOnLoad(uiCamera.gameObject);

        //动态创建Canvas
        uiCanvas = GameObject.Instantiate(ResMgr.Instance.Load<GameObject>("UI/Canvas")).GetComponent<Canvas>();
        //设置使用的UI摄像机
        uiCanvas.worldCamera = uiCamera;
        //过场景不移除
        GameObject.DontDestroyOnLoad(uiCanvas.gameObject);

        //找到层级父对象
        bottomLayer = uiCanvas.transform.Find("Bottom");
        middleLayer = uiCanvas.transform.Find("Middle");
        topLayer = uiCanvas.transform.Find("Top");
        systemLayer = uiCanvas.transform.Find("System");

        //动态创建EventSystem
        uiEventSystem = GameObject.Instantiate(ResMgr.Instance.Load<GameObject>("UI/EventSystem")).GetComponent<EventSystem>();
        GameObject.DontDestroyOnLoad(uiEventSystem.gameObject);
    }

    /// <summary>
    /// 获取对应层级的父对象
    /// </summary>
    /// <param name="layer">层级枚举值</param>
    /// <returns></returns>
    public Transform GetLayerFather(E_UILayer layer)
    {
        switch (layer)
        {
            case E_UILayer.Bottom:
                return bottomLayer;
            case E_UILayer.Middle:
                return middleLayer;
            case E_UILayer.Top:
                return topLayer;
            case E_UILayer.System:
                return systemLayer;
            default:
                return null;
        }
    }

    /// <summary>
    /// 显示面板
    /// </summary>
    /// <typeparam name="T">面板的类型</typeparam>
    /// <param name="layer">面板显示的层级</param>
    /// <param name="callBack">由于可能是异步加载 因此通过委托回调的形式 将加载完成的面板传递出去进行使用</param>
    /// <param name="isSync">是否采用同步加载 默认为false</param>
    public void ShowPanel<T>(E_UILayer layer = E_UILayer.Middle, UnityAction<T> callBack = null, bool isSync = false) where T:BasePanel
    {
        //获取面板名 预设体名必须和面板类名一致 
        string panelName = typeof(T).Name;
        //存在面板
        if(panelDic.ContainsKey(panelName))
        {
            //如果要显示面板 会执行一次面板的默认显示逻辑
            panelDic[panelName].ShowMe();
            //如果存在回调 直接返回出去即可
            callBack?.Invoke(panelDic[panelName] as T);
            return;
        }

        //不存在面板 加载面板
        ABResMgr.Instance.LoadResAsync<GameObject>("UI", panelName, (res) =>
        {
            //层级的处理
            Transform father = GetLayerFather(layer);
            //避免没有按指定规则传递层级参数 避免为空
            if (father == null)
                father = middleLayer;
            //将面板预设体创建到对应父对象下 并且保持原本的缩放大小
            GameObject panelObj = GameObject.Instantiate(res, father, false);

            //获取对应UI组件返回出去
            T panel = panelObj.GetComponent<T>();
            //显示面板时执行的默认方法
            panel.ShowMe();
            //传出去使用
            callBack?.Invoke(panel);
            //存储panel
            panelDic.Add(panelName, panel);

        }, isSync);
    }

    /// <summary>
    /// 隐藏面板
    /// </summary>
    /// <typeparam name="T">面板类型</typeparam>
    public void HidePanel<T>() where T : BasePanel
    {
        string panelName = typeof(T).Name;
        if(panelDic.ContainsKey(panelName))
        {
            //执行默认的隐藏面板想要做的事情
            panelDic[panelName].HideMe();
            //销毁面板
            GameObject.Destroy(panelDic[panelName].gameObject);
            //从容器中移除
            panelDic.Remove(panelName);
        }
    }

    /// <summary>
    /// 获取面板
    /// </summary>
    /// <typeparam name="T">面板的类型</typeparam>
    public T GetPanel<T>() where T:BasePanel
    {
        string panelName = typeof(T).Name;
        if (panelDic.ContainsKey(panelName))
            return panelDic[panelName] as T;
        return null;
    }
}

只提供基础版

标签:框架,panelName,panelDic,Unity,UI,private,using,面板
From: https://blog.csdn.net/weixin_62613770/article/details/142025060

相关文章

  • 问:聊一下NIO模型在Netty框架中的用法?
    1.核心概念和特点Netty是一个基于JavaNIO(Non-blockingI/O)的高性能网络应用框架,它简化了网络编程,如TCP和UDP套接字服务器的开发。Netty的核心概念包括:Channel:Netty中的基本I/O操作抽象。Channel表示一个打开的连接,可以进行读写操作。EventLoop:负责处理Channel上的事件......
  • RuoYi框架部分历史漏洞
    RuoYi框架部分历史漏洞生产环境搭建(代码审计)项目地址:若依(y_project)-Gitee.com官方文档:RuoYi项目构成因为RuoYi框架是基于SpringBoot搭建的,所以我们启动项目时不用像SpringMVC那样去配置我们的服务器然后把项目放到服务器上启动。我们成功导入项目之后会生成一些文件......
  • 干货——UGUI渲染RT渲染半透明并与背景完美融合
    文章目录一、技术概述1.UGUI2.RenderTexture3.半透明效果与融合二、实现步骤1.创建RenderTexture2.设置相机3.创建特效4.RenderTexture渲染到UGUI三、实现完美混合1.混合模式2.Shader改造四、最终效果五、方法限制在游戏开......
  • 【鸿蒙实战开发】基于加解密算法框架的常见规格问题
    往期知识点整理鸿蒙(HarmonyOS)北向开发知识点记录~【鸿蒙实战开发】ArkTS多线程的多线程系列(一):ArkTS多线能力入门【鸿蒙实战开发】ArkTS多线程的多线程系列(二):基于Sendable共享对象实现跨线程通信及UI状态刷新【鸿蒙实战开发】ArkTS多线性的多线程系列(三):基于单例实现跨......
  • tkinter搭建GUI软件框架并创建不同的Frame界面实现不同的功能
    引言    在本篇博客中,小编要带大家解决的问题是如何创建一个软件窗口对象,并在窗口顶部菜单中通过按钮实现不同Frame界面的切换,在不同的Frame页面中实现访问路径等不同的功能,其中每行代码代表的意思,小编也在相应代码后面进行了注释,此外,代码在排版上也非常规范,各位小可爱......
  • Unity(2022.3.41LTS) - 音频
    目录一、音频系统概述二、音频资源类型三、音频组件四、音频空间定位五、音频效果处理六.音乐框架设计一、音频系统概述Unity的音频系统允许开发者在游戏中添加各种声音效果,包括背景音乐、音效、环境音等。它提供了丰富的功能来控制音频的播放、音量、循环、空间定......
  • 基于python+flask框架的手机电子商城平台设计(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着移动互联网技术的飞速发展,智能手机已成为人们日常生活中不可或缺的一部分。消费者对于手机的需求日益多样化,不仅关注手机的性能、品牌......
  • 基于python+flask框架的基于Web的智能导诊系统(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着医疗需求的日益增长和医疗资源的有限性,患者在就医过程中常面临挂号难、找对科室难、等待时间长等问题。传统医疗导诊模式已难以满足患......
  • 【Unity必备插件】NGUI:UI设计传奇工具
    ......
  • 前端框架有哪些?以及每种框架的详细介绍
    目录前言1.React2.Vue.js3.Angular4.Bootstrap5.Foundation总结前言前端框架是Web开发中不可或缺的工具,它们为开发者提供了丰富的工具和抽象,使得构建复杂的Web应用变得更加容易。当前,前端框架种类繁多,其中一些最受欢迎的框架包括React、Vue.js、Angular、Boots......