MonoBehavior调用的优化方案

xiaoxiao2021-02-28  97

MonoBehavior调用的优化方案

本帖最后由 204有个大坑 于 2017-5-31 18:00 编辑       假如我告诉你Unity仅仅在调用MonoBehaviour函数的时候就非常浪费资源,你会怎么想?并且与你的脚本具体在做的事没有关系。如果你有上百或者上千的脚本,你应该意识到还是有一些的优化空间的。 1.魔法函数       MonoBehaviour 函数调用很慢,我指的是Update(),LateUpdate(),OnRender()等。这些就是所谓的“魔法函数”,如果你熟悉面向对象编程语言的话,这个概念看起来就像是利用反射机制去调用方法(反射就是允许你调用方法而不必知道具体接口)。反射的调用非常贵,所以Unity做每一件事情都是尽可能缓冲任何计算结果,因此,在每一帧需要调用“魔法函数”时,CPU的指令集合都会被设置成很小,但是,它依然很慢,非常慢… 2.为什么这么慢?       详细的我就不说(但是你想具体了解,可以查看文末给出的文章链接),想象一下,Unity想要尽可能灵活而容易地被使用。让一些事情变得简单花费了CPU性能,因为引擎不可能对你的游戏做出任何设想,而且还需要同时对一大堆的事情做检查,如:“魔法函数”是否用在了对的物体上,顺序是否正确,期间是否会崩溃。 3.还可以更快吗?       啊~这是我最喜欢的部分啦。是的!可以!怎样更快?你必须承担起调用Update()函数的责任,通过自定义函数并且从一个管理类来调用这些函数。这样,你就担起了update object的责任啦。可以快多少呢?这依赖于平台。我使用了这家伙的测量结果:

table2.png (9.72 KB, 下载次数: 0)

下载附件  保存到相册

2017-5-31 17:39 上传

可以看到这两者的区别是值得的。这是调用了10000次的测量结果。 写一个Manager 我写了一个非常简单的管理类命名为Boxmanager,用来管理BoxManaged脚本。Manager主要负责两个事情:1.保持被管理的物体的更新。2.Manger的Update函数被调用时,在被管理物体中的类似Update的函数也要被调用。 代码写起来应该是像这样的: [C#] 纯文本查看 复制代码 ?   01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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 [C#] 纯文本查看 复制代码 ?   01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 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          } } Enable时注册,在Disable时注销。ManageredUpdate函数将会取代“魔法函数”的Update()。我们来实现BoxManager.Update(),这样所有的BoxManaged.ManagedUpdate()都将立刻会被调用。 [C#] 纯文本查看 复制代码 ?   1 2 3 4 5 6 void Update() {          for ( int i = 0; i < _managedBoxes.Count; ++i)          {                  _managedBoxes[i].ManagedUpdate();          } } 就是这样啦!现在,在ManagerUpdate()函数中,你可以做任何原本需要在update中要做的事情。请注意,我并没有使用foreach循环。首先,它回产生少量的垃圾。其次,foreach本身就慢。 需要在意这些细节吗? 这主要取决于你所开发游戏的类型以及平台。问问你自己 –是不是有很多MonoBehaviour 对象的Update()函数被调用?它不需要Update(),或许它可以是挂在每一帧的任何东西。然后,如果是在移动平台,那就非常值得去试试!如果是PC端呢?仍然要考虑一些事情,特别是有大量的Object的时候。 有时候也需要manager,即使只是有少量的物体。在IOS的OnRender()函数上曾有一个问题(不知道现在是否已经修复)。30 ~40个物体会降低两倍的游戏性能!解决方案?一个类似前面提到的Manager,但不同的是调用的是OnRender()而不是Update()。这样是可以的。 记住,这是很多的优化策略中你可以使用的一种。这种策略非常隐蔽 –除非你非常了解它,否则你要发现它真的很困难。这就是这篇博客存在的原因。 引申阅读: https://blogs.unity3d.com/2015/12/23/1k-update-calls/ 原文作者:Tweets by @KnightsOfUnity 原文连接:http://blog.theknightsofunity.com/monobehavior-calls-optimization/ 扫描下方二维码关注 游戏蛮牛 官方微信~每日都有精选干货与你分享哟~

155547iluo7umxezrb2ekr.png (57.7 KB, 下载次数: 0)

下载附件  保存到相册

2017-5-31 17:53 上传

转载请注明原文地址: https://www.6miu.com/read-72516.html

最新回复(0)