i-school - 3Dトップビューアクション 手順7
 この手順では、プレイヤーの移動制御を修正し、カメラの正面方向を基準とした移動方法を新たに実装します。
また、それと合わせて、マウスによるカメラの上下左右回転の機能も追加し、カメラと移動とを連動させていきます。

 これにより、カメラを左右方向に回転させた場合でも、常にカメラの正面に向かって移動する機能が実装出来ます。

<実装動画>
動画ファイルへのリンク

手順7 ーカメラの正面方向を基準とした、プレイヤーの移動機能の実装ー



 ・Camera.main 変数
 ・Transform.forward 変数/ Transform.right 変数
 ・Vector3.Scale メソッド

 ・Transform.RotateAround メソッド
 ・Transform.localEulerAngles 変数



1.カメラの正面方向を基準としたプレイヤーの移動機能を実装する

1.設計


 現在のプレイヤーの移動方法の場合、カメラの左右回転がないため、プレイヤーの移動先が変わってもカメラは回転しません。
そのため、固定化されているカメラの元でプレイヤーが前後左右に移動している形式になっています。

 白猫プロジェクトなど多くのゲームの場合、カメラの向きを左右回転させる機能があり、
その回転先に対して前進するような仕組みでプレイヤーの移動ができるようになっています。
これは、プレイヤーの情報を主体とした移動ではなくて、カメラの正面方向の情報を主体とした移動に切り替えることで実装出来ます。

 この手順は、新しいスクリプトを作成して、プレイヤーの移動方法を変更していきます。

 こちらのサイト内のスクリプトは、下記の記事を参考にさせていただいております。
ありがとうございます。
TechProjin 様
Unityでカメラの向きを基準に移動する方法と、追従して回転できるカメラの実装
https://tech.pjin.jp/blog/2016/11/04/unity_skill_5...


2.PlayerController クラスを作成する


 プレイヤーの情報を管理するためのスクリプトとして PlayerController クラスを作成します。
このスクリプト内にカメラの情報を元にした移動の処理を記述し、プレイヤーを制御します。

 手順5で作成した PlayerMove スクリプトとの違いは、移動時の制御部分(Move メソッドの内容)のみです。
そのため、宣言する変数、定義するメソッドなどは同じです。
利用している処理の復習にもなりますので、完成してから見比べてみるとよい学習になります。



PlayerController.cs

<= クリックすると開きます。



3.<Camera.main 変数>


 スクリプト内で Camera コンポーネントの情報を扱うために用意されている変数です。
この値には、Unity によって自動的に取得された情報が代入されており、具体的には、
ヒエラルキーにあるゲームオブジェクトのうち、"MainCamera" のタグ付けが行われている
最初の有効な Camera コンポーネントの情報が代入されています。
この値は読み取り専用の変数ですので、参照は可能ですが、代入したりすることは出来ません。

 初期設定として、ヒエラルキーに Camera コンポーネントがアタッチされているのは MainCamera ゲームオブジェクトのみであり、
また、この MainCamera ゲームオブジェクトには MainCamera のタグが設定されていますので、複数のカメラを追加したり、タグを変更していない限りは
MainCamera ゲームオブジェクトの Camera コンポーネントの情報が Camera.main 変数の値となります。

 この変数により、スクリプト内で Camera コンポーネントの情報を利用したい場合には、
事前に GameObject.Find メソッドでカメラのゲームオブジェクトを見つけてきたり、
そのゲームオブジェクトに対して GetComponent メソッドを利用して Camera コンポーネントの情報を準備する必要がありません。

 Camera コンポーネントは利用する機会が多いので、すぐに利用できる(取得を省略できる)ために、Camera.main 変数が用意されています。


参考サイト
Unity公式スクリプトリファレンス
Camera.main
TechProjin 様
【Unity】スクリプトからMain Cameraを取得するのは簡単だよ


4.<Transform.forward 変数/ Transform.right 変数>


 ゲームオブジェクトの向きを取得することができる変数です。
transform 変数に代入されているゲームオブジェクトの向きの情報が取得出来ます。

 ゲームオブジェクトの正面の向きは、Transform.forward 変数で取得出来ます。
Scene ビューにあるゲームオブジェクトを選択したときに表示される、Z 軸向き(青色)の矢印(ベクトル)に相当する情報です。

 この値はワールド座標系で正規化(長さが 1 の単位ベクトル)されたベクトルであり、それぞれ、(0, 0, 1) の値となります。

 公式スクリプトリファレンスには、Vector3.forward 変数との違いについても記載されています。


<公式スクリプトリファレンスと翻訳>
Returns a normalized vector representing the blue axis of the transform in world space.
  ワールド空間でのトランスフォームの青軸を表す正規化されたベクトルを返します。

The example below shows how to manipulate a GameObject’s position on the Z axis (blue axis) of the transform in world space.
  以下の例は、ワールド空間でのトランスフォームの Z 軸 (青い軸) 上のゲームオブジェクトの位置を操作する方法を示しています。

Unlike Vector3.forward, Transform.forward moves the GameObject while also considering its rotation.
  Vector3.forward とは異なり、Transform.forward は回転も考慮しながら GameObject を移動します。

When a GameObject is rotated, the blue arrow representing the Z axis of the GameObject also changes direction.
  ゲームオブジェクトが回転すると、ゲームオブジェクトの Z 軸を表す青い矢印も方向が変わります。

Transform.forward moves the GameObject in the blue arrow’s axis (Z).
  Transform.forward は、GameObject を青い矢印の軸 (Z) に沿って移動します。

For moving the GameObject on the Z axis while ignoring rotation, see Vector3.forward.
  回転を無視して Z 軸上でゲームオブジェクトを移動するには、Vector3.forward を参照してください。


参考サイト
Unity公式スクリプトリファレンス
Transform-forward



 ゲームオブジェクトの右の向きは Transform.right 変数から取得することができます。
Scene ビューにあるゲームオブジェクトを選択したときに表示される、X 軸向き(赤色)の矢印(ベクトル)に相当する情報です。

 この値はワールド座標系で正規化された(長さが 1 の単位ベクトル)されたベクトルであり、それぞれ、(1, 0, 0) の値となります。
Vector3.up との違いも、Transform.forward 変数と同じで回転情報を参照するか、しないかにあります。


参考サイト
Unity公式スクリプトリファレンス
Transform-right



 ここでは取り上げませんが、上方向の情報を取得できる Transform.up 変数も用意されています。
覚えておくと便利な変数群です。


参考サイト
ねこじゃらシティ 様
【Unity】オブジェクトの向きを取得する


5.<Vector3.Scale メソッド>


 Unity の Vector3 の扱える情報の1つです。

 第1引数の各成分と、第2引数の同じ成分を乗算した結果を、戻り値として Vector3 型で取得します。
そのため、計算結果を代入する Vector3 型の変数を用意しておく必要があります。

  // カメラの方向から、X-Z平面の単位ベクトルを取得
  Vector3 cameraForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;

 Camera.main.transform.forward には、(0, 0, 1) の値が代入されています。それに対して、new Vector3(1, 0, 1)を乗算します。
上記の場合、(0 * 1, 0 * 1, 1 * 1) という計算が行われることになります。

 X 軸と Y 軸には常に 0 の値が乗算されるため、処理の結果として、Z の情報はそのまま、X と Y は 0 という結果が戻り値として得られて、
その値が cameraForward の値に代入されます。そのため、Camera.main.transform.forward の値から X 成分と Y 成分を除去し、0 にすることが出来ています。

 その後、各成分の計算結果に対して、normalized 変数が適用され、単位ベクトルの値に変換されています。


参考サイト
Unity 公式スクリプトリファレンス
Vector3.Scale
ねこじゃらシティ 様
【Unity】ベクトルAPIの内部計算式まとめ


6.プレイヤー用のゲームオブジェクトに PlayerController スクリプトをアタッチする


 ヒエラルキーにあるプレイヤー用のゲームオブジェクトから、PlayerMove スクリプトを Remove(削除)します
その後、先ほど作成した PlayerController スクリプトをドラッグアンドドロップしてアタッチします。

 ヒエラルキーのプレイヤー用のゲームオブジェクトを選択し、インスペクターを表示して、PlayerController スクリプトがアタッチされていることを確認します。

 MoveSpeed 変数の値はインスペクターより調整できます。この値がプレイヤー用のゲームオブジェクトの移動速度の値になりますので、適宜調整をお願いします。


<インスペクター画像>



 以上で設定は完了です。


7.ゲームを実行して動作を確認する


 キー入力を行った際に、プレイヤーが実際に移動するか、動作確認(デバッグ)を行います。
この時点で、いままでと同じように移動処理が出来ていれば問題ありません。


<実装動画>
動画ファイルへのリンク


 正常に動作した場合、それで終わり、ではなくて、プログラムを読み直し、
どのような処理によって、今回の移動の制御が行われているかを、しっかりと読み解けるようにしてください。


2.スクリプトによるカメラ(Cinemachine)の制御機能を実装する

1.設計


 カメラの正面の方向に対して移動する機能が実装できましたので、この手順ではカメラの回転機能を作成します。

 マウスの右クリックをしている間だけ、カメラが上下左右に回転するような設計にします。
カメラを回転させるためには、回転の主軸を考える必要があります。今回は、プレイヤーを主軸にします。
そして、そのプレイヤーを軸として、カメラの位置を上下左右に回転させます。このカメラの回転は公転回転となります。


2.CameraControllerFromCinemachine スクリプトを作成する(Cinemachine によるカメラの場合)


 Cinemachine を利用する場合のスクリプトです。

 追従の処理については Cinemachine の Follow に追従対象を設定している想定です。
また、X 軸の可動域についても処理が異なります。これらの値については、実行しながら調整してください。

 マウスの右ボタンを押し続ける(ドラッグしている)間、カメラの上下左右の公転回転が可能になります。
また、記事の内容に加えて、カメラの上下の可動域(X 軸に制限)を設けています。左右は 360 度回転可能です。


CameraControllerFromCinemachine.cs

<= クリックすると開きます


 スクリプトを作成したらセーブします。
Virtual Studio ではショートカット機能があり、Ctrl + Shift + S キーの同時押しで開いているすべてのスクリプトをまとめてセーブができます。

 この CameraControllerFromCinemachine スクリプトは MainCamera ゲームオブジェクトではなく、
CinemachineVirtualCamera コンポーネントがアタッチされているゲームオブジェクトにアタッチしてください。


3.<Transform.RotateAround メソッド>


 ゲームオブジェクトを、指定したゲームオブジェクトを中心軸として回転させます。
例えると、地球に対しての月の公転回転のような回転を行う機能を持つメソッドです。

<公式スクリプトリファレンスより>
 ワールド座標の point を中心とした軸( axis )で angle 度回転させます。
これは Transform の位置と回転が同時に変更されます。



 今回はこちらの公転回転の機能を活用し、プレイヤーを地球として考えたとき、カメラを月のように公転回転させています。

 // カメラを追従対象の周囲を公転回転させる
  transform.RotateAround(targetObj.transform.position, Vector3.up, x * Time.deltaTime * cameraRotateSpeed);


<参考サイト>
Unity公式スクリプトリファレンス
Transform.RotateAround
MRが楽しい 様
指定のトランスフォームを中心にオブジェクトを回転させる
フタバゼミ 様
ターゲットの周囲を円形に移動する


4.<Transform.localEulerAngles 変数>


 Transform コンポーネントは回転情報を Rotation 変数として管理しています。
インスペクター上は Vector3 型の (x, y, z) で表示されていますが、この値は内部的には Quaternion 型であるため、
回転情報を更新(代入)するためには、Quaternion 型の値を指定する必要があります。

 その方法とは別に、スクリプトでは、Vector3 型の値をそのまま代入して、Rotation の値を更新する方法があります。
そのために用意されているのが Transform.localEulerAngles 変数です。

 この Transform.localEulerAngles 変数は、親の Transform オブジェクトから見た、相対的なオイラー角としての回転値です。

 この変数を利用すると、Vector3 型の情報をオイラー角として利用して、回転情報の更新が行えます。
オイラー角によって Vector3 型の回転情報を表現すると 0 度〜 360 度になりますので、直感的にわかりやすい形での代入処理を記述することが出来ます。

 // カメラの回転
  transform.localEulerAngles = localAngle;

 ここでは触れませんが、Transform.eulerAngles 変数もあります。


<参考サイト>
Unity公式スクリプトリファレンス
Transform.localEulerAngles


5.ゲームを実行して動作を確認する


 処理の内容を見直したうえで、ゲームを実行して動作を確認します。

 カメラの上下左右の回転を確認しつつ、プレイヤーを移動させてみてください。
カメラの向いている方向にプレイヤーが前進していけば制御成功です。


<実装動画>
動画ファイルへのリンク



 以上でこの手順は終了です。

 次は 手順8 ージャンプの実装− です。