バーチャル3Dクリエイター神部まゆみです(*^-^*)
この記事はunity Chinemachine Virtual Cameraをoffsetで移動させるスクリプトを書いたのでそのメモです。
書いたというかChatGPT氏に書かせたというほうが正しいか(笑)。
前回の記事はこちら。
使用したバージョンはunity2020.3.40です。




エイム時にカメラをズームさせるようにしたかった
↓前回の記事までだとこんな感じだけど、


↓今回の記事のスクリプトを付けたらこんな感じでズームするようにした。
コード CameraZoom.cs
スクリプトはこんな感じ。
using UnityEngine; using Cinemachine; public class CameraZoom : MonoBehaviour { public Animator aimAnimator; // Aim変数を持ったモデルのアニメーターをInspectorで指定 public float aimZoomZ = -1f; // エイム中のカメラのZ軸位置 public float normalZoomZ = -3f; // 通常時のカメラのZ軸位置 public GameObject inspectObject; // インスペクターオン・オフを切り替えるオブジェクト private void Update() { // エイム中はカメラをズームして、エイム解除時は通常のズームに戻す if (aimAnimator.GetBool("Aim")) { SetCameraZoom(aimZoomZ); SetInspectObjectActive(true); } else { SetCameraZoom(normalZoomZ); SetInspectObjectActive(false); } } private void SetCameraZoom(float zoomZ) { // CinemachineBrainを取得 CinemachineBrain cinemachineBrain = Camera.main.GetComponent<CinemachineBrain>(); if (cinemachineBrain != null) { // Cinemachine Camera OffsetのZ軸位置を変更 CinemachineVirtualCameraBase virtualCamera = cinemachineBrain.ActiveVirtualCamera.VirtualCameraGameObject.GetComponent<CinemachineVirtualCameraBase>(); if (virtualCamera != null) { CinemachineCameraOffset cameraOffset = virtualCamera.GetComponent<CinemachineCameraOffset>(); if (cameraOffset != null) { Vector3 offset = cameraOffset.m_Offset; offset.z = zoomZ; cameraOffset.m_Offset = offset; } } } } private void SetInspectObjectActive(bool active) { // 指定したオブジェクトのSetActiveを切り替える if (inspectObject != null) { inspectObject.SetActive(active); } } }
Cinemachine Offsetのあるオブジェクトにアタッチして、プレイヤーのアニメーターやズーム距離、エイムターゲットを指定する。


↑の画像だと、奥行のZ軸を-3から-1に切り替えてズームする感じです。
Cinemachine Camera Offsetがなければ追加して位置調整しておく必要があります。


Offsetの座標と、Camera Zoomで指定するZ軸の値の組み合わせで見え方が変わるので、ゲーム画面を見ながら調整してください。


Inspect ObjectのAimTargetはエイムの中心にオブジェクトを表示しているので、非エイム時はインスペクターオフにして見えないようにするために指定している。
そのあたりについては前回の記事を参照。
せっかくなので特定の条件でCinemachineを移動や切り替えさせるコードを書いてみる
書いてみるって言うかChatGPT氏に書かせただけだけど(;^_^A
例1:スペースキーを押したらカメラを切り替え、もう一度押したら戻る
Cinemachine一つで動かしてもいいみたいだけど、Cinemachineは複数作ってスムーズに切り替えられるっぽいのでカメラを切り替えるようにします。
↓空のオブジェクトを追加して、Cinemachine Virtual CameraコンポーネントとCinemachine Camera Offsetを追加しました。


これでCinemachine Brainが一つ、Cinemachine Virtual Cameraが二つある状態。
Cinemachine Brainは一つあればいいっぽい。
これをとりあえずプレイヤーから離れた位置に持って行っておく。
↓は以前アセットストアで買ったグールのモデルを映してます。


とりあえずCinemachine Virtual Cameraの設定ではこのグールだけFollowするようにしてあります。
LookAtとか他のところはいじってません。


カメラを切り替えるスクリプト CameraController.cs
これを適当なオブジェクトにアタッチする。
using UnityEngine;
using Cinemachine;
public class CameraController : MonoBehaviour
{
public CinemachineVirtualCamera initialCamera;
public CinemachineVirtualCamera zoomedInCamera;
private CinemachineVirtualCamera activeCamera;
private void Start()
{
// 初期のカメラを有効にする
activeCamera = initialCamera;
activeCamera.gameObject.SetActive(true);
// ズームインのカメラを非アクティブにする
zoomedInCamera.gameObject.SetActive(false);
}
private void Update()
{
// Spaceキーが押されたらカメラの切り替えをトリガーする
if (Input.GetKeyDown(KeyCode.Space))
{
// カメラの切り替えを行う
SwitchCamera();
}
}
private void SwitchCamera()
{
// 現在のカメラを非アクティブにする
activeCamera.gameObject.SetActive(false);
// カメラを切り替える
if (activeCamera == initialCamera)
{
activeCamera = zoomedInCamera;
}
else
{
activeCamera = initialCamera;
}
// 切り替え後のカメラをアクティブにする
activeCamera.gameObject.SetActive(true);
}
}
Initial Cameraにはデフォルトのプレイヤーカメラを、Zoomed In Cameraには遷移先のカメラを設定する。


遷移先のカメラはインスペクターオフにしておき、スペースキーを押したら切り替えるようにしてある。


無事に切り替えられた!
これで遷移できた!
以前普通のカメラを切り替えるスクリプトも書いたけど、Cinemachineはキーフレームの線形補間みたいな感じにノーカットで遷移してくれますね。
例2:プレイヤーがObjectタグが付いたオブジェクトに触れたらOnControllerColliderHitでカメラを切り替える
タグを分けておけば衝突判定に便利っぽいので、適当なオブジェクトを追加して新規にObjectって名前のタグを追加して設定します。




OnControllerColliderHitは、キャラクターコントローラーコンポーネントがついたプレイヤーが接触した時のみ動作する命令です。
CharacterController-OnControllerColliderHit(ControllerColliderHit) – Unity スクリプトリファレンス (unity3d.com)
Starter AssetsのThirdPersonのやつを追加するとデフォルトでついてるはず。
Starter Assetsの設定については以前の記事を参照。
OnControllerColliderHitを使えば、コライダーつけなくてもキャラクターコントローラーあるなら衝突判定ができる。


コード CameraController.cs
これはキャラクターコントローラーがあるオブジェクト、ここではプレイヤーにアタッチします。
Objectタグを設定したオブジェクトに触れると、カメラが切り替わって3秒後に戻る。
衝突がダブらないように、当たったら指定したオブジェクトを一旦消すようにしてある。
using UnityEngine;
using Cinemachine;
public class CameraController : MonoBehaviour
{
public CinemachineVirtualCamera initialCamera;
public CinemachineVirtualCamera zoomedInCamera;
private CinemachineVirtualCamera activeCamera;
private bool isZoomedIn = false;
private bool isSwitching = false; // カメラ切り替え中かどうかのフラグ
public GameObject hide;
private void Start()
{
// 初期のカメラを有効にする
activeCamera = initialCamera;
activeCamera.gameObject.SetActive(true);
// ズームインのカメラを非アクティブにする
zoomedInCamera.gameObject.SetActive(false);
}
// CharacterControllerの衝突検知
private void OnControllerColliderHit(ControllerColliderHit hit)
{
// カメラが切り替え中でない場合にのみ処理を行う
if (!isSwitching)
{
// 衝突したオブジェクトが"Object"タグを持っているかを確認
if (hit.gameObject.CompareTag("Object"))
{
//指定したオブジェクトを消す
hide.SetActive(false);
// カメラの切り替えを行う
SwitchCamera();
// カメラの切り替え完了後、3秒後に元のカメラに戻す
Invoke("SwitchCameraBack", 3f);
}
}
}
private void SwitchCamera()
{
// カメラ切り替え中のフラグを立てる
isSwitching = true;
// 現在のカメラを非アクティブにする
activeCamera.gameObject.SetActive(false);
// カメラを切り替える
if (activeCamera == initialCamera)
{
activeCamera = zoomedInCamera;
}
else
{
activeCamera = initialCamera;
}
// 切り替え後のカメラをアクティブにする
activeCamera.gameObject.SetActive(true);
// ズームイン中かどうかのフラグを更新
isZoomedIn = !isZoomedIn;
// カメラ切り替え中のフラグを解除する
isSwitching = false;
}
private void SwitchCameraBack()
{
// カメラを元に戻す
if (isZoomedIn)
{
SwitchCamera();
//指定したオブジェクトを戻す
hide.SetActive(true);
}
}
}
Initial CameraにデフォルトのCinemachineカメラを、Zoomed In Cameraに遷移先のCinemachineカメラを指定します。
Hideは衝突するオブジェクトを指定して、二重検知しないように遷移中は隠すようにしてあります。


これでいい感じに動いた!
例3:オブジェクトに当たったらFollowターゲットを切り替える
Cinemachine Virtual Cameraを複数作って切り替えるのではなく、Cinemachineカメラ一つでFollowターゲットを切り替えてみます。
これでも注視するターゲットを変えられるけど、カメラの位置調整が必要になりそう。
上でやったオフセットを調整すれば行けると思うけど、今回はとりあえずFollowターゲットの切り替えだけやります。
コード CameraController2.cs
このスクリプトをCharacter Controllerがあるプレイヤーモデルにアタッチします。
using UnityEngine;
using Cinemachine;
public class CameraController2 : MonoBehaviour
{
public CinemachineVirtualCamera initialCamera;
public GameObject followTarget; // インスペクターで指定するフォローターゲットのオブジェクト
private CinemachineVirtualCamera activeCamera;
private Transform defaultFollowTarget; // デフォルトのFollowターゲットを保存する変数
public GameObject hide;
private void Start()
{
activeCamera = initialCamera;
activeCamera.gameObject.SetActive(true);
// 初期のカメラのデフォルトのFollowターゲットを保存
defaultFollowTarget = initialCamera.Follow;
}
// CharacterControllerの衝突検知
private void OnControllerColliderHit(ControllerColliderHit hit)
{
// 衝突したオブジェクトが"Object"タグを持っているかを確認
if (hit.gameObject.CompareTag("Object"))
{
// 指定したオブジェクトを消す
hide.SetActive(false);
// カメラの切り替えを行う
SwitchCamera();
// カメラの切り替え完了後、3秒後に元のカメラに戻す
Invoke("SwitchCameraBack", 3f);
}
}
private void SwitchCamera()
{
// フォローターゲットを切り替える
activeCamera.Follow = followTarget.transform;
// 切り替え後のカメラをアクティブにする
activeCamera.gameObject.SetActive(true);
}
private void SwitchCameraBack()
{
// デフォルトのFollowターゲットに戻す
Debug.Log("Default Follow Target before switch back: " + activeCamera.Follow);
activeCamera.Follow = defaultFollowTarget;
Debug.Log("Default Follow Target after switch back: " + activeCamera.Follow);
// 指定したオブジェクトを戻す
hide.SetActive(true);
}
}
Cinemachineのカメラと切り替え先のターゲット、衝突するオブジェクトを指定する。


位置調整とかは面倒だからやってないけどとりあえず切り替えることはできた。
3秒すると元のターゲットに戻ります。
おわりに
Cinemachineは難しいかと思ったけど、簡単な切り替えならそこまで難しくなさそうで良かった。
まぁChatGPTのお陰だけどね(;^_^A
とりあえず複雑なカメラワークとかは必要ないし最低限使えればいいかな。
まぁもう少しいじってみます(*^-^*)