Unity基础课程之物理引擎7-物理运动应该在FixedUpdate执行

在第2章里提到过FixedUpdate,当时解释它是物理更新,会保证稳定的时间间隔。所谓Fixed的意思就是“固定的、稳定的”。获取两次Update之间的时间间隔用Time.deltaTime,获取两次FixedUpdate之间的时间间隔用Time.fixedDeltaTime。当设备运行不流畅、帧率下降时,会发现Time.deltaTime变大了(即帧与帧之间的时间间隔变长)

但是Time.fixedDeltaTime却不会。一般Time.fixedDeltaTime会是一个固定的值(默认为0.02秒,可以通过选择主菜单的Edit→Project Settings→Time来修改)。

FixedUpdate的作用和原理解释起来不是很容易,笔者尽可能详细说明。要理解FixedUpdate,需要先理解“物理系统对于时间是非常敏感的”。下面举两个例子说明物理系统对于时间的敏感性。

(1)子弹从枪口射出,0.1秒后击中物体。假如物理更新频率不稳定,导致子弹接触物体时并没有及时检测,再晚0.02秒,子弹就已经穿过了物体。这样子弹就错过了碰撞的时机,导致后续结果完全不同。

(2)在Unity中做一个在地上弹跳的皮球,使用物理材质,弹性设置为0.8。由于没有外力作用,弹跳高度会越来越低。搭建场景做一个简单的实验,通过实验可得:默认物理帧率为50帧时,球会弹跳8次;物理帧率降低为20帧时,小球弹跳9次;物理帧率升高到100帧时,小球弹跳6次;而当物理帧率降低到10帧以下时,小球会穿过地板。

事实证明,物理更新的时间间隔会极大影响物理效果的正确性,那么为什么不把默认的50帧变得更大一些呢?这是因为物理更新次数越高,硬件的计算负担就越重。引擎设计师不得不在性能和正确性上做出取舍,默认50帧是实验验证过的最合适的选择。除此之外,物理更新不仅要保证频率高,还要保证频率稳。不稳定的频率一样会带来糟糕的效果,因此所有的物理系统处理都在引擎循环中的一个专门环节上完成。

有读者可能会深想一步:如果机器硬件确实卡顿了,例如手机或计算机正处于繁忙、无响应的状态,物理更新还能保证更新频率吗?答案是有办法间接保证这一点。

简单来说,游戏世界的时间是一个虚拟的概念,一定程度上可以人为控制。如果在某个时刻T,硬件卡顿了0.06秒,正好错过了3次FixedUpdate()的调用时机,那么在下一次有机会运行的时候,FixedUpdate()函数会补上之前错过的3次,连续执行4次,而且还会“假装”这4次的调用时间点分别是T+0.02s、T+0.04s、T+0.06s、T+0.08s。通过这样的机制,就能确保无论硬件运行是否稳定,游戏都能保证“稳定”的物理更新,避免出现奇怪的结果。作为对比,Update()函数没有这个特性!

小技巧

解决刚体移动过快的问题为了避免游戏中子弹飞行过快,错过了碰撞体或触发器,Unity的刚体具有一个“Collision Detection(碰撞检测方式)”选项,将默认的“Discrete(离散)”改为“Continuous(连续)”,就可以避免错误碰撞。它的原理大致是,高速飞行的子弹的路径在空间中是一些离散的点,通过在这些路径点之间连线,检查连线是否碰撞到物体,就能知道子弹是否碰撞到物体。

 在第2章的游戏实例中,讲解过“跟随式摄像机”的制作方法。在当时的设计里,玩家角色是在Update()函数中移动的,摄像机也是在Update()函数或LateUpdate()函数中移动的。

但是,如果玩家角色是一个通过对刚体施加力控制的小球,就可能会出现一些小问题。尝试一下会发现,如果小球是物理移动,而摄像机在Update()函数或LateUpdate()函数中移动,那么会导致屏幕有抖动的情况,画面不是很稳定,小球运动越快则抖动越明显。这是由于刚体因速度或受力而产生的运动,属于物理更新。而Update()函数和LateUpdate()函数不属于物理更新,这其中有着微妙的时间差。要解决这个问题并不难,针对物理移动的刚体,只要将跟随摄像机的移动也编写到FixedUpdate()里,抖动的问题就会消失了。

@以上内容来自《Unity3d 脚本编程与游戏开发》书籍 

你可能感兴趣的:(Unity零基础课程,unity,游戏引擎)