在游戏中,由于每一帧需要处理的数据不同,所以两帧之间的间隔时长并不固定。因此,如果在 MonoBehaviour.Update
这种按帧刷新的函数中去处理物理计算,就可能出现以下情况:
上面这张图可能代表了玩家跳跃轨迹的抛物线,在抛物线顶部,玩家可能会碰到障碍物或者拾取道具。但是由于第二帧和第三帧的间隔时间太长,从而错过了这部分。
所以,我们需要一种稳定的函数来处理物理计算,它就是 MonoBehaviour.FixedUpdate
。在 Unity 文档中,是这样描述它的:
Frame-rate independent MonoBehaviour.FixedUpdate message for physics calculations.
MonoBehaviour.FixedUpdate
是一个与帧率无关的函数,它总是以“固定频率”进行更新。这里的固定频率并不是指间隔相等的时间点,而是由代码模拟出来的。相关代码很可能长这样:
public static class Time
{
public static float fixedTime;
public static float fixedDeltaTime;
public static float time;
public static float deltaTime;
}
public class Game
{
private float lastTime;
private static float fixedTimestep = 0.02f;
void Game()
{
Time.fixedDeltaTime = fixedTimestep;
}
void UpdateEachFrame()
{
var thisTime = GetRealTime();
while (Time.fixedTime + fixedTimestep <= thisTime)
{
Time.fixedTime += fixedTimestep;
// https://docs.unity3d.com/ScriptReference/Time-time.html
// When Time.time called from inside MonoBehaviour.FixedUpdate, it returns Time.fixedTime
Time.time = Time.FixedTime;
FixedUpdate();
}
Time.time = thisTime;
Time.deltaTime = thisTime - lastTime;
Update();
}
}
在 Update()
方法前,FixedUpdate()
会被调用零次或多次,具体多少次取决于每一帧的时间以及 fixedTimestep
的值。每一次 FixedUpdate()
的调用,都能保证 Time.fixedTime
是按固定间隔增长的。因此,在 FixedUpdate()
中处理物理计算,就能保证每一帧的物理计算都基于相同的时间间隔。