Unity 的时间逻辑
Unity 的时间逻辑
与时间相关的属性
Unity 中有一些与时间相关的数值属性,它们都在Time库中:
Time.time表示从游戏开始运行以来到当前帧经过的时间
Time.fixedTime表示从游戏开始运行以来到最近一次执行FixedUpdate()经过的时间
Time.deltaTime表示从上一帧到当前帧经过的时间
Time.timeScale控制时间流逝的速度
Time.fixedDeltaTime表示固定帧率之间的时间间隔
Time.maximumDeltaTime表示两帧之间时间间隔的上限
Time.unscaledTime表示从游戏开始运行以来到当前帧经过的时间(不受Time.timeScale和Time.maximumDeltaTime影响)
Time.realtimeSinceStartup表示从游戏开始运行以来经过的实际时间(不受游戏暂停影响。在同一帧内多次调用返回结果可能不同,同样在不同帧内多次调用返回结果也可能相同)
Time.unscaledDeltaTime表示从上一帧到当前帧经过的时间(不受Time.timeScale和Time.maximumDeltaTime影响)
可变时间步长和固定时间步长
Unity 中存在两种基于“时间”进行事件处理的系统,一种基于“可变时间步长”,另一种基于“固定时间步长”。
“可变时间步长”系统的两次事件处理之间的时间间隔是不固定的,在该系统中,每在屏幕上绘制一帧执行一次事件处理。
“固定时间步长”系统每隔一个固定的时间间隔执行一次事件处理,通常它与物理模拟相关,当然如果需要也可以在该系统中执行你自己的代码。
可变时间步长
我们可以在Update()方法中定义要在可变时间步长系统中执行的代码,也就是说,这些代码会每帧执行一次。
注意由于不同设备(或同一设备不同情况)绘制一帧所需的时间是不固定的,通常需要在Update()方法中使用Time.deltaTime对代码产生的副作用(例如物体移动的距离)进行缩放,以保证不管游戏的帧率是多少,在相同的时间内可以产生一致的结果。
例如在下面的例子中,通过Update()方法读取用户的输入,并以每秒1米的速度移动对象。
using UnityEngine;
using System.Collections;
public class CubeController : MonoBehaviour
{
public float speed = 1.0f;
void Update()
{
// 从 Input 类中获取用户输入
float xAxis = Input.GetAxis("Horizontal");
float zAxis = Input.GetAxis("Vertical");
Vector3 pos = transform.position;
Vector3 step = new Vector3(xAxis, 0, zAxis).normalized * speed * Time.deltaTime;
pos.x += step.x;
pos.z += step.z;
transform.position = pos;
}
}
固定时间步长
在固定时间步长系统中执行的代码在FixedUpdate()中定义,“固定时间步长”系统会在每一帧开始时,尽可能多地调用FixedUpdate(),直到赶上当前时间(在下面的时间逻辑图中查看更多的细节)。
Unity 的物理系统也以固定时间步长运行,如果要执行物理相关的代码(例如为一个刚体施加力),也必须在FixedUpdate()中处理。
根据帧率的不同,FixedUpdate()可能在一帧内运行0次到多次。因为FixedUpdate()可能会在某一帧不执行,所以不能在FixedUpdate()中读取输入,可能会因此错过用户的输入。
时间逻辑图
以下流程图说明了 Unity 用于计算单个帧中时间的逻辑,以及time、deltaTime、fixedDeltaTime和maximumDeltaTime属性如何相互关联。

- 将当前时间减去上一次记录的时间,得到
deltaTime - 判断
deltaTime是否大于maximumDeltaTime,如果是,则将deltaTime限制为maximumDeltaTime - 将
deltaTime加到time中,更新time - 判断
time和fixedTime的时间差是否不小于fixedDeltaTime,如果是,跳到5,否则跳过7 - 将
fixedDeltaTime加到fixedTime中,更新fixedTime - 调用
FixedUpdate(),然后回到4 - 调用
Update() - 回到1,重复循环
注
以上顺序只是描述了 Unity 事件循环中与时间相关的部分,完整的事件循环请查阅事件函数的执行顺序 - Unity 手册。
通过这张时间逻辑图,就可以更好地理解上面已经提到的“在每一帧开始时(Update()执行前),尽可能多地调用FixedUpdate()”的含义,以及在整个时间循环中,Time.time、Time.deltaTime和Time.fixedTime的变化机制
