UGUI——进阶篇

DrawCall

Drawcall:字面意义上就是绘制呼叫的意思,表示CPU通知GPU

概念:CPU准备好渲染数据(顶点,纹理,法线,shader)后告知GPU开始渲染的命令

------将命令放入命令缓存区。

简单来说,CPU准备渲染数据,GPU开始渲染这样一次过程就是DrawCall

如果游戏中DrawCall数量较高会影响CPU的效率,最直接的感受就是游戏会卡顿

可以用拷贝文件来类比 DrawCall 对性能的影响:

  • 场景一 :拷贝 10,000 个 1KB 的小文件(总大小约 10MB)

    → 虽然数据量不大,但耗时很长。

  • 场景二 :拷贝 1 个 10MB 的大文件

    → 几乎瞬间完成。

原因

每个小文件的拷贝都需要额外开销,比如分配内存、创建文件句柄、更新目录等。类似地,每次 DrawCall 都需要 CPU 准备渲染状态、提交数据给 GPU,这些操作虽小,但频繁调用会显著拖慢性能。

因此,减少 DrawCall(合并渲染批次)就像把多个小文件打包成一个大文件,能大幅提升效率。

如何降低减少DrawCall数量

在UI层面上

小图合并大图------即多个小DrawCall合并成一个大DrawCall

图集制作

ProjectSetting设置

1、需要先安装2D Sprite插件,Edit -> Project Settings -> Editor -> Sprite Packer-> Mode

2、选择合适的图集模式

|---------------------------------------------------------------------------|--------|-----------------------|
| Disabled 禁用 | 精灵图集模式 | 默认关闭 |
| Sprite Atlas V1 - Enabled For Builds (精灵图集 V1 - 为构建启用) | 精灵图集模式 | 仅在构建时打包精灵图集 |
| Sprite Atlas V1 - Always Enabled (精灵图集 V1 - 始终启用) | 精灵图集模式 | 在构建和进入 Play 模式时打包精灵图集 |
| Sprite Atlas V2 (Experimental) - Enabled (精灵图集 V2 - 启用) | 精灵图集模式 | 在构建和 Play 模式前打包精灵图集 |
| Sprite Atlas V2 (Experimental) - Enabled For Builds (精灵图集 V2 - 为构建启用) | 精灵图集模式 | 仅在构建时打包精灵图集 |

新建图集资源

1、新建图集资源

2、对应UI放入一个图集中

如何看UGUI的DrawCall

什么都没有的正常情况下,默认Batches为2,此后每添加一个就会加1个Bathces

一个图集中多个图只会增加一个Batches

如果将一个UI放在同一图集的两个image中,并且与其中image有重叠部分

这里正常来讲是4个(所有图片属于一个图集)

这里就变成了5,有一个图批处理被打断?(但我不明白为什么只是一个?明明我重合了两个)

UI事件接口

事件接口是用于处理用户交互和其他事件的编程结构,事件接口通常用于响应用户输入,如鼠标点击、拖拽等。

cs 复制代码
1、鼠标触碰对象
IPoin terEnterHandler - OnPointerEnter:当指针进入对象时调用(鼠标进入)。
IPoin terExitHandler - OnPointerExit:当指针退出对象时调用(鼠标离开)。
2 鼠标的按键
IPoin terDownHandler - OnPointerDown:在对象上按下指针时调用(按下)。
IPoin terUpHandler - OnPointerUp:松开指针时调用(在指针正在点击的游戏对象上调用)(抬起)。
IPoin terClickHandler - OnPointerClick:在同一对象上按下再松开指针时调用(点击)。
3 鼠标拖拽
IBeginDragHandler - OnBeginDrag:即将开始拖动时在拖动对象上调用(开始拖拽)。
IDragHandler - OnDrag:发生拖动时在拖动对象上调用(拖拽中)。
IEndDragHandler - OnEndDrag:拖动完成时在拖动对象上调用(结束拖拽)。

UI接口的使用

cs 复制代码
using UnityEngine;
using UnityEngine.EventSystems;//1.引用空间

public class Lesson : MonoBehaviour,
    IPointerEnterHandler,
    IPointerExitHandler,
    IPointerDownHandler,//2.事件接口
    IPointerUpHandler
{
    public void OnPointerDown(PointerEventData eventData)
    {
        print("鼠标(触摸)按下");
        print(eventData.pointerId);
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        // 鼠标进入(在移动设备上通常无效,因无"悬停"概念)
        print("鼠标进入");
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        // 鼠标退出(在移动设备上通常无效)
        print("鼠标退出");
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        print("鼠标(触摸)抬起");
    }
}

eventData类

PointerId:左键-1,右键-2,中键-3

Position与PressPostion:UI拖拽中适合用Position找到UI实时改变的位置,PressPostion只是鼠标点击的位置

delta:指针移动增量------一般用于拖拽UI,让UI跟随鼠标

UI事件触发器

我们之前学习过了控件的额外事件的接口,但是那些接口都需要我们一个一个去脚本中继承相应的接口再挂载到对应的控件上,这看起来有点麻烦

EventTrigger组件能够一次性帮我们完成好添加接口到控件上并顺便绑定好函数。

拖拽使用

1、把这个Event Trigger挂载到对应UI上

2、点击Add new Event Type(注意这里的传参的参数,代码中也要对应)

这里需要注意下:EventTrigger是给响应对象,而不是Panel

3、将脚本挂载到Panel后,设置Image中的组件

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class EventTrigger1 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {

    }

    public void TestPointerEnter(BaseEventData data)
    {
        PointerEventData eventData = data as PointerEventData;
        print("鼠标进入" + eventData.position);
    }
}

设置Image中的组件如下:

代码使用

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class EventTrigger2 : MonoBehaviour
{
    public EventTrigger et;
    // Start is called before the first frame update
    void Start()
    {
        //声明一个希望被监听的事件对象
       EventTrigger.Entry entry = new EventTrigger.Entry();
        //声明事件类型
        entry.eventID = EventTriggerType.PointerUp;
        //监听函数关联
        entry.callback.AddListener((data) => { print("按起"); });
        //将事件添加到事件触发器组件中
        et.triggers.Add(entry);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

**这里需要注意:**et.trigger其实是image的EventTrigger中已有的触发事件,一并添加到Panel的事件队列entry进行统一管理

RectTransformUtility进行坐标转化

Unity的 RectTransformUtility 函数里面提供了常用的坐标系之间的转换关系。

这里的UGUI坐标指的是对应UI的**RectTransform 的本地坐标系**(以父级为参考,单位是像素,受锚点影响)。

ScreenPointToLocalPointInRectangle函数

可以将屏幕坐标转换成局部坐标(方便拖拽UI时的位置更新)

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class RectTolocal : MonoBehaviour,IDragHandler
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    public void OnDrag(PointerEventData eventData)
    {
        #region 知识点二 将屏幕坐标转换为UI本地坐标系下的点
        //方法:
        //RectTransformUtility.ScreenPointToLocalPointInRectangle
        ////参数一:相对父对象
        ////参数二:屏幕点
        ////参数三:摄像机
        ////参数四:最终得到的点
        ////一般配合拖拽事件使用
        Vector2 nowPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            this.transform.parent as RectTransform,
            eventData.position,
            eventData.enterEventCamera,
            out nowPos);
        print(nowPos);
        this.transform.localPosition = nowPos;
        #endregion
    }
}

其他辅助静态方法

Mask遮罩

  • 定义:在不改变图片本身内容的情况下,通过特定技术手段让图片在游戏中只显示其中一部分的效果
  • 应用场景:常见于不规则图形显示(如圆形头像)、UI元素局部显示控制等

实现遮罩效果的关键组件是 Mask 组件。

通过在父对象上添加 Mask 组件即可遮罩其子对象。

注意:

  1. 想要被遮罩的 Image 需要勾选 Maskable。
  2. 只要父对象添加了 Mask 组件,那么所有的 UI 子对象都会被遮罩。
  3. 遮罩父对象图片的制作,不透明的地方显示,透明的地方被遮罩。

异形按钮

异形按钮:图片形状不是传统矩形的按钮

方法一

按钮之所以能够响应点击,主要是根据图片矩形范围进行判断的

它的范围判断是自下而上的,意思是如果有子对象图片,子对象图片的范围也会算为可点击范围

那么我们就可以用多个透明图拼凑不规则图形作为按钮子对象用于进行射线检测

方法二

这个是牺牲性能而提高精准识别异形范围的

将如下脚本挂载到Button组件上

cs 复制代码
public class Lesson23 : MonoBehaviour
{
    public Image img;
    // Start is called before the first frame update
    void Start()
    {
        //该参数含义:指定一个像素必须具有的最小alpha值,以变能够认为射线命中了图片
        //说人话:当像素点alpha值小于了 该值 就不会被射线检测了
        img.alphaHitTestMinimumThreshold = 0.1f;
    }

自动布局

在Unity的用户界面系统(UGUI)中,自动布局(Auto Layout)是一个强大的功能,它允许开发者在不需要手动调整每个UI元素位置和大小的情况下,根据一定的规则和约束自动排列和调整界面元素。

Horiztal Layout

(Horizontal Layout Group组件)

  • Child Control Size孩子决定自己的大小
  • Child Force Expand爸爸决定孩子要撑满
  • 两个都勾:孩子先按内容定大小,再被爸爸强行撑大
  • 两个都不勾:孩子自己设大小,不受控制

Grid Layout Group组件

Grid Layout

ContentSizeFitter

内容适配器使用场景

这里以Scorll View为例

1、当Content中的内容已经超出Content范围,向下滑动无法到达

2、遇到这种情况可以使用 这个组件------就不需要随时修改Content大小了

宽高比适配器

AspectRatioFitter(宽高比适应器)是Unity UGUI中的一个组件,用于控制UI元素的宽高比例,使其能够根据父容器的大小进行自适应调整。

AspectRatioFitter组件通过调整UI元素的宽高比例来适应父容器的大小。它有两种模式可供选择:Fit In Parent(适应父容器)和 Envelope Parent(包裹父容器)。

  • Fit In Parent模式: UI元素会根据父容器的大小等比例缩放,以适应父容器的尺寸。如果UI元素的宽高比例与父容器的宽高比例不一致,UI元素会在父容器内留有空白区域。
  • **Envelope Parent模式:**UI元素会根据父容器的大小等比例缩放,以填满父容器的尺寸。如果UI元素的宽高比例与父容器的宽高比例不一致,UI元素会超出父容器的范围。

CanvasGroup

这个组件直接放在对应Panel面板上,直接控制整个Panel面板上UI的浅入浅出

属性 说明
Alpha 透明度
Interactable 是否为可交互的
Blocks Raycasts 是否作为射线投射的碰撞体
Ignore Parent Groups 是否受到父物体的Canvas Group的影响

具体使用:

CanvasGroup的使用

相关推荐
Exquisite.2 小时前
企业高性能web服务器(4)
运维·服务器·前端·网络·mysql
2501_944525543 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter
2601_949857433 小时前
Flutter for OpenHarmony Web开发助手App实战:快捷键参考
前端·flutter
wangdaoyin20103 小时前
若依vue2前后端分离集成flowable
开发语言·前端·javascript
心柠3 小时前
vue3相关知识总结
前端·javascript·vue.js
Amumu121384 小时前
Vue Router(二)
java·前端
a1117764 小时前
图书借阅管理系统(FastAPI + Vue)
前端·vue.js·fastapi
常年游走在bug的边缘5 小时前
掌握JavaScript作用域:从函数作用域到块级作用域的演进与实践
开发语言·前端·javascript
极致♀雨5 小时前
vue2+elementUI table表格勾选行冻结/置顶
前端·javascript·vue.js·elementui