http://forum.china.unity3d.com/thread-25087-1-9.html
在Unite Europe 2017的Keynote主题演讲中,我们为大家分享了将主机游戏《影子战术》现场移植到移动平台的过程,并分享了游戏针对移动平台进行的优化。今天这篇文章将为大家分享该游戏制作过程中总结的开发经验。
这其中的很多问题只有当你真正在制作主机游戏、手机游戏、或者处理巨量游戏内容时才会出现。如果在开发的早期就能把这些问题考虑进去,那么在开发过程中,你会更轻松,而你的游戏也会更炫酷。
Transform变化消息每当一个GameObject移动、旋转、缩放时,我们必须通知让每个与它相关的游戏系统。渲染、物理、以及该GameObject的每个父子物体,都需要被通知到,以匹配它做出的动作。随着游戏内容的增加,GameObject的数量也会暴涨,仅是发送这些消息的开销就会成为很大的性能问题。
以Unite Europe 2017上分享的项目 《影子战术》为例。
这是一个NPC以及它的所有组成部件。这张截图是他们使用Optimize Game Objects(优化游戏对象)选项,优化了骨骼绑定之后截取的。所以原始版本的NPC,除了所有的游戏对象和模型结构之外,还有NPC模型的所有骨骼。
这是一个很标准的游戏设计过程:关卡设计师设置NPC的生成对象。然后在运行时,这些生成对象会实例化一个NPC作为其子物体。Enemy_normal是NPC的根节点,它包含了用来控制NPC移动的NavAgent组件。每个NPC都有一堆的子物体来实现NPC的各个功能。这些看起来没有任何问题。
但这意味着,在每一帧,当NPC移动的时候,它必须通知这个NPC的所有子物体,告诉它们根节点的transform已经发生了变化。每一帧,每一个NPC都会发送成百上千的transform变化消息,占用大量的帧处理时间。
我们在发现Transform变化消息消耗大量帧时间的问题后,与Mimimi Productions进行了讨论,他们将NPC的生成方式做了简化处理。除了使用Optimize Game Objects之外,他们开始在场景的根节点下生成NPC,并把NPC能力相关的游戏对象都移到NPC的根节点上,使它们不会成为NavAgent组件的子对象。这样Nav Agent下面只剩下NPC的视觉与物理组件。优化过后,在他们的目标硬件平台上的帧率提高了10帧左右。
重要的事,多说几遍:
每秒钟提升了10帧!10帧!帧!
没有影响工作流程。无需返工重做大量的工作。仅仅是在他们现有的内容上做了一点改动。
Transform变化分发
从Unity 5.4开始,我们一直在尽最大努力优化所有与transform和Transform变化消息相关的代码。我们已经优化了内存布局并提供了.SetPositionAndRotation API来避免没有特定关联的改变。我们现在允许向系统注册某个特定的transform,而不是向引擎中的每个系统都广播Transform变化消息。
正在进行中的一个巨大改变是,我们将逐步迁移到一个延迟多线程TransformChangeDispatch系统。这让我们可以将所有的Transform 变化消息形成独立的队列,并在主线程之外对它们进行解析。我们正对尽可能多的系统进行迁移,分发这些通知,而不是让它们在主线程上进行同步处理。
即使有了这些改进,在开发游戏时你仍要好好考虑你的层级结构。这样能帮你节约帧执行时间,为你的玩家提供更好的游戏体验。
层级结构指南
如果有东西每一帧都会移动,确保它所有的子物体都确实需要了解位置信息。只有渲染、物理、音频或者类似的核心系统才应该出现。
在运行时动态创建的游戏对象,如果它们没有必要作为出生点对象的子物体,那就放在场景的根节点下。
你可以很方便的注册自己生成的所有内容,并通过OnEnable 和OnDisable来向它们传递出生点对象的ActiveInHeirarchy状态。
尝试将需要移动的物体进行分组,大约每个根节点50个左右的GameObject。这样,底层系统可以将你的TransformChangeDispatch任务按照每线程最优数量进行分组。可避免出现线程过于繁忙或过于空闲的情况。
结语
感谢Mimimi Productions让我们使用《影子战术》作为范例。我们还将为大家分享游戏开发相关的全局光照和多场景编辑的经验与教训,请保持关注!
|