摄像机抖动
本课属于 Coddy Unity 学习旅程的“物理与游戏玩法”单元。第 50 课,共 71 课。
抖动是一小段随机偏移:在十分之几秒内,相机每帧都会停在静止位置附近的一个随机点,然后回到原位。协程很适合,因为它会跨多帧运行,并自行结束。当巨石落地时,这个相机就会抖动(另一个脚本会调用 BoulderLanded();文件以 using System.Collections; 开头,以使用 IEnumerator):
public float strength = 0.2f;
public float duration = 0.4f;
Vector3 rest;
void Start()
{
rest = transform.localPosition;
}
public void BoulderLanded()
{
StartCoroutine(Shake());
}
IEnumerator Shake()
{
float elapsed = 0f;
while (elapsed < duration)
{
transform.localPosition = rest + Random.insideUnitSphere * strength;
elapsed += Time.deltaTime;
yield return null;
}
transform.localPosition = rest;
}Random.insideUnitSphere * strength 会在任意方向上产生一个长度不超过 strength 的随机偏移,而 yield return null 会在下一帧选取新的偏移。每次循环都加上 Time.deltaTime,就能累计实际经过的秒数,因此无论帧率如何,抖动都会持续 duration。最后一行会让相机回到原位;没有这一行,相机就会停留在最后一次偏移的位置。
每一帧中,Unity 会先运行每个 Update(),然后运行等待 yield return null 的协程,最后运行每个 LateUpdate()。因此,在 LateUpdate() 中设置位置的跟随相机会覆盖抖动造成的任何变化。如果相机是一个负责跟随的空对象的子对象,那么抖动 localPosition 就能避免这个问题:父对象移动,而相机则围绕它下方的位置抖动。
挑战
中等按下 Space 时,让下面的摄像机抖动。
- 添加字段
Vector3 shake;,并在LateUpdate()中设置transform.position = player.position + offset + shake;。 - 在
Shake()中,当elapsed < duration时:shake = Random.insideUnitSphere * strength;,将Time.deltaTime加到elapsed上,然后执行yield return null;。 - 循环结束后,设置
shake = Vector3.zero;。
按下“开始”,运行并按下 Space:视角会在跟随时抖动。然后点击“检查”。
亲手试试
using System.Collections;
using UnityEngine;
public class ShakeFollow : MonoBehaviour
{
public Transform player;
public Vector3 offset = new Vector3(0, 4, -8);
public float strength = 0.3f;
public float duration = 0.4f;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(Shake());
}
}
void LateUpdate()
{
transform.position = player.position + offset;
}
IEnumerator Shake()
{
// 让摄像机以跟随位置为基准抖动 duration 秒,最大偏移量为 strength。
yield return null;
}
}
物理与游戏玩法中的所有课
自己练习: Unity 在线编辑器