(2024/03/10 追記)
cinemachine3でAPIが若干変わるらしく、このコードが使えなくなるのかなと書きかえに来ましたが、「using Cinemachine;」を「using Unity.Cinemachine;」に書きかえたら普通に動きました。
(追記終了)
Unity1週間ゲームジャムで横方向だけ追跡するカメラをCinemachineで実装しようとしたら、良く分からなくて調べたのでここにまとめます。
※詳しいコードの内容の説明はしません
目的
動画のように、追跡対象がY軸(画面上下)方向に移動してもカメラがついていかないようにします。
環境
Unity 2021.1.20f1
Cinemachine 2.7.8
実装
手順
①下記の軸を一定の座標で固定するCinemachineExtensionを継承したスクリプトを作成(今回はY軸を固定)
②CinemachineVirtualCameraのExtensionsから①で作成したスクリプトを追加
Y軸固定のみの簡単なコード
using UnityEngine; using Cinemachine; [ExecuteInEditMode] [SaveDuringPlay] [AddComponentMenu("")] // Hide in menu public class LockCameraY : CinemachineExtension { [Tooltip("カメラのY座標を固定する値")] public float m_YPosition = 10; protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { if (stage == CinemachineCore.Stage.Body) { var pos = state.RawPosition; pos.y = m_YPosition; state.RawPosition = pos; } } }
汎用化版
スクリプト一本で全ての軸を制御可能にするために慣れないエディタ拡張を書いて汎用化させました。
インスペクタ上から固定したい軸のトグルにチェックを入れると、特定の座標で固定することができます。
using UnityEngine; using Cinemachine; #if UNITY_EDITOR using UnityEditor; #endif [ExecuteInEditMode] [SaveDuringPlay] [AddComponentMenu("")] // Hide in menu public class LockAxisCamera : CinemachineExtension { public bool x_islocked,y_islocked,z_islocked; public Vector3 lockPosition; protected override void PostPipelineStageCallback( CinemachineVirtualCameraBase vcam, CinemachineCore.Stage stage, ref CameraState state, float deltaTime) { if (stage == CinemachineCore.Stage.Body) { var newPos = state.RawPosition; if (x_islocked) newPos.x = lockPosition.x; if (y_islocked) newPos.y = lockPosition.y; if (z_islocked) newPos.z = lockPosition.z; state.RawPosition = newPos; } } } #if UNITY_EDITOR [CustomEditor(typeof(LockAxisCamera))] public class LockAxisCameraEditor : Editor { public override void OnInspectorGUI() { var lockAxisCamera = target as LockAxisCamera; using (new EditorGUILayout.HorizontalScope()) { EditorGUIUtility.labelWidth = 10; EditorGUILayout.LabelField("固定する軸"); lockAxisCamera.x_islocked = EditorGUILayout.Toggle("X", lockAxisCamera.x_islocked); lockAxisCamera.y_islocked = EditorGUILayout.Toggle("Y", lockAxisCamera.y_islocked); lockAxisCamera.z_islocked = EditorGUILayout.Toggle("Z", lockAxisCamera.z_islocked); } EditorGUILayout.LabelField("固定する座標"); using (new EditorGUILayout.HorizontalScope()) { EditorGUIUtility.labelWidth = 10; lockAxisCamera.lockPosition.x = EditorGUILayout.FloatField("X", lockAxisCamera.lockPosition.x); lockAxisCamera.lockPosition.y = EditorGUILayout.FloatField("Y", lockAxisCamera.lockPosition.y); lockAxisCamera.lockPosition.z = EditorGUILayout.FloatField("Z", lockAxisCamera.lockPosition.z); } } } #endif
おわりに
スクリプトを書かなくてもCinemachineの機能だけで完結できれば便利だったのですが、調べた限りでは出てきませんでした。
特定の軸を固定するのってあまり需要ないんでしょうかね?