Unity控制物体显示与隐藏方法及优化总结
创始人
2024-04-23 00:57:37
0

Tandre的碎碎念:我开始用Unity做项目接触最早的接口就是Unity的GameObject的SetActive接口,当时甚至只用这一个接口就解决了一个项目中所有关于显示与隐藏的问题,但实际上它的问题很多,很多时候需要尽量避免使用或避免直接使用,这篇博客就记录下关于显示与隐藏的优化问题。

目录

        • SetActive接口
          • 示例代码
          • 问题
          • 优化方案
        • UI的显示隐藏
          • SetActive()
          • Canvas group组件(推荐使用)
        • 其他的显示与隐藏方法
          • 缩小Scale
          • 移动物体
          • 设置MeshRenderer状态
          • 设置Shader透明度
          • 修改物体Layer
        • 结语

SetActive接口

可以说是最常用的控制显示与隐藏的接口了,但往往并不推荐使用

示例代码
GameObject go
go.SetActive(true);
go.SetActive(false);
问题

1.会导致网格重建,触发Unity的垃圾回收机制(GC),总之很影响性能
2.引起OnEnable和OnDisable的调用,会有一定的消耗

优化方案

因为对于该接口的GC问题很难解决,所以只能尽量的避免。

SetActive在底层会先对物体进行判断是否处于Active状态,而SetActive这个接口在调用时本身就是在C#层调用底层,所以为避免不必要的底层判断,可以在C#层对物体的Active状态进行判断。示例代码如下:

static public class MyTools
{public static void MSetActive(this GameObject go, bool State){if (go){if (go.activeSelf != State){go.SetActive(State);}}}
}

写完这样一个方法后,在后续需要设置显示隐藏时只需要调用这个方法

GameObject go;
go.MsetActive(true);

UI的显示隐藏

因为UI的显示与隐藏是最经常面对的需求之一,所以需要单独写一下

SetActive()

首先应尽可能地不用SetActive这个接口,它在使用时会遍历这个物体下所有继承MonoBehaviour的脚本,并执行脚本上相应的OnEnable和OnDisable脚本,所以基本相当于对每个子物体都执行了一遍SetActive方法

如果一定要用也可以借助上面自定义的方法(MSetActive())减少一定的不必要性能消耗。

Canvas group组件(推荐使用)

通过在父物体上挂载CanvasGroup组件,然后控制它的Alppa的1/0来控制显示/隐藏,相对SetActive的性能相差并不大,两者都不会触发DrawCall,但CanvadGroup组件不会执行子节点的Awake方法,而SetActive(true)会执行Awake()方法
使用CanvasGroup显示隐藏物体的方法示例:

public static void MSetActive(this CanvasGroup cgrop,bool active)
{if (cgrop!=null){if (active){cgrop.alpha = 1;cgrop.interactable = true;cgrop.blocksRaycasts = true;}else{cgrop.alpha = 0;cgrop.interactable = false;cgrop.blocksRaycasts = false;}}
}

其中的Alpha表示透明度,可用于UI淡入淡出的控制,Interactable表示是否禁用输入交互,BlockRaycasts是否禁用射线检测,IgnoreParentGroups是否忽略父级的CanvasGroup。这些属性将作用于该组件及其所有子物体,所以利用该组件可以较便捷的实现很多实用的效果。

其他的显示与隐藏方法

缩小Scale

采用缩小Scale的方法,即:

transform.localScale=Vector3.zero;

这种方法可以避免SetActive带来的很多性能消耗,但当Scale改回原大小时会触发DrawCall带来相对更多的性能消耗。

移动物体

通过更改物体位置(Position),将物体移动到屏幕外,使相机不渲染此物体,缺点在于,更改物体位置会导致它和它的所有子物体重新进行位置计算。

设置MeshRenderer状态

需要物体带有MeshRenderer组件,相当于将物体隐身,并不会影响物体的脚本运行,物体的碰撞体也依然存在。示例如下:

gameObject.GetComponent().enabled = true;
gameObject.GetComponent().enabled = false;
设置Shader透明度

这种方法与上一个类似,但需要的是材质球上的shader存在可以控制透明度的属性,示例如下:

material.SetColor("_Color", Color.white);
修改物体Layer

将物体的layer设置在相机的CulingMask之外,使相机不渲染此物体,示例如下:

gameObject.layer=LayerMask.NameToLayer("isDisabled");

这里layer的名字需要自行根据需要添加或使用

结语

对于UI的显示与隐藏相对好的方式是使用CanverGroup,但其更好的点在于组件上属性的控制而并非对显示隐藏的优化上面。对于物体显示与隐藏,为避免网格重建和大量GC消耗,优化方向便是想办法让其不被相机渲染,或尽可能减少不必要的计算。

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...