Unity实现时缓机制的一些注意点
主要和物理模拟相关。
众所周知,unity中物理模拟在FixedUpdate前以Time.fixedUpdate(可在Project Setting中调整)速率进行物理模拟。
PS:Unity的物理引擎,根据官方文档显示
Built-in 3D physics (Nvidia PhysX engine integration)
Built-in 2D physics (Box2D engine integration)
当我们使用Time.scale改变时间速率时,也就是
之后,需要额外处理,来解决一些表现问题。因为由于时间变慢,但物理更新速率没变,会出现物理帧数表现不够,一卡一卡。(也就是说数值正常,但是表现卡顿)
错误做法:假设我们的时间scale为timescale,那么一个典型的“错误”做法是,令代码调用:
从表现上来说,这么做能够使得物理表现恢复“丝滑”,因为此时提高了物理更新速率。但是如果在一段物理模拟过程中,突然改变Time.fixedUpdateTime,也就是dt,那么物理模拟会出现错误。因为Unity物理模拟是实时解算,有赖于上一帧的结果和dt的稳定,此时改变dt一定会导致接下来的物理解算出错。所以这个“错误”做法不能用于物理过程中改变Time.scale。
正确做法:
第一,我们可以去Project Setting里适当降低fixedUpdateTime,以提高基础的物理模拟速率。
第二,对于RigidBody,在时缓时使用
来开启自带的插值功能,使得表现变顺滑。
第三,对于我们自己实现的(在FixedUpdate中更新的)一些位移或者旋转逻辑,我们自己去Update里实现我们自己的顺滑插值。至于怎么实现,需要我们有最基本的物理模拟插值认知。
我们自己位移逻辑的物理插值实现例子:
假设我们之前在FixedUpdate中维护了一个功能dash,用于每物理帧往一个方向冲刺:
那现在要改写。一个最简单常见的插值思路是,假定每一物理帧瞬间都是匀速直线运动,那么就可以根据上一个物理帧的位置,预测当前位置,直到下一个物理帧再硬set回正确位置。(看似暴力,但实际上可以应付99%的情况,并且在极端情况下,即使多考虑一些帧数信息也不一定能更好预测,除非上卡尔曼滤波,那就太复杂了。其实SLAM领域里也是这么做的)
改写物理帧如下:
然后在Update函数里,进行插值:
至此,Unity中实现时缓机制的一些问题就解决了。