本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/70921049
作者:cartzhang
本文同步与游戏蛮牛。
MonoBehavior的调用优化
如果告诉你,Unity由于调用你的MonoBehaviour函数而造成CPU性能大量浪费?真的与你的脚本无关么?若你有成千上百个呢,你应该了解一个新的优化领域。
魔术技巧
MonoBehaviour函数调用缓慢。我们谈论的是像Update(),LateUpdate(),OnRender()等函数。这里所谓的魔术技巧,若你熟悉面向对象语言编程,这个概念就像是使用反射机制(反射让你即使不知道接口也可以调用方法)。反射的调用非常消耗,所以unity尽可能的缓存任何操作,这样所需要的CPU指令集来每帧调用魔术方法就可能很少。但是,依旧很慢,很慢…
为什么这么慢啊?
我不打算讨论具体细节(若真需要了解细节,可以阅读文章后面的链接)(译者注:反射原理),所以只想象Unity试图尽可能的灵活和易用。制造一些容易的东西容易增大CPU功耗,因为引擎不能假设你要做的游戏,它需要做很多检测来保证魔法函数被正确对象以正确顺序调用,且不能崩溃。
可以更快么?
这是我最喜欢的部分了。是的,当然可以!怎么做呢?你需要通过自定义的函数,并负责从一个管理器中调用Update()函数。这样一来,自己负责更新对象。会有多快呢?这个取决有平台。让我们使用Valentin Simonov在Unity官方博客上做的对比:
这里你可以看到不同的时间消耗。这个是测试了调用Update 10000次的结果。
写一个管理器
将介绍一个简单例子,一个名为BoxManager的管理器,用来管理被管理的脚本。
管理器有两个职责:
保持管理对象的列表已更新,
当管理器Update()被调用时,调用受管对象类的更新功能。
代码可能如下所示:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class BoxManager : MonoBehaviour
{
public static BoxManager Instance { get; private set; }
public List<BoxManaged> _managedBoxes = new List<BoxManaged>();
void Awake()
{
Instance = this;
}
void Update()
{
// update objects here
}
public void Register(BoxManaged box)
{
_managedBoxes.Add(box);
}
public void Unregister(BoxManaged box)
{
_managedBoxes.Remove(box);
}
}
如你所见,它看起来很简单。在使用Update函数之前,我们看看BoxManaged.cs。
using UnityEngine;
public class BoxManaged : MonoBehaviour {
private Vector3 _position;
private Transform _transform;
void OnEnable()
{
BoxManager.Instance.Register(this);
}
void OnDisable()
{
BoxManager.Instance.Unregister(this);
}
public void ManagedUpdate()
{
// do what you normally do in Update here
}
}
当可以使用和被禁用的时候都会自动注册。很公平,ManagedUpdate()函数代替Update()这个魔法函数。我们来实现BoxManager.Update(),这样它就会立刻调用所有的BoxManaged.ManagedUpdate()。
void Update()
{
for (int i = 0; i < _managedBoxes.Count; ++i)
{
_managedBoxes[i].ManagedUpdate();
}
}
就是这样。真的!现在你可以在ManagedUpdate()中实现你平时在Update()中处理的任何内容。
请注意,我并没有使用foreach来迭代。首先,因为在unity的Mono版本中它会产生少量的GC垃圾。其次,它看起来似乎较慢。(译者注:在Unity5.5 beta后就不是问题了)
我该在意这个么?
这取决于你的游戏类型和目标平台。问下自己——你有很多MonoBehaviour对象调用Update()么?它不一定需要Update(),它可以是每帧调用的任何对象。然后,若针对的是移动平台,绝对值得一试!单机平台?依旧值得考虑,尤其是你有大量的对象。
尽管你的对象数量较少,有时候你可能还是需要一个管理器。在IOS上(我不知道是否已经修复)OnRender()函数有问题。在30-40个对象可能会让游戏的性能降低两倍!解决方案?像上面提到的管理器,不是调用Update(),而是OnRender()代码。是的,效果很明显。
请记住,这是您可以使用的许多优化策略之一。 然而,这一个很隐蔽 - 除非你知道,否则你将很难找到这个。 这就是为什么这篇文章产生的原因。
参考
https://blogs.unity3d.com/2015/12/23/1k-update-calls/
原帖地址:http://blog.theknightsofunity.com/monobehavior-calls-optimization/
作者:The Knights of Unity
蛮牛地址:http://manew.com/forum.php?mod=viewthread&tid=103317&page=1&extra=#pid1417941
若有问题,请随时联系!!
感谢浏览,欢迎点赞!