问答专场(精华篇):游戏开发中的物理系统
关于游戏开发中的物理系统,你知道多少?腾讯GAD邀请了腾讯前台程序专家方煜宽、朱新铭,以及《穿越火线:枪战王者》主程谢文,针对大家提出的关于物理引擎、动力学、碰撞检测技术的问题,进行了全面解答。
小编为大家整理了部分精彩问答,文末可以查看全部问答~
Q:长连接网游怎么做碰撞检测?如果是Unity客户端,在地图上,以及单位之间,怎么做碰撞检测?
朱新铭:看你对于碰撞检测是否有物理上的需求。如果只需要检查碰撞是否发生,直接在对应需要检测碰撞的物体上,绑定碰撞体XXCollider使用is trigger方式,同时设置好对应的layer,然后在PhysicsManager中,做好对应的layer设置,最后写脚本接收碰撞事件即可,相关碰撞事件可以参考官方的文档。
Q:怎样检测一个复杂的物体的碰撞?当导管进入心脏时,导管碰到心脏的壁,可以正常的运行,并且不会穿透模型。
方煜宽:导管给它设置Capsule Collider,而心脏给它设置Mesh Collider,他们的层级设置成可以互相碰撞,就可以。另外如果导管如果是可以动的话。注意给它挂一个Rigidbody,否则会有效率上的问题。
Q:U3D如何防止因速度过快穿透碰撞器?
朱新铭:最简单的方法是,可以在碰撞检测中设置连续动态检测来解决部分高速碰撞问题,但是性能消耗会比较大。如果是比较极端的情况,物体个体非常小而速度又非常快,需要其他更为复杂的整体方案处理。
方煜宽:1.如果你自己做的刚体移动,你的刚体从一个位置A移动到另一个位置B的的时候,先做个检测,可以从位置A发一个射线到位置B。看看有没碰到墙体的碰撞体,如果射线射到墙的C点。则刚体不应该移动到位置,而是应该移动到位置C。如果你想做到顺着墙滑动的话,就不是移动到位置C,而是移动到AB连线在墙体的投影位置。
2.如果你全交给物理引擎,可以在刚体开启连续碰撞检测Continuous Dynamic
Q:如果要制作一个手机端的3D即时战略游戏,每个模型两百个面左右,要实现同屏几百个角色近战群殴的话,请问有什么方法可以优化一下战斗系统?
方煜宽:不知道你镜头是什么样的。俯视还是有点定角度的平视。不同的方案,优化的方案也会不一样。我就按最高要求,几百个角色必要都要做表现来说一下。也就是俯视。
1.物理。几百个碰撞盒能不能受得了,这个我没有测试过不好说,你可以自己先简单测试一下。就挂boxcollider,然后把rigibody也挂上,再把动力学勾上。如果没挂刚体,性能会非常差。这里说一下另一个方案。不使u3d的碰撞系统。现在的碰撞只是检测角色之之间的碰撞。一个角色可以用一个圆柱体来表示,也就是一个点pos、一个半径r和高度h。然后把地图划分区域。如在水平上把地图分成n*m个格子。每个格子大小比角色大一些。(如果你关心高度的话就在垂直方向也要划分,划分好后有点像魔方立方体那样),然后在内存开辟一个三维数组,当角色移动到相应位置后,就把角色放在三维数组相应位置。在移动的过程,遍历角色本身所在格子周围的格子,看是否有其它角色,如果有则判断一下他们是距离是否过近pos1-pos2<r1+r2。过近则拉回到合适的位置。这样效率会高很多。
2.其它,既然要求几百个角色同屏,那面数肯定不能太高,再说手机屏幕那么小,容纳几百角色那角色肯定会是比较小的,你说的两百面左右。300角色才6万。手机可以支撑得住没问题,但是要注意一下,角色的骨骼不要用太多。
3.如果是平视的话。则根据离镜头的距离做LOD,比较近的用高模。远的用低模和简单的特效和shader,以及简单的动作。
Q:用虚幻4模拟汽车物理,开起来轻飘飘的(车重量设置1.5t),速度70或以上,过弯整个车身会漂移,该怎么办?
方煜宽:你是用一个刚体挂一个碰撞体。然后就给它一个力这样去实现的吗?这样出来的效果不是车子的效果,是一个力拉着一个盒子走的效果。
如果要达到比较真实的效果,是要自己去做很多东西的。每个轮胎的着地,地面支持四个轮胎,四个轮胎最后对车的扭力,还有车子悬挂系统的实现,另外不同速度时的空气阻力,地面摩擦力。一整套系统写起来后,还要调整参数来调整手感。还是比较花时间的。只有点点去调整才能调出比较好的效果。
回到你的问题,你可以这样试试。把你刚体的质心设置低一些,这样车子会比较稳一些。另外你的旋转点不要设置车子的中心点,而是车子中心偏后一点的位置,差不多后车轮那个位置。看看这样会不会好一些。
谢文:尽量把车的重心往下拉,另外试下在转弯时可以给受力侧的轮子一个支撑力,调大physic material的动摩擦力.
Q:两个都有碰撞器和刚体,控制他们成为一个整体时,碰撞失败,怎么办?
问题补充:一个车和一个球,带有碰撞器和刚体;一面墙,带有碰撞器。正常情况下,车和球都能够和墙发生碰撞,但是把球的位置用代码定在车的正前方,我们控制车顶着球去撞墙时,车不会穿透,而球却碰撞失败,穿透到了墙里面。
谢文:动态物体的位置是在每帧物理解算后决定的,如果每帧直接设置球的位置,是会出现这种问题。你可以试试在车上绑一个fixed joint,连接到球。
方煜宽:现在你只是强制修改了球的位置,其实那个时候球刚体的状态是不对的。你可以试一下,把车刚体的速度和角速度也设置给球的刚体。
Q:在帧同步中,如何让Unity自带的碰撞系统能在逻辑层执行呢?如果不用自带的碰撞,有什么好的碰撞检测库使用的呢?
方煜宽:在逻辑层执行可以用Physics.OverlapBoxNonAlloc这个系列的API。(这类API在u3d5.6.1为止,还是有bug的。可能在某些情况下,在android手机会导致崩溃)
另外如果用帧同步不能用Unity自带的碰撞系统。Unity物理引擎使用的是PhysX,会有浮点误差。
Q:Unity帧同步模式开发游戏,客户端物理碰撞不一致怎么办?
问题补充:帧同步测试,四个客户端同时运行在一台PC上,他们的逻辑同步都放在fixedupdate方法里,每隔20毫秒会发送客户端的操作信息到服务端。服务端在每50毫秒会广播所有客户端的操作信息给所有客户端,客户端收到信息后,才会在本地模拟之前的操作做2D碰撞。但是实际运行结果是,他们各自运行的结果并能保持100%的一致。我检查过,四个客户端都不存在丢帧的情况。我也没有使用任何浮点数运算,只使用了Rigidbody2D.addForce这个对刚体做了运动的模拟。请问这种情况怎么解决呢?
方煜宽:Unity用的物理physx本身是浮点误差的。你现在的问题是用了Rigidbody2D.addForce给刚体一个力。物理引擎会做物理运算得到一个刚体的状态。这些收浮点运算得出的结果也存在浮点误差。因为你是2D的碰撞,相对比较简单一些。可以根据自己的需求去做物理运算。如给一个刚体一个力,其实就是产生一个加速度,也就是牛顿第二定律。自己实现一套无浮点误差物理运算。