今天的最佳实践系列文章,将由Unity社区专家Ricardo Aguiar为大家介绍一些在游戏中使用物理效果的经验,以及帮助了解为何而使用。

图层和碰撞矩阵
如果没有预先设置,所有游戏对象都会创建在默认图层,默认情况下在这个图层中所有对象都会和对象发生碰撞。这样一来运行效率较低。所以我们需要建立各个不同对象间的碰撞关系,明确什么对象应与什么对象相互碰撞。

为此我们需要为每个类型的对象定义不同的图层。每当建立新图层时,碰撞矩阵上都会添加新的行和列。当添加一个新图层时,碰撞矩阵会默认设置该新图层与已有图层相碰撞,所以开发人员有责任对它处理并设置交互。通过正确设置图层和碰撞矩阵,将避免在碰撞器上发生不必要的碰撞和测试。

我将创建一个简单的演示项目来进行证明。在此项目中,我在方框容器里实例化了2000个对象,红色的绿色各1000个。绿色对象只会与绿色对象和容器壁碰撞,红色对象同理。

在其中一项测试中,所有实例都属于默认图层,而碰撞判断会通过对比碰撞器上游戏对象标记的字符串来完成。在另一项测试中,每个对象类型都会设置相应的图层,我将每个图层的碰撞判断都通过碰撞矩阵进行配置。这样就不需要任何字符串,因为这时只会发生正确的碰撞。

023105vbvg555qgdk26ggg.png
碰撞矩阵设置

下图是从演示项目中截取。它带有一个简单的管理器,可以计算碰撞量并自动在5秒后自动暂停。当使用相同图层时,发生不必要额外的碰撞量非常惊人。

023105pqv8l6pbbz7p38e2.png
5秒内的碰撞量

为了获取更多详细数据,我还在物理引擎上捕获了性能分析器的数据。

023106qanrbw66gksuwimt.png
相同图层 vs 分离图层:物理性能分析器数据

从分析器数据中可以看出,二种情况下物理效果的CPU占用总量相差较大,前者使用单个图层,平均约27.7毫秒,后者使用多个分离图层,平均约17.6毫秒。

光线投射
光线投射(Raycast)在物理引擎上是一个非常实用和强大的工具。它能让我们以指定长度发射光线到指定方向,还能在光线碰到东西时告诉我们。这个功能操作的性能资源消耗较大,会受到光线长度和场景中碰撞体类型的很大影响。

下面是一些有助于使用光线投射的小建议:
1、使用最少的光线数量来完成任务。
2、不要将光线长度延长到比所需要的更长。光线越长,就有越多的对象要针对光线进行测试。
3、不要在FixedUpdate()函数中使用光线投射,有时候甚至没必要在Update()中使用。
4、要注意所使用的碰撞体类型。对网格碰撞体进行的光线投射会消耗大量性能资源。

使用基本碰撞体来创建子对象是个不错的解决方案,并要尝试估算网格形状。所有在刚体父对象下的子碰撞体都会作为复合碰撞体来产生行为。如果一定要使用网格碰撞体,那么至少使它们的形状凸起。

5、要明确光线应该碰到什么对象,并且要尝试确定光线投射函数上的图层遮蔽。

在官方文档中已经很好地解释了这个做法的原因,但你要在光线投射函数上明确的不是图层id而是位掩码。

所以如果你想要光线碰到所属图层id为10的对象上,那么你应该明确规定的是1<<10(位数会从1移动到10x)而不是10。

如果你想要光线能够碰到除了图层10以外的所有对象,那么只要使用位反转运算符(~)来逆转位掩码上的每一位即可。

我开发了一个简单的演示项目,里面的对象会发射只与绿色方块碰撞的光线。

023106aomouuojbgxskoez.png
简单的光线投射演示场景

在那之中,我会控制光线的数量和长度,得到一些性能分析器数据进行验证。我们可以从下方的图表看出光线数量和长度对性能的影响。

023107oa9againyahhnu5f.png
光线数量对性能的影响

023107h7rrrpa22heu979f.png
光线长度对性能的影响

同样为了进行验证,我决定使它能够从常见的基本碰撞体切换到网格碰撞体。

023108td5jswtr7eawfc5z.png
网格碰撞体场景,每个碰撞体有110个顶点

023108xgmtyovyqtvlzmxm.png
基本碰撞体 vs 网格碰撞体:物理性能分析器数据

从性能分析图中可以看出,针对网格碰撞体的光线投射会让物理引擎在每帧执行更多工作。

2D物理 vs 3D物理
要选择对你项目最适用的物理引擎,不同物理引擎之间存在着性能差异。如果你正在开发一个2D或2.5D游戏,使用3D物理引擎的话就太过浪费,因为额外维度会造成项目中不必要的CPU占用。

刚体
在添加对象之间的物理交互时,Rigidbody刚体组件是必不可少的组件。即使使用碰撞器作为触发器,我们也需要将它们添加到游戏对象上,从而使OnTrigger事件正常工作。

没有刚体组件的游戏对象会被看做静态碰撞体。这点至关重要,因为移动静态碰撞体的运行效率极低,这样做会迫使物理引擎完全重新计算物理世界里的所有内容。幸运的是,当你移动静态碰撞体时,性能分析器会通过在CPU性能分析器的警告标签页添加警告内容来提醒你。

为了更好证明移动静态碰撞体的影响,我在第一个演示中,移除了所有移动对象中的刚体,然后从中采集新的性能分析器数据。

023109zuxbv9y9hxvev7g8.png
移动静态碰撞体时的警告

从上图中可以看出,共生成了约有2000多条警告,每个警告都是针对移动的游戏对象给出的。在物理效果上消耗的平均CPU占用量从约17.6毫秒升高到了约35.85毫秒,这个变化相当大。当移动游戏对象时,必须向其添加刚体。如果想要直接控制它的移动,只需在刚体属性中将其标记为kinematic即可。

固定时间步长
修改时间管理器(Time Manager)上的固定时间步长(Fixed Timestep)可以直接影响FixedUpdate()和物理更新速率。

通过修改这个数值,我们可以尝试在精确度和CPU在物理效果的时间占用上,达到很好的折衷。

小结
所有已讨论主题的配置和实现过程都十分简单,而且它们都会对项目的性能产生较大影响,这是因为几乎所有游戏都将使用物理引擎,即使只用于碰撞检测功能也需要用到它。

后续我们会分享最佳实践的一系列教程文章,内容涵括:UI的优化、图形的优化、Unity中的内存管理等。尽请期待! 更多Unity的技术教程尽在Unity官方中文论坛(UnityChina.cn) !
最佳实践, 实践, 物理, 优化, 教程锐亚教育

锐亚教育 锐亚科技 unity unity教程