Menu
CoddyTech

カメラシェイク

CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 50/71。

揺れとは、ランダムな位置ずれが短時間続くことです。ほんの数分の一秒の間、カメラは初期位置の近くにあるランダムな位置にとどまり、フレームごとに新しい位置に移動してから、元に戻ります。コルーチンは複数のフレームにわたって実行され、自然に終了するため、この用途に適しています。ここでは、岩が着地したときにカメラを揺らします(別のスクリプトから BoulderLanded() を呼び出します。このファイルの先頭には IEnumerator を使うための using System.Collections; があります)。

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 を揺らすことでこれを避けられます。親オブジェクトが移動し、カメラはその下の位置を中心に揺れます。

challenge icon

チャレンジ

中級

次のカメラをSpaceキーで揺らしてください。

  1. フィールド Vector3 shake; を追加し、LateUpdate() で transform.position = player.position + offset + shake; を設定します。
  2. Shake() 内で、elapsed < duration の間、shake = Random.insideUnitSphere * strength; とし、elapsed に Time.deltaTime を加算して、yield return null; を実行します。
  3. ループの後、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()
    {
        // カメラを追従位置から最大strengthだけ、duration秒間揺らす。
        yield return null;
    }
}

物理演算とゲームプレイのすべてのレッスン

自分で練習してみよう: Unityプレイグラウンド