Unity|物理系统最佳实践

本文将为大家讲解在游戏中使用物理的最佳实践,并通过一些案例来演示为何要这么用。

本文转自Unity官方论坛:forum.china.unity3d.com

将由Unity 技术支持团队根据多年的经验总结,为大家讲解在游戏中使用物理的最佳实践,并通过一些案例来演示为何要这么用。

 

层(Layer)与碰撞矩阵

所有的游戏对象创建时如果未设置层,则默认位于Default层,位于Default层表示可以与一切事物发生碰撞。这样做非常低效。我们应当为各层设定好能够发生碰撞的对象。为此,应当为不同类型的对象定义不同的层级。每新添加一个层级,碰撞矩阵中就会新添加一行和一列。该矩阵用于定义不同层之间的交互关系。

 

默认情况下,新添加的层在碰撞矩阵中被设置为可以与其它所有层发生碰撞,所以开发者需要手动设置新层间的交互关系。正确设置好层和碰撞矩阵,可以避免很多不必要的碰撞和碰撞检测。这里创建了简单的Demo进行演示,Demo是在一个盒状容器中实例化了2000个对象(1000个红色,1000个绿色)。物体只会与相同颜色的物体以及容器壁产生交互。

 

在Demo的其中一个测试中,所有物体的层都设为Default,然后通过比较碰撞监听函数中不同游戏对象的标签字符串来判断是否进行交互。而在另一个测试中,每种颜色的物体都位于单独的层,然后设置碰撞矩阵来定义层间的交互。这样就不需进行字符串比较了,碰撞只会发生在正确的层上。

 

 

图1:碰撞矩阵配置

 

下图是Demo运行截图。用一个简单的管理器来统计所有的碰撞次数,并于5秒后自动暂停。结果相当的难以置信,使用相同层会产生大量不必要的碰撞。

 

图2:五秒的碰撞次数

 

这里还通过Profiler中的物理引擎来了解更详细的数据。

 

图3:相同层和不同层在物理分析器中的数据比较

 

正如在分析器中所观察到数据情况,两个测试对于物理计算上的CPU消耗截然不同。使用相同层平均消耗约27.7毫秒,不同层平均消耗约17.6毫秒。

 

射线投射(Raycast)

射线投射是物理引擎中一个非常有用且强大的工具。使用它可以向特定方向发射一条特定长度的射线,通过这个射线就能知道它是否击中某物。然而这样的操作会产生很大的性能消耗。它的性能会受到在场景中射线的长度和碰撞器类型的巨大影响。

 

这里有一些提示,可以帮助我们更好的使用它。

 

  • 第一条很明显,就是使用尽可能少的射线来完成。

  • 按需设置射线长度,不要过长。射线越长,需要与之进行碰撞检测的物体就越多。

  • 不要在FixedUpdate()函数中使用射线投射,有时即使是在Update()函数中,射线投射也会导致过多的消耗。

  • 注意使用碰撞器的类型,射线投射与网格碰撞器进行交互的性能消耗是相当大的。

  • 比较好的解决方案是使用多个基础碰撞器组合出网格形状。可以将父节点Rigidbody下所有的子碰撞器作为混合碰撞器使用。

  • 如果非得使用网格碰撞器,至少将其设为凸面。

  • 为了明确射线会碰撞到哪些物体,应当在Raycast函数中指明层级遮罩(Layer Mask)。

  • 这在官方文档中给出了详细说明,在Raycast函数指定的是位掩码而非层ID。

  • 如果希望射线射向ID为10的层,在Raycast函数中应当设置参数为1 << 10(将' 1 '左移10位)而非直接设为10。

  • 如果希望射线击中除了层为10以外的所有对象,可以使用位运算符(~)轻松对位掩码按位取反。

 

下面的Demo展示了射线只与绿色盒子发生碰撞的情况。

 

  

图4:简单的射线投射Demo场景

 

通过操作射线的数量和长度,来验证之前提到的数据分析。可以从下图中发现,射线的数量和长度对性能影响极大。

 

图5:射线数量对性能的影响

图6:射线长度对性能的影响

 

下面演示使用网格碰撞器代替基础碰撞器的效果。

 

图7:网格碰撞器场景(每个碰撞器有110个顶点)

 

图8:基础碰撞器和网格碰撞器在物理分析器中的情况

 

正如分析器截图所示,射线投射与网格碰撞器的碰撞检测在每帧都增加了不少工作。

 

2D与3D物理系统的比较

为项目选择最合适的物理引擎,如果只开发2D游戏或2.5D游戏(2D平面上的3D游戏效果),使用3D物理引擎就太浪费了。这样会为项目带来额外的不必要的CPU消耗。可以使用下面文章中提到的方法来检测使用不同的物理引擎所带来的消耗:

 

http://x-team.com/2013/11/unity3d-v4-3-2d-vs-3d-physics/

 

刚体(Rigidbody)

Rigidbody是为对象间添加物理交互必不可少的组件。即使将碰撞器作为触发器使用,也需要为游戏对象添加刚体组件,以便OnTrigger 事件函数可以正常工作。没有刚体组件的游戏对象会被视为静态碰撞器。了解这点非常重要,因为尝试移动静态碰撞器会带来很大的性能消耗,它会迫使物理引擎重新计算整个物理世界的数据。幸运的是,当移动静态碰撞器时,分析器会在CPU分析器上添加一个警告标签给予提示。为了更好的展示移动静态碰撞器所带来的影响,我移除了之前第一个Demo中所有移动对象的Rigidbody组件,然后通过分析器重新获取数据。

 

图9:移动静态碰撞器的警告

 

如图所示,总计生成了2000个警告,每次移动游戏对象都会产生警告。CPU在物理计算上所耗费的平均时间约从17.6毫秒增长至35.85毫秒,这个增长相当惊人。因此,当移动一个游戏对象时,必须为其添加刚体组件。如果想直接控制物体的移动,只需简单的勾选Rigidbody组件的的Is Kinematic属性即可。

 

Fixed Timestep

调整Time Manager中的 Fixed Timestep值,会直接影响FixedUpdate()函数 和物理引擎的更新率。调整该值可以在物理系统的精确度和CPU耗时之间达到一个良好的平衡。

 

总结

本文所讨论的主题都可以轻松配置或实现,并且会为您的项目带来显著的性能提升,因为几乎所有项目都会用到物理引擎,即时只是碰撞检测也会有所区别

 

随着PokemonGO的大火,Unity引擎在游戏开发引擎中的地位也更加夯实了。但一款好的游戏不单纯只靠IP够大够吸引人,其本身的性能所带给玩家的游戏体验也相当重关键。为了避免手游性能方面对游戏的负面影响,可以利用一些现成的测试工具进行深度的检测,腾讯游戏品质管理团队专门打造的工具Cube目前已经可以使用,Cube”可以帮助开发者发现Unity手游内分类资源的占用情况,尤其是对Unity游戏场景中的FPS、CPU、PSS的变化趋势重点关注,帮助在Unity游戏开发过程中不断改善玩家的体验。目前功能还在免费开放中。

 

Cube

体验地址:http://wetest.qq.com/cube 

关于测试报告的问题http://wetest.qq.com/guide/view/?id=267 

使用帮助http://wetest.qq.com/guide/view/?id=266 

常见问题http://wetest.qq.com/guide/view/?id=268  

 

最新文章
1客户案例研究:专家安全扫描,守护金融银行小程序安全和私密性 WeTest私有化部署的定制扫描平台让金融银行客户能无成本接入扫描系统并迅速上手使用。客户能方便快捷地根据定制手册进行自助扫描,根据生成的扫描报告,详细洞察漏洞,快速识别并准确定位问题根源。
2客户案例研究:专家渗透测试,洞察电子商务小程序重大交易漏洞 通过WeTest渗透测试服务,某知名零售公司旗下的在线购物类小程序中发现了8处安全风险,我们的安全专家为客户提供了详细的漏洞报告,提供了较为清晰完整的安全加固方案。在回归测试中,中危以上风险均被解决。
3自查小程序4大安全隐患!文末免费赠送小程序安全扫描专业版! 腾讯WeTest现面向小程序开发者开放免费申请使用小程序安全扫描专业版,助您提前发现全面的安全漏洞。扫描文中问卷二维码或点击问卷链接,即可报名参与免费领取活动。
4浅谈渗透测试服务在泛互行业带来的价值 在泛互联网行业中,渗透测试服务对于保障企业的网络安全至关重要。
5云手机卡顿/无特定设备/商店登录受限怎么办?WeTest专有云帮您解决! 公有云满足了大量小微企业、个人的测试需求;随着客户深入使用,也遇到了一系列新问题。本篇将对几个常见问题予以解答
购买
客服
反馈