总结使用Unity 3D优化游戏运行性能的经验

转自:http://gamerboom.com/archives/76214程序员

做者:Amir Fasshihi编程

流畅的游戏玩法来自流畅的帧率,而咱们即将推出的动做平台游戏《Shadow Blade》已经将在标准iPhone和iPad设备上实现每秒60帧视为一个重要目标。缓存

如下是咱们在紧凑的优化过程当中提高游戏运行性能,并实现目标帧率时须要考虑的事项。ssh

当基本游戏功能到位时,就要确保游戏运行表现可以达标。咱们衡量游戏运行表现的一个基本工具是Unity内置分析器以及Xcode分析工具。使用Unity分析器来分析设备上的运行代码真是一项宝贵的功能。ide

咱们总结了这种为将目标设备的帧率控制在60fps而进行衡量、调整、再衡量过程的中相关经验。函数

  1、遇到麻烦时要调用“垃圾回收器”(Garbage Collector,无用单元收集程序,如下简称GC)工具

因为具备C/C++游戏编程背景,咱们并不习惯无用单元收集程序的特定行为。确保自动清理你不用的内存,这种作法在刚开始时很好,但很快你就公发现本身的分析器常常显示CPU负荷过大,缘由是垃圾回收器正在收集垃圾内存。这对移动设备来讲尤为是个大问题。要跟进内存分配,并尽可能避免它们成为优先数,如下是咱们应该采起的主要操做:性能

1.移除代码中的任何字符串链接,由于这会给GC留下大量垃圾。优化

2.用简单的“for”循环代替“foreach”循环。因为某些缘由,每一个“foreach”循环的每次迭代会生成24字节的垃圾内存。一个简单的循环迭代10次就能够留下240字节的垃圾内存。动画

3.更改咱们检查游戏对象标签的方法。用“if (go.CompareTag (“Enemy”)”来代替“if (go.tag == “Enemy”)” 。在一个内部循环调用对象分配的标签属性以及拷贝额外内存,这是一个很是糟糕的作法。

4.对象库很棒,咱们为全部动态游戏对象制做和使用库,这样在游戏运行时间内不会动态分配任何东西,不须要的时候全部东西反向循环到库中。

5.不使用LINQ命令,由于它们通常会分配中间缓器,而这很容易生成垃圾内存。

  2、谨慎处理高级脚本和本地引擎C++代码之间的通讯开销。

全部使用Unity3D编写的游戏玩法代码都是脚本代码,在咱们的项目中是使用Mono执行时间处理的C#代码。任何与引擎数据的通讯需求都要有一个进入高级脚本语言的本地引擎代码的调用。这固然会产生它本身的开销,而尽可能减小游戏代码中的这些调用则要排在第二位。

1.在这一情景中四处移动对象要求来自脚本代码的调用进入引擎代码,这样咱们就会在游戏玩法代码的一个帧中缓存某一对象的转换需求,并一次仅向引擎发送一个请求,以便减小调用开销。这种模式也适用于其余类似的地方,而不只局限于移动和旋转对象。

2.将引用本地缓存到元件中会减小每次在一个游戏对象中使用 “GetComponent” 获取一个元件引用的需求,这是调用本地引擎代码的另外一个例子。

  3、物理效果

1.将物理模拟时间步设置到最小化状态。在咱们的项目中就不能够将让它低于16毫秒。

2.减小角色控制器移动命令的调用。移动角色控制器会同步发生,每次调用都会耗损极大的性能。咱们的作法是缓存每帧的移动请求,而且仅运用一次。

3.修改代码以避免依赖“ControllerColliderHit” 回调函数。这证实这些回调函数处理得并不十分迅速。

4.面对性能更弱的设备,要用skinned mesh代替physics cloth。cloth参数在运行表现中发挥重要做用,若是你肯花些时间找到美学与运行表现之间的平衡点,就能够得到理想的结果。

5.在物理模拟过程当中不要使用ragdolls,只有在必要时才让它生效。

6.要谨慎评估触发器的“onInside”回调函数,在咱们的项目中,咱们尽可能在不依赖它们的状况下模拟逻辑。

7.使用层次而不是标签。咱们能够轻松为对象分配层次和标签,并查询特定对象,可是涉及碰撞逻辑时,层次至少在运行表现上会更有明显优点。更快的物理计算和更少的无用分配内存是使用层次的基本缘由。

8.千万不要使用Mesh对撞机。

9.最小化碰撞检测请求(例如ray casts和sphere checks),尽可能从每次检查中得到更多信息。

  4、让AI代码更迅速

咱们使用AI敌人来阻拦忍者英雄,并同其过招。如下是与AI性能问题有关的一些建议:

1.AI逻辑(例如能见度检查等)会生成大量物理查询。可让AI更新循环设置低于图像更新循环,以减小CPU负荷。

  5、最佳性能表现根本就不是来自代码!

没有发生什么状况的时候,就说明性能良好。这是咱们关闭一切没必要要之物的基本原则。咱们的项目是一个侧边横向卷轴动做游戏,因此若是不具备可视性时,就能够关闭许多动态关卡物体。

1.使用细节层次的定制关卡将远处的敌人AI关闭。

2.移动平台和障碍,当它们远去时其物理碰撞机也会关闭。

3.Unity内置的“动画挑选”系统能够用来关闭未被渲染对象的动画。

4.全部关卡内的粒子系统也可使用一样的禁用机制。

  6、回调函数!那么空白的回调函数呢?

要尽可能减小Unity回调函数。即便敌人回调函数存在性能损失。没有必要将空白的回调函数留在代码库中(有时候介于大量代码重写和重构之间)。

  7、让美术人员来救场

在程序员抓耳挠腮,绞尽脑汁去想该如何让每秒运行更多帧时,美术人员总能神奇地派上大用场。

1.共享游戏对象材料,令其在Unity中处于静止状态,可让它们绑定在一块儿,由此产生的简化绘图调用是呈现良好移动运行性能的重要元素。

2.纹理地图集对UI元素来讲尤为有用。

3.方形纹理以及二者功率的合理压缩是必不可少的步骤。

4.咱们的美术人员移除了全部远处背景的网格,并将其转化为简单的2D位面。

5.光照图很是有价值。

6.咱们的美术人员在一些关口移除了额外顶点。

7.使用合理的纹理mip标准是一个好主意(游戏邦注:要让不一样分辨率的设备呈现良好的帧率时尤为如此)。

8.结合网格是美术人员能够发挥做用的另外一个操做。

9.咱们的动画师尽力让不一样角色共享动画。

10.要找到美学/性能之间的平衡,就免不了许多粒子效果的迭代。减小发射器数量并尽可能减小透明度需求也是一大挑战。

  8、要减小内存使用

使用大内存固然会对性能产生负面影响,但在咱们的项目中,咱们的iPod因为超过内存上限而遭遇了屡次崩溃事件。咱们的游戏中最耗内存的是纹理。

1.不一样设备要使用不一样的纹理大小,尤为是UI和大型背景中的纹理。《Shadow Blade》使用的是通用型模板,但若是在启动时检测到设备大小和分辨率,就会载入不一样资产。

2.咱们要确保未使用的资产不会载入内存。咱们必须迟一点在项目中找到仅被一个预制件实例引用,而且从未彻底载入内存中实例化的资产。

3.去除网格中的额外多边形也能实现这一点。

4.咱们应该重建一些资产的生周期管理。例如,调整主菜单资产的加载/卸载时间,或者关卡资产、游戏音乐的有效期限。

5.每一个关卡都要有根据其动态对象需求而量身定制的特定对象库,并根据最小内存需求来优化。对象库能够灵活一点,在开发过程当中包含大量对象,但知道游戏对象需求后就要具体一点。

6.保持声音文件在内存的压缩状态也是必要之举。

增强游戏运行性能是一个漫长而具备挑战性的过程,游戏开发社区所分享的大量知识,以及Unity提供的出色分析工具为《Shadow Blade》实现目标运行性能提供了极大帮助

相关文章
相关标签/搜索