pc网站转wap网站,厦门做网站最好的公司有哪些,作文素材网站,五金网站建设制作大家好#xff0c;这里是七七#xff0c;今天又来更新Unity脚本优化篇了#xff0c;话不多说#xff0c;直接上主题。
一、注意缓存Transform的变化
Transform组件只存储与其父组件相关的数据。这意味着访问和修改Transform组件的position、rotation和scale属性会导致大量…大家好这里是七七今天又来更新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有意以这种方式向我们展示的一个属性。