关于Unity中FixedUpdate()的意义已经在网络上有很多了,这里不再赘述那些,只是记录一下我对它的理解。
首先,关于FixedUpdate(),能不用就不用。因为它是一个固定帧率调用的方法,默认是50帧。它额外于Update方法独立运行,尤其对于配置较低的电脑来说,游戏的帧率可能都没有50帧,再额外来个50帧的负载,对性能会有影响。另外,Unity默认50帧,这个数字其实看起来怪怪的。我们都知道游戏的最低理想帧率是60,这个默认50帧的设定我想本来就是考虑到性能消耗的结果。
当然如果你在网上搜索,会搜到FixedUpdate()其实是用于物体运动控制的方法。因为Update会受到游戏运行帧率影响,调用有快有慢,所以用调用帧率相同的FixedUpdate()来处理就会防止物体运动速度随着帧率波动。这种说法是对的,但是在实际操作过程中又有问题。首先要明确的是这里指的物体移动是利用Rigidbody组件移动,当然,你会在网上搜到类似Unity中控制物体移动不推荐使用transform.Translate这样的内容。实际上这完全依据你的实际使用情况,没有什么推荐不推荐的。这里就说Rigidbody,控制其运动的方法在于给他的velocity变量赋值即可,赋值越大跑的越快。而只要velocity不是0,物体就不会停。所以首先不用在FixedUpdate()中赋值,同样也不用在FixedUpdate()中将其置0好让物体停下来。所以除非是精确控制,可以尽量不用FixedUpdate()。那么什么是精确控制呢?比如让物体从A点移动到B点,我们给在A点的物体的RigidBody一个朝向B点的velocity,现在物体开始动了。然后,问题是什么时候停下来,如何在程序中体现物体到达B点这个状态。这里我们要物体精确停留在B点,所以有个很容易想到的方法就是在物体运动的时候不断测量自己与B点的距离,如果距离非常小了就认为到了B点。那么这个测量距离的方法就要写在FixedUpdate()中。因为Rigidbody的运行方法是依照固定频率来的,即可以这么理解,它没写在FixedUpdate()中,但是也是在FixedUpdate()中更新自己的位置。所以在FixedUpdate()检测距离,其检测的频率刚好就和Rigidbody更新自己位置的频率一致,所以控制就很准确。
除此以外,就是配合TIme.timeScale使用。我们都知道一种情况就是,如果是游戏,那么当我呼出菜单或者其他情况下,游戏是会暂停的。那么这里就会利用timeScale来完成。但是问题是,我们这个时候并不希望程序这个时候真的全部暂停。很简单就能理解,呼出菜单后游戏暂停,但是菜单本身属于UI界面,我并不希望菜单本身也暂停。再比如游戏中有一些过场演出,在演出的同时,我需要游戏内物体停止运动,但是演出本身不能停止。这时timeScale的用处就体现出来了,它只会暂停FixedUpdate()的调用,而不会暂停Update()的调用(timeScale = 0时,Time.deltaTime = 0)。这就方便了我们编写内容。
那么问题来了,如果一定要在Update()中移动物体,又不想让物体移动速度受帧率影响该咋办呢。这里方法有很多,我们先说上文提到的transform.Translate。其实只要看一下官方文档就能明白。
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
void Update()
{
// Move the object forward along its z axis 1 unit/second.
transform.Translate(Vector3.forward * Time.deltaTime);
// Move the object upward in world space 1 unit/second.
transform.Translate(Vector3.up * Time.deltaTime, Space.World);
}
}
官方文档中给出了上面这个例子,上面已经注释的非常清楚,物体以1 unit/second的速度移动,这个速度是固定的。其实很好理解,每一帧有长有短,但其实无论长短多少,都会体现在Time.deltaTime中。它会随着帧率下降而增加,随着帧率上升而减小。那么1秒钟内,有多少帧就会有多少次deltaTime,每次的deltaTime都是距离上一帧的时间间隔,那么所有deltaTime加起来就还是1秒。