物理系统最佳实践
本文将由Unity 技术支持团队根据多年的经验总结,为大家讲解在游戏中使用物理的最佳实践,并通过一些案例来演示为何要这么用。
所有的游戏对象创建时如果未设置层,则默认位于Default层,位于Default层表示可以与一切事物发生碰撞。这样做非常低效。我们应当为各层设定好能够发生碰撞的对象。为此,应当为不同类型的对象定义不同的层级。每新添加一个层级,碰撞矩阵中就会新添加一行和一列。该矩阵用于定义不同层之间的交互关系。
默认情况下,新添加的层在碰撞矩阵中被设置为可以与其它所有层发生碰撞,所以开发者需要手动设置新层间的交互关系。正确设置好层和碰撞矩阵,可以避免很多不必要的碰撞和碰撞检测。这里创建了简单的Demo进行演示,Demo是在一个盒状容器中实例化了2000个对象(1000个红色,1000个绿色)。物体只会与相同颜色的物体以及容器壁产生交互。
在Demo的其中一个测试中,所有物体的层都设为Default,然后通过比较碰撞监听函数中不同游戏对象的标签字符串来判断是否进行交互。而在另一个测试中,每种颜色的物体都位于单独的层,然后设置碰撞矩阵来定义层间的交互。这样就不需进行字符串比较了,碰撞只会发生在正确的层上。
图1:碰撞矩阵配置
图2:五秒的碰撞次数
图3:相同层和不同层在物理分析器中的数据比较
正如在分析器中所观察到数据情况,两个测试对于物理计算上的CPU消耗截然不同。使用相同层平均消耗约27.7毫秒,不同层平均消耗约17.6毫秒。
第一条很明显,就是使用尽可能少的射线来完成。
按需设置射线长度,不要过长。射线越长,需要与之进行碰撞检测的物体就越多。
不要在FixedUpdate()函数中使用射线投射,有时即使是在Update()函数中,射线投射也会导致过多的消耗。
注意使用碰撞器的类型,射线投射与网格碰撞器进行交互的性能消耗是相当大的。
比较好的解决方案是使用多个基础碰撞器组合出网格形状。可以将父节点Rigidbody下所有的子碰撞器作为混合碰撞器使用。
如果非得使用网格碰撞器,至少将其设为凸面。
为了明确射线会碰撞到哪些物体,应当在Raycast函数中指明层级遮罩(Layer Mask)。
这在官方文档中给出了详细说明,在Raycast函数指定的是位掩码而非层ID。
如果希望射线射向ID为10的层,在Raycast函数中应当设置参数为1 << 10(将' 1 '左移10位)而非直接设为10。
如果希望射线击中除了层为10以外的所有对象,可以使用位运算符(~)轻松对位掩码按位取反。
下面的Demo展示了射线只与绿色盒子发生碰撞的情况。
图4:简单的射线投射Demo场景
通过操作射线的数量和长度,来验证之前提到的数据分析。可以从下图中发现,射线的数量和长度对性能影响极大。
图5:射线数量对性能的影响
图6:射线长度对性能的影响
图8:基础碰撞器和网格碰撞器在物理分析器中的情况
正如分析器截图所示,射线投射与网格碰撞器的碰撞检测在每帧都增加了不少工作。
请点击活动标题,了解活动详情,报名参与!
活动一:女性开发者论坛
活动时间:7月28日 9:00 ~ 12:00
活动地点:上海浦东嘉里大酒店
活动内容:聚焦女性在游戏行业的发展与未来!
活动时间:7月29日 9:00 ~ 18:00
活动地点:上海淳大万丽酒店
活动内容:实战演练Unity 2D与3D游戏开发!
活动三:Unity 两岸开发者交流
活动时间:7月28日 18:00 ~ 19:30
活动地点:上海浦东嘉里大酒店
活动内容:两岸开发者互相分享Unity案例!
活动四:Unity Ads Open Day开放日
活动时间:7月29日 9:00 ~ 18:00
活动地点:上海浦东嘉里大酒店
活动内容:分享Unity Ads广告服务实现游戏推广与盈利!
活动五:Unity官方认证考试
考试时间:7月30日 10 : 00 ~ 11 : 30
考试地点:Unity大中华区办公室
让我们相聚7月,相聚ChinaJoy!
我们还会分享更多Unity相关的技术内容在Unity官方中文论坛(forum.china.unity3d.com),请保持关注!