Unity优化——脚本优化策略3

大家好,这里是七七,今天又来更新Unity脚本优化篇了,话不多说,直接上主题。

一、注意缓存Transform的变化

Transform组件只存储与其父组件相关的数据。这意味着访问和修改Transform组件的position、rotation和scale属性会导致大量未预料到的矩阵乘法计算,从而通过其父Transform为对象生成正确的Transform表示。对象在Hierarchy窗口中的位置越深,确定最终结果需要进行的计算就越多。

然而,这也意味着使用localPosition、localRotation和localScale的相关成本相对较小,因为这些值直接存储在给定的Transform中,可以进行检索,不需要任何额外的矩阵算法。因此,应该尽可能使用这些本地属性值。

遗憾的是,将数学计算从世界空间更改为本地空间,会使原本很简单的问题变得过于复杂,因此进行这样的更改会破坏实现方案,并引入大量以外的bug。有时,为了更容易地解决复杂的3D数学问题,牺牲一点性能是值得的。

不断更改Transform组件属性的另一个问题是,也会向组件(如Collider、RigidbodyLight和Camera)发送内部通知,这些组件也必须进行处理,因为物理和渲染系统都需要知道Transform的值,并相应地更新。

题外话:如上文所述,由于内存中Transform的充足,这些内部通知的速度在Unity5.4中得到了极大的提高,但我们仍需了解它们的成本。

在复杂的事件链中,在同一帧中多提提换Transform组件的属性是很常见的。每次发生这种情况时,都会触发内部消息,即使它们发生在同一帧甚至同一个函数调用期间。因此,应该尽量减少修改Transform属性的次数,方法是将它们缓存在一个成员变量中,只在帧的末尾提交它们

二、避免在运行时使用Find()和SendMessage()方法

众所周知,SendMessage()方法和GameObject.Find()方法非常昂贵,应该不惜一切代价避免使用。在有些时候,如场景初始化期间调用Find()是可以原谅的,例如在Awake()或Start()回调期间。即使在这种情况下,它也只能用于获取已经确定存在于场景中的对象,以及只有少量GameObjects的场景。无论如何,在运行时使用这两种方法进行对象间通信会产生非常明显的开销,还可能丢帧。

可以采取多尔方法来解决这个问题,体量比较大,以后找个专题说说。

三、禁止未使用的脚本和对象

场景有时会变得非常繁忙,特别是构建大型的、开放的世界时,在Update()回调这种,调用代码的对象越多,它的伸缩性就越差,游戏也就越慢。然而,如果许多正在处理的内容在玩家的视野之外,或者只是太远而显得不重要,就完全不必要处理它们。这种可能不适合建立模拟大型城市的游戏,因为必须总是处理整个仿真。但它通常适用于第一人称和赛车游戏:因为玩家活动在开阔的区域,而非可视对象可以临时禁用,而不会对游戏过程产生任何明显的影响。下面来介绍两种禁用方式:

3.1通过可见性禁用对象

有时,希望组件或GameObject在不可见时禁用。Unity带有内置的渲染功能,以避免渲染对玩家的相机视图不可见的对象, 避免渲染隐藏在其他对象后面的对象,但这些只是渲染层的优化。它不会影响在CPU上执行任务的组件,比如AI脚本、用户界面和游戏逻辑。我们必须自己控制这种行为。

解决这个问题的一个好方法是使用OnBecameVisible()和OnBecameInvisible()回调。顾名思义,这些回调方法是在可渲染对象对于场景中的任何相机变得可见或不可见时调用的。此外,当一个场景中有多个摄像机时,只有当对象对任何一个相机可见,以及对所有相机不可见时,才会分别调用这两个回调。这意味着上述回调将在预期的正确时间调用;

由于可见性回调必须与渲染管线通信,因此GameObject必须附加上一个可渲染的组件,例如MeshRenderer或SkinnedMeshRenderer。必须确保希望接受可见性回调的组件也与可渲染对象连接在同一个GameObject上,而不是连接到其父或子GameObject上,否则它们也不会调用。

提示:要注意,Unity还计算Scene窗口中对 OnBecameVisible()和OnBecameInvisible()回调隐藏的摄像头数。如果发现在播放模式测试期间,这些方法没有被正确调用,请确保将Scene窗口的摄像机背对所有对象,或完全禁用Scene窗口

为了使用可见性回调开启/禁用独立组件,需要添加下述方法:

 void OnBecameVisible() { enabled = true; }void OnBecameInvisible() { enabled = false; }

为了开启/禁用Component所附加的整个GameObject,可以下面的方式实现方法:

void OnBecameVisible() { gameObject.SetActive(true); }
void OnBecameInvisible() { gameObject.SetActive(false); }

不过,请注意,禁用包含可渲染对象的GameObject或它的父对象之一,就不可能调用OnBecameVisible(),因为现在摄像机没有图形表示来查看和触发回调。应该将组件放在一个子GameObject上,并让脚本禁用它,使可渲染的对象始终可见。

3.2通过距离禁用对象

在其他情况下,如果组件或GameObject离玩家够远,以至于看不见,就可以禁用它们。原神中的原魔就是在玩家走进后才会出现的。

下面的代码是一个简单的协程,定期检查与给定目标的总距离,太远就禁用自己

 [SerializeField] GmeObject _target;[SerializeField] float _maxDistance;[SerializeField] int _coroutineDelay;void Start(){StartCoroutine(DisableAtADistance());}IEnumerator DisableAtADistance(){while (1){float distSqrd = (transform.position - _target.transform.position).sqrMagnitude;if (distSqrd < _maxDistance * _maxDistance){enabled = true;}else{enabled = false;}for (int i = 0; i < _coroutineDelay; i++){yield return new WaitForEndOfFrame();}}}

四、使用距离平方而不是距离

可以肯定地说,CPU比较擅长将浮点数相乘,但不擅长计算它们的平方根。每次使用magnitude属性或Distance()方法要求Vector3计算距离时,都会要求它执行平方根计算,与许多其它类型的向量数学计算相比,这会消耗大量的CPU开销。

然而,Vector3类也提供了sqrMagnitude属性,它提供了同样可作为距离的结果,只是该值时平方。这意味着如果也将需要比较的距离进行平方,就可以执行基本相同的比较,而不需要昂贵的平方根计算。

用这两种方式的结果几乎相同,原因是浮点精度。可能会失去一些使用平方根的精度,因为该值调整为具有不同密度的可表示数字区域;它可以准确地落在一个更精确的可表示数字区域,更有可能落在一个精度较低的数字区域上。结果,比较并不完全相同,但是,在在大多数情况下,它非常接近,不会引起注意,对于这种方式替换的每条指令,性能收益可能相当可观。

如果这个小的精度损失不重要,那么应该考虑这个性能技巧。然而,如果精度是非常重要的,就可能要忽略这个技巧。

注意,此技术可用于任何平方根计算。而不只是用于距离。这是最常见的示例,它揭示了Vector3类的sqrMagnitude属性的中亚行。这是Unity Technologies有意以这种方式向我们展示的一个属性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173189.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅谈安科瑞ASJ继电器在马尔代夫环岛水上排屋的应用

摘要&#xff1a;对电气线路进行接地故障保护&#xff0c;方式接地故障电流引起的设备和电气火灾事故越来越成为日常所需。针对用户侧主要的用能节点&#xff0c;设计安装剩余电流继电器&#xff0c;实时监控各用能回路的剩余电流状态。通过实时监控用能以及相关电力参数、提高…

长期用台灯影响视力吗?备考专用护眼台灯推荐

大家都知道台灯作为一种小范围的桌面照明灯具&#xff0c;在夜晚能给我们带来很大的帮助&#xff0c;不管是办公、还是学习、阅读都需要它提供照明。那么长期使用台灯会影响视力吗&#xff1f;其实台灯一般都眼睛都是没有伤害的&#xff0c;真正对眼睛有伤害的是不正确的使用台…

小内存服务器生存指南 ——SWAP 虚拟内存

人们常说,网络是服务器的生命线,没有了网络,服务器再怎么牛逼,都跑不起来。然而偏偏有这么一票的服务器,它的网络很好,CPU 也很好,就是内存有点小。他们是主机界的独行侠 —— 入门级 VPS 服务器。 前俩天买的一台 TMT 的服务器就是这个类型: 256M 内存CPU 1vCore (2.…

C++学习之路(七)C++ 实现简单的Qt界面(消息弹框、按钮点击事件监听)- 示例代码拆分讲解

这个示例创建了一个主窗口&#xff0c;其中包含两个按钮。第一个按钮点击时会显示一个简单的消息框&#xff0c;第二个按钮点击时会执行一个特定的操作&#xff08;在这个例子中&#xff0c;仅打印一条调试信息&#xff09;。 功能描述&#xff1a; 创建窗口和布局&#xff1a;…

业务编码生成规则

在开发中&#xff0c;咱们有很多时候需要自定义编码&#xff0c;而不是使用uuid或者是自增ID。 本章就介绍一个自定义业务编码的生成规则。 import lombok.AllArgsConstructor; import lombok.Getter;/*** author: mcs* Date: 2022/11/27 10:00* Description: 业务编码类型及其…

力扣labuladong——一刷day53

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣1485. 克隆含随机指针的二叉树二、力扣1490. 克隆 N 叉树三、力扣133. 克隆图四、力扣138. 随机链表的复制 前言 复制带有随机指针的二叉树或者链表&am…

Java 文件常用操作与流转换

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

正向代理和反向代理

正向代理和反向代理是常用的代理方式。 正向代理是代理服务器为客户端&#xff08;如浏览器&#xff09;提供服务。一般来说&#xff0c;客户端发起请求&#xff0c;请求会被代理服务器所截获&#xff0c;代理服务器向目标服务器发送请求&#xff0c;目标服务器将响应发送给代…

Java基础之注解

Java基础之注解 一、Java注解1.1、内置注解1.2、元注解1.3、自定义注解 一、Java注解 注解&#xff08;Annotation&#xff09;是一种为程序代码提供元数据&#xff08;metadata&#xff09;的方式。注解提供了关于程序代码的额外信息&#xff0c;这些信息可以在运行时或编译时…

前端项目部署自动检测更新后通知用户刷新页面(前端实现,技术框架vue、js、webpack)——方案一:编译项目时动态生成一个记录版本号的文件

前言 当我们重新部署前端项目的时候&#xff0c;如果用户一直停留在页面上并未刷新使用&#xff0c;会存在功能使用差异性的问题&#xff0c;因此&#xff0c;当前端部署项目后&#xff0c;需要提醒用户有去重新加载页面。 技术框架 vue、js、webpack 解决方案 编译项目时动…

GPS北斗对时服务(时间同步系统)电力变电站应用方案

GPS北斗对时服务&#xff08;时间同步系统&#xff09;电力变电站应用方案 GPS北斗对时服务&#xff08;时间同步系统&#xff09;电力变电站应用方案 1.概述 在现代电网中&#xff0c;统一的时间系统对于电力系统的故障分析、监视控制及运行管理具有重要意义。变电站的对时是指…

GEE——利用Landsat C02 T1_L2数据进行某研究区的长时序(1985-2023年)NDVI和FVC计算

本教程的主要目的是在2022年底GEE已经不提供LandsatC01数据,所以这里给大家提供数据质量更高的C02数据集,这样我们就可以更快的切换过来。本教程主要目的就是实现NDVI和FVC长时序的计算,从而看某个区域的时空变化特特征。 数据介绍 Landsat C02 T1_L2数据是Landsat 8卫星(…

内网隧道学习

默认密码&#xff1a;hongrisec2019 一.环境搭建 网卡学习 一个网卡一个分段&#xff0c;想象成一个管道 192.168.52一段 192.168.150一段 仅主机模式保证不予外界连通&#xff0c;保证恶意操作不会跑到真实机之上 52段是内部通信&#xff0c;150段属于服务器&#xff08;…

数据结构 / 结构体指针

1. 格式 struct 结构体名{数据类型 成员1;数据类型 成员2; .... };struct 结构体名 *指针变量名 2. 结构体指针指向普通变量的地址 struct CAR{char name[10];int price; };struct CAR car{"byd",160}; struct CAR *p&car; //p是指向结构体变量car的指针// p…

使用重试和回退机制确保 Spring 微服务中的 API 弹性

在当今的数字环境中&#xff0c;应用程序严重依赖外部 HTTP/REST API来实现各种功能。这些 API 通常会编排复杂的内部和外部 API 调用网络。这创建了一个依赖网络。因此&#xff0c;当依赖的 API 发生故障或停机时&#xff0c;面向主要应用程序的 API 需要熟练、优雅地处理这些…

实验五 键盘按键与数码管显示(汇编与微机原理)

键盘按键与数码管显示 实验目的&#xff1a; 熟悉星研集成开发环境&#xff0c;掌握微机接口程序编写调试的基本方法。 掌握矩阵式键盘的工作原理及识别键盘按键的方法。 掌握8段数码管显示数字或字符的工作原理和它的使用方法。 掌握用8255扫描键盘及用8255刷新数码管显示…

优秀的员工成为公司的管理者之后,为何表现平庸?因为他们缺乏这些思维

在企业的实践中&#xff0c;我们发现平时能力最强的员工&#xff0c;在被提拔到管理层之后就慢慢变得平庸了&#xff0c;再也不是以前那个无所不能的“企业能人”了&#xff0c;甚至在一些事情的处理上还会有些笨拙。面对这种情况&#xff0c;我们一定会感觉很疑惑&#xff0c;…

Eclipse和Intellij IDEA的格式化代码快捷键

Eclipse和Intellij IDEA的格式化代码快捷键 eclipse的格式化快捷键是 Windows/Linux: Ctrl Shift F Mac: Cmd Shift F 按下这个组合键将会对当前编辑的代码进行格式化&#xff0c;使其符合你在Eclipse配置中定义的代码样式规范。你可以在Eclipse的偏好设置中配置代码格式化…

PC8231(CC/CV)5V/2.4A同步降压芯片 频率可调 限流欠压补偿

一&#xff0e;概述 PC8231 是一款同步降压转换器&#xff0c; 该转换器可驱动输出 2.4A 负载电流。 设计允许 PC8231 在 9V 到40V 宽输入电压范围内工作。通过将 COMP/EN 引脚逻辑电平拉低来实现外部关断功能&#xff0c;并进入待机模式。外部补偿使反馈控制环路具有良好的线…

JavaScript 原型,原型链的特点

JavaScript 的原型&#xff08;Prototype&#xff09;和原型链&#xff08;Prototype chain&#xff09;是 JavaScript 面向对象编程中的重要概念。 原型&#xff08;Prototype&#xff09; 在 JavaScript 中&#xff0c;每个对象都有一个原型对象&#xff0c;而这个原型对象…