【Unity】Cinemachineでカメラの追従対象を切り替える

こじゃら
こじゃら

Cinemachineでキャラを追いかけるカメラワークを作っているんだけど、別のキャラに切り替える方法が分からなくて困ってるの~

このは
このは

スクリプトから設定することになるけど簡単だわ。
次のような方法で実現可能よ。

カメラの追従対象を切り替える方法
  • バーチャルカメラの追従対象を直接変更する
  • 複数のバーチャルカメラのうち使用するものを選択する

Cinemachineではバーチャルカメラ1カメラの実体ではないが、実質的にカメラのようにふるまうオブジェクト。という仮想的なカメラを複数持たせられる仕組みを採用しています。これにより、複数のカメラワークの切り替えが容易に実現できます。

また、バーチャルカメラの追従対象はスクリプトから読み書きできるようになっています。

この仕組みによって、次のように動的に追従対象を切り替えることができます。

本記事では、Cinemachineを使ってカメラの追従対象を切り替える方法について解説していきます。

動作環境
  • Unity2020.3.4f1
  • Cinemachine2.6.4

この作品はユニティちゃんライセンス条項の元に提供されています

前提条件

次のように、シーン内に複数のUnityちゃんがいる場面を想定します。

初期状態では、一番左のUnityちゃんをカメラが追従させることにします。
Cinemachineのセットアップや追従のさせ方が分からない方は、以下記事もあわせてご覧ください。

方法1 : バーチャルカメラの追従対象を直接書き換える

1つのバーチャルカメラを使いまわして追従対象だけをスクリプトから変更する方法です。

メリット・デメリットは次の通りです。

  • メリット
    • バーチャルカメラを1個用意するだけで良い
  • デメリット
    • カメラを瞬時にしか切り替えられない(切替アニメーションできない)

追従対象のパラメータ

バーチャルカメラはCinemachineVirtualCameraクラスのコンポーネントとしてスクリプトからアクセスできます。
スクリプトから書き換えるパラメータは次の2つです。

  • Follow
    • バーチャルカメラが追従する対象となるオブジェクト(Transform型)
    • Followプロパティとしてアクセス可
  • Look At
    • バーチャルカメラが照準を合わせる対象となるオブジェクト(Transform型)
    • LookAtプロパティとしてアクセス可

追従対象の切り替え処理

追従対象の切り替えは、CinemachineVirtualCameraクラスのFollowおよびLookAtプロパティを書き換えれば良いです。

次のようなコードになります。

CinemachineVirtualCamera virtualCamera;

// 中略

virtualCamera.Follow = follow; // 追従対象
virtualCamera.LookAt = lookAt; // 照準合わせ対象

カメラ切り替えのサンプル

画面をクリックするとカメラを切り替えるスクリプトの例です。

CameraTargetSelector.cs

using System;
using UnityEngine;
using Cinemachine;

/// <summary>
/// 追従対象を切り替えるサンプル
/// </summary>
public class CameraTargetSelector : MonoBehaviour
{
    // 追従対象情報
    [Serializable]
    private struct TargetInfo
    {
        // 追従対象
        public Transform follow;
        // 照準を合わせる対象
        public Transform lookAt;
    }

    // バーチャルカメラ
    [SerializeField] private CinemachineVirtualCamera _virtualCamera;

    // 追従対象リスト
    [SerializeField] private TargetInfo[] _targetList;

    // 選択中のターゲットのインデックス
    private int _currentTarget = 0;

    // フレーム更新
    private void Update()
    {
        // 追従対象情報が設定されていなければ、何もしない
        if (_targetList == null || _targetList.Length <= 0)
            return;

        // マウスクリックされたら
        if (Input.GetMouseButtonDown(0))
        {
            // 追従対象を順番に切り替え
            if (++_currentTarget >= _targetList.Length)
                _currentTarget = 0;

            // 追従対象を更新
            var info = _targetList[_currentTarget];
            _virtualCamera.Follow = info.follow;
            _virtualCamera.LookAt = info.lookAt;
        }
    }
}

これを適当なゲームオブジェクトにアタッチし、Virtual CameraとTarget Listをインスペクタから設定します。

実行結果

成功すると、次のようにカメラが切り替わります。

分かりやすくするために、CinemachineのAimのDampingはあえて0にしています。
カメラの向きが一瞬で切り替わっているのが分かります。

方法2 : 複数のバーチャルカメラを切り替える

対象物ごとに追従するバーチャルカメラを用意し、バーチャルカメラをCinemachine Brain2Cinemachineの大元となるコンポーネントで、バーチャルカメラの切り替えなどを管理します。から切り替える方法です。
こちらの方がよりCinemachineらしい使い方かもしれません。

メリット・デメリットは次の通りです。

  • メリット
    • カメラ切り替えの動きを細かく制御できる
  • デメリット
    • バーチャルカメラを追従対象の個数分用意する必要がある

バーチャルカメラの切り替え方法

各々のバーチャルカメラには優先度(Priority)が付けられています。
Cinemachine Brainからは、最も優先度が高いバーチャルカメラが選択されます。

スクリプト側からは、この優先度を書き換えることでバーチャルカメラの切り替えができます。

CinemachineVirtualCamera vCam1, vCam2;

// 中略

vCam1.Priority = 10; // こちらは選択されない
vCam2.Priority = 11; // 優先度が高いので、こちらが選択される

バーチャルカメラを切り替える際は、Cinemachine Brainに設定されているカメラブレンド情報3Blend Update Method、Default Blend、Custom Blendsプロパティ等に基づいてアニメーションしながら切り替わります。4即座に切り替えることも可能です。その場合、Default Blendの時間を0にすれば良いです。

カメラ切り替えのサンプル

方法1と同様に、画面をクリックするとカメラを切り替えるスクリプトです。

VirtualCameraSelector.cs

using UnityEngine;
using Cinemachine;

/// <summary>
/// バーチャルカメラを切り替えるサンプル
/// </summary>
public class VirtualCameraSelector : MonoBehaviour
{
    // バーチャルカメラ一覧
    [SerializeField] private CinemachineVirtualCamera[] _virtualCameraList;

    // 非選択時のバーチャルカメラの優先度
    [SerializeField] private int _unselectedPriority = 0;

    // 選択時のバーチャルカメラの優先度
    [SerializeField] private int _selectedPriority = 10;

    // 選択中のバーチャルカメラのインデックス
    private int _currentCamera = 0;

    // バーチャルカメラの優先度初期化
    private void Awake()
    {
        // バーチャルカメラが設定されていなければ、何もしない
        if (_virtualCameraList == null || _virtualCameraList.Length <= 0)
            return;

        // バーチャルカメラの優先度を初期化
        for (var i = 0; i < _virtualCameraList.Length; ++i)
        {
            _virtualCameraList[i].Priority =
                (i == _currentCamera ? _selectedPriority : _unselectedPriority);
        }
    }

    // フレーム更新
    private void Update()
    {
        // バーチャルカメラが設定されていなければ、何もしない
        if (_virtualCameraList == null || _virtualCameraList.Length <= 0)
            return;

        // マウスクリックされたら
        if (Input.GetMouseButtonDown(0))
        {
            // 以前のバーチャルカメラを非選択
            var vCamPrev = _virtualCameraList[_currentCamera];
            vCamPrev.Priority = _unselectedPriority;

            // 追従対象を順番に切り替え
            if (++_currentCamera >= _virtualCameraList.Length)
                _currentCamera = 0;

            // 次のバーチャルカメラを選択
            var vCamCurrent = _virtualCameraList[_currentCamera];
            vCamCurrent.Priority = _selectedPriority;
        }
    }
}

これを適当なゲームオブジェクトにアタッチし、インスペクタの項目を設定します。

実行結果

アニメーションしながら緩やかに切り替わるようになりました。

動画の例では、0.5秒かけてカメラを切り替えるようにCinemachine Brainのブレンドを設定しています。

さいごに

Cinemachineを使ってカメラの追従対象をスクリプトから切り替える方法について解説しました。
複雑なスクリプトを書くことなくカメラワークの切り替えができます。

Cinemachineはノーコーディングで優れたカメラワークを実装できるのが特徴ですが、スクリプトとの連携や拡張性にも優れているのも特徴です。

参考サイト