使用 Unity 开发 Android 游戏时如何追踪性能问题(3)

我从来没有考虑过对象的实例化会消耗多少性能,我几乎在所有地方都实例化了。我只是觉得它跟创建一个新的类的引用消耗的性能类似。但是我错了,事实上,程序花费了一些时间在 CPU 上实例化一个对象,又花费相同时间去销毁这个对象。问题在于我发现每次 UFO 攻击的时候,他妈的都会让我创建大量的激光。每个激光的实例化和销毁间隔很短很短的时间。我算了一下,大约 20-40 对象的实例化和销毁耗时 1.5 秒。减少了绘图调用是很好,但是我从未意识到 UFO 出现后实际上是实例化消耗了大量的性能。

能解决这个问题的唯一的办法是创建有序的对象池。我在场景里面创建了一个新的空的对象并调用ProjectilePool。在代码里创建了一些新的 Projectiles ,我废弃了以前在 Projectiles  list 里去查找Projectile,而是在 ProjectilePool 里线查找有没有可用的 Projectile,如果有,就取得这个 Projectile 并且从新设置它的位置和状态。这样就能从新使用这个就旧的 Projectile 了。

如果我没有在 List 中找到 Projectile,我就像以前一样创建一个。但是这时 Projectile 通常会被销毁掉,而我把 Projectile 添加到 ProjectilePool 并且使它不活动。因此我现在可以将 UFO 攻击期间的CPU 的使用率降低到几乎 25%-30%。现在我的游戏运行的超级好。

总结

绘图调用等于怪兽。如果你想尽可能的减少。最好的方式是面对他们,减少你的对象使用的素材的数量。使用较少不同的纹理,试着并且调整尽量多的纹理到地图集中。如果你正在实现 2D 并且不要使用太多的光源或者像我一样,只使用只有一种颜色的纹理。然后使用使用无光源顶点颜色,没有任何参数可以被用到所有的类。这很可能减少很多次绘图调用。如果你愿意牺牲一漂亮的视觉效果,你也可以合并网格或许这还是有用的。

实例化很慢,非常慢。试着尽可能的避免实例化。试着在初始化的时候加载尽肯能多的对象,然后当你想使用的时候在引用它们。另一个很好的方式用一个对象池循环的使用旧的对象来减少实例化的数量。

当然绘图调用和实例化不仅仅是唯一的恶棍。你得记着绘图调用使用了 CPU 和 GPU,而实例化使用了 CPU。

如果在你的游戏中你有大的复杂的模块或者太多的处理要运行。仅仅减少绘图调用是不能帮助你提供速度,当然这也会使你的游戏运行的快些但不总是这样。CPU 有时是你最大的敌人。先看看你的代码,然后试着找出运行的糟糕的地方然后让它运行的更好些。

在我的游戏中,实例化,销毁和 Web 请求时最大问题。

这篇文章的结束只是下一篇开始

Sky Blocks 在 Google Play 上的下载地址
https://play.google.com/store/apps/details?id=com.Shinobytes.SkyBlocks

我使用的无光源顶点着色器

减少绘图调用到底有多重要?

"虽然绘图调用可以成为一个瓶颈,但是记住帧频才是王道。如果你的帧频是够好,那就没必要担心绘图调用。绘图调用被请求的数量是否严重的影响了性能,很大程度上取决于硬件的状况和每一帧所做的所有的事情"
— Daniel Brauer, Unity Technologies

实例化素材 VS 共享素材

实例化素材的主要的特点是一个可以让任何属性改变的素材。一个实例化素材仅仅为了一个特殊的类被实例化一次。每次的实例化都有可能会触发一次绘图调用。但是实例化之后改变他的属性是不会创建新的实例的,而仅仅是修改了当前的实例。然而共享的素材是使用了相同的着色器和其他相同的属性的素材。Unity 是可以对素材分组并且批处理所有对象来使用这个素材。自从我用了无光源着色器就没有在代码中修改过任何属性,素材也从来没有被实例化过而所有的素材都是一起被批处理的。

注意了,我将要发布一篇较详细信息的文章来介绍对于不同的对象,我是如何提高性能的,包括更多的代码实例。

但是现在,祝大家永远开心,快乐。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d00426951a2fe90b736e0a416a4f10a0.html