Cinemachineに独自の動きを追加させたいけど、何か良い方法はないの~?
CinemachineのExtensionを使えば良いわ。
Cinemachineはスクリプト無しでも様々なカメラワークが作れるのが特徴ですが、独自のスクリプトで機能拡張することで、更に凝ったカメラワークを作成する事も可能です。
これはExtension(拡張機能)としてコンポーネントを自作することで実現できます。
参考:Extension | Cinemachine | 2.6.0
コンポーネントを自作する方法はシンプルで、CinemachineExtensionクラスを継承した独自クラスを定義してスクリプトとしてUnityプロジェクト内に配置するだけです。
これで、次のようにCinemachine側に独自のExtensionが適用できるようになります。
本記事では、このようなExtensionを独自実装してCinemachineを拡張する方法について解説していきます。
この作品はユニティちゃんライセンス条項の元に提供されています
- Unity2021.1.14f1
- Cinemachine2.7.4
目次 非表示
前提条件
予めシーン上にCinemachineVirtualCameraが配置されているものとします。
このバーチャルカメラに対して独自のExtensionを適用していきます。
Cinemachineの設定が分からない方は、以下記事をご覧ください。
Extensionの仕組み
Cinemachineでは、カメラワーク処理の合間に独自処理を追加できる仕組みを備えています。これはExtension(拡張機能)という形で提供され、CinemachineExtensionクラスの派生クラスを実装することで独自の拡張を追加できます。
参考:Extension | Cinemachine | 2.6.0
ExtensionはCinemachine側でいくつか用意されており、これらをExtensionとして使う事もできます。バーチャルカメラコンポーネントのExtension > Add Extensionから該当のExtensionを追加します。
例えば、CinemachineCameraOffsetを使用すると、Cinemachineのカメラワーク処理によって計算された位置を補正できるようになります。
独自のExtensionを実装する
ここからは、Extensionをスクリプトで実装する手順を解説していきます。
Extensionクラスの作成
CinemachineExtensionクラスの派生クラスをスクリプトとして作成します。
Extensionの最小スクリプトは次のようになります。
引数stageの内容をコンソールログに出力するだけのサンプルです。
上記スクリプトをTestCinemachineExtension.csというファイル名でUnityプロジェクトに保存すると、CinemachineのバーチャルカメラにExtensionとして追加できるようになります。
上記を選択すると、コンポーネントとしてExtensionが追加されます。
この状態でゲームを実行すると、以下のような内容がコンソールログに出力されます。
Extensionの実行タイミング
上記コードのPostPipelineStageCallback()メソッドは、バーチャルカメラ側から呼び出されます。
Cinemachineでは、カメラワーク処理をBody(移動)、Aim(回転)、Noise(振動)の順に処理するパイプラインで管理しています。PostPipelineStageCallback()コールバックは、このパイプライン処理の合間に実行されます。
実行されるタイミングは、1フレームあたりのカメラワーク処理の中で次の4か所となります。
- カメラの移動後(Body処理後)
- カメラの回転後(Aim処理後)
- カメラの振動後(Noise処理後)
- カメラワークのパイプライン処理が完了した後
どのタイミングの呼び出しかは、PostPipelineStageCallback()メソッドの第2引数stageの値からチェックできます。特定のタイミングだけで処理したい場合、stageの値によって条件分岐させるコードで実現できます。
PostPipelineStageCallbackの引数
CinemachineExtension.PostPipelineStageCallback()コールバックは次の形式で定義されています。
第1引数vcamには、対象のバーチャルカメラが指定されます。
第2引数stageには、実行タイミングが指定されます。
第3引数stateには、カメラ状態の構造体データが参照渡しされます。Extensionで計算した結果は、このstateの中身を編集する形で格納します。
第4引数deltaTimeには、現在のデルタタイムが指定されます。
参考:Class CinemachineExtension| Package Manager UI website
Extensionによるカメラワークの実装例
Extensionを使ったCinemachineの拡張例として、マウスホイールのスクロールでズームイン/ズームアウトする機能を追加する例を紹介します。
サンプルスクリプト
このスクリプトをMouseWheelZoom.csとしてUnityプロジェクトに保存すると、バーチャルカメラのExtensionからMouseWheelZoomが選択できるようになります。
実行結果
マウスホイールをスクロールさせると、カメラがズームイン/ズームアウトするようになりました。
サンプルスクリプトの説明
サンプルスクリプトでどのような処理を行っているかについても軽く触れておきます。
タイミングの判定
次の処理で、Aim直後だけExtensionのカメラワーク処理を実行するようにしています。
マウスホイールによる画角の調整
バーチャルカメラの画角は、state.Lens.FieldOfViewフィールドに格納されています。
state.Lensは構造体なので、一時的に変数に格納してから値を書き換えるようにしています。
stateの内部状態は、Cinemachineのカメラワーク処理が実行されるたびに元に戻ります。前回書き換えた値が引き継がれないことに注意です。
そのため、コールバックが呼び出されるたびにFieldOfViewの内容を書き換えています。
マウスホイールのスクロール判定
マウスホイール操作の状態取得は、PostPipelineStageCallbackではなくUpdateイベントで行うようにします。
これは、PostPipelineStageCallbackの呼び出しはFixedUpdateイベントで行われる可能性があり、マウスホイールの操作量を正しく取得できなくなる可能性があるためです。
さいごに
本記事では、Cinemachineをスクリプトで拡張する方法について解説しました。
Extensionは、Cinemachineに独自のカメラワークを追加していける便利な機能です。Cinemachineの既存のカメラワークだけではどうしても物足りない場合に検討すると良いでしょう。