Unityに関連する記事です

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

 以下の内容で順番に実装を進めていきます。

手順7 ーキャラクターの経路移動機能ー
10.PlayerNavigationController スクリプトの作成



 <新しく学習する内容>
 ・RequireComponent(typeof(クラス名/コンポーネント名))]属性
 ・SerializeField 属性
 ・TryGetComponent メソッドと out キーワード宣言
 ・Vector3.Distance() メソッド ー2点間の位置情報から距離と方向を算出するー
 ・NavMeshAgent に用意されている変数とメソッド
    ー1.NavMeshAgent.destination 変数(SetDestination メソッド)ー
    ー2.NavMeshAgent.speed 変数ー
    ー3.NavMeshAgent.ResetPath メソッドー




10.PlayerNavigationController スクリプトの作成

1.設計


 アクションゲームではありますが、今回のゲームは、十字キーの操作で任意の移動を行うタイプではなく、
ステージ内をタップすることで、その地点まで自動的に経路を決定して移動するタイプを利用します。

 そのため、前回の手順では AI による経路の計算を行うため、NavMeshAgent の準備を行いました。
今回はそちらの機能を利用してキャラクターを操作するためにスクリプトを作成して、機能を制御します。


2.スクリプト作成の準備


 今後多くのスクリプトを作成していくことになりますので、スクリプトを管理するためのフォルダを作成してから
スクリプトの作成に入りましょう。

 Project フォルダ内の空いている場所で右クリックをするか、Project タブの下にある + ボタンを押してメニューを表示します。
Create → Folder を選択し、名前を Scripts に変更します。


Scripts フォルダ作成



3.スクリプト作成


 続いて、その Scripts フォルダをダブルクリックしてフォルダを開き、その中で再度右クリックをしてメニューを表示し、
Create → C# Script を選択します。新しいスクリプト・ファイルが作成されますので、名前を PlayerNavigationController に変更します。
名前を間違えてしまった場合には、一度削除して、もう一度作成し直してください。

 新しい機能をたくさん利用していますので、このあとに説明を用意しています。
スクリプトの処理を記述後に説明を読んで理解を深めてください。

 なお Ray と Physics.Raycast メソッドの説明については割愛しています。
Unity の教科書にて学習済ですので、そちらで復習をしておいてください。


PlayerNavigationController.cs

 ← クリックすると開きます。


 スクリプトを作成したらセーブを行います。Ctrl + Shift + S キーでセーブできます。
自動的に Unity との同期が行われて、エラーがある場合には表示されるようになっています。


4.<RequireComponent(typeof(クラス名/コンポーネント名))]属性>

  
 [] で書かれた情報は属性(Attribute)と呼ばれるものです。
属性を付与する事で他の変数と区別したり、特別な挙動を設定することが出来ます。

[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour {

 このRequireComponent(リクワイア・コンポーネント)属性は、クラス名の1行上に記述する属性です。

 この属性の(引数)で指定したクラスやコンポーネントが、このスクリプトがアタッチされているゲームオブジェクトにアタッチされていないと、Console ビューにエラーが出るようになります。 

 またこの属性が定義されているスクリプトをゲームオブジェクトにアタッチすると、引数で指定しているコンポーネントが自動的にアタッチされます。(今回は Rigidbody コンポーネント)
つまりこの機能は、スクリプトを正常に動作させるために必要なコンポーネントを強制的に用意してくれる内容になっています。
 
 今回この PlayerController スクリプトにより Player ゲームオブジェクトを移動させるには Rigidbody コンポーネントが必要になります。
[RequireComponent(typeof(Rigidbody))]属性を追加することによって、自動的にコンポーネントのアタッチを行うとともに、アタッチされていない場合にはエラーが出るようにしています。


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


5.<SerializeField 属性>


 変数の宣言に合わせて宣言できる、属性情報と呼ばれるものの1つです。変数の宣言の前に [ ] 付きで書かれた内容が属性情報となります。

 今回利用している属性は SerializeField という属性情報です。この機能は、インスペクター上に変数を表示させる、というものです。

 主に private 修飾子とセットで用いられ、アサインをインスペクター上で可能にするものの、変数の参照先が外部のスクリプトにない(publicの必要がない)場合に利用します。

 たとえば ButtonコンポーネントやTextコンポーネントといった、アサインはするものの、その変数の利用先が他のスクリプトにはないようなもの、には利用しやすいです。

 今回はプレイヤーの移動速度を設定するための変数の宣言に属性情報を付与しています。
移動速度の情報をインスペクターに表示させることにより、移動速度の調整にあたり、
スクリプト内でその都度書き直さなくてもよいようにする目的で利用しています。

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


6.<TryGetComponent メソッドと out キーワード宣言>


  if (!TryGetComponent(out agent)) {
      Debug.Log("NavMeshAgent を取得出来ません。");
      return;
  }

 Unity2019.2以降に追加されたメソッドです。処理結果として bool 型で戻り値を返してくれます。
このときの処理結果というのは、指定したコンポーネントの型の取得を行い、それが取得できればtrue、取得できなければfalseが戻ります

 また out キーワードによる宣言があります。
 out キーワード宣言を行うと、out を付けた引数で指定した変数はメソッド内で必ず結果が入ることが保証されるものです。
そのため、処理結果の戻り値が true の場合には必ず、この out の後に宣言した変数内に型が代入されます

 端的にいうならば、GetComponent メソッドの処理に加えて、その処理の成否判定(コンポーネントが取得出来たか、出来なかったか)を同時に行ってくれるメソッドになります。



<実装例 
  private Rigidbody rb;

  TryGetComponent(out rb);

<実装例◆〔瓩蠱佑魍萢僉
if(col.gameObject.TryGetComponent(out Rigidbody rigid)) {

   // 処理を書く
}

 今回は実装例,僚萢として利用しています。スクリプト内に TryGetComponent メソッドを直接記述した場合、GetComponent メソッドと同様に、
このスクリプトがアタッチしているゲームオブジェクトのコンポーネントから指定されている種類のコンポーネントを取得してます。
それを out キーワード後の rb 変数に代入しています。GetComponent メソッドのように<型引数>を指定していないのは、rb 変数によって型を推論することが可能であるためです。

 out キーワード以降にはゲームオブジェクトから取得したい型と変数を宣言します。今回のように事前に変数の宣言をしている場合には、変数のみを用意しておくことが出来ます。

 実装例△両豺腓蓮△發靴發海 TryGetComponent メソッドの処理結果が実行可能ならば、つまり、ゲームオブジェクトに Rigidbody コンポーネントがアタッチされているのであれば、
out として用意した rigid 変数に Rigidbody コンポーネントの情報が代入されます''。また、true の値が、それとは別に処理結果として戻ります。
out に用意した変数が事前に宣言されている変数の場合(例えば rb 変数)には、宣言されていた変数に代入されます。
この辺りは変数のスコープを考えて実装を行う必要があります。

 TryGetComponent メソッドの処理結果が false の場合には Rigidbody コンポーネントの取得ができなかったため、rigid 変数は null のままで、false が処理結果として戻ります''。


 なお TryGetComponent メソッドには複数の書式があります。こちらは下記のリファレンスを参照してください。

参考サイト
Unity公式スクリプトリファレンス
Component.TryGetComponent


7.<Vector3.Distance() メソッド ー2点間の位置情報から距離と方向を算出するー>


 以下の計算式を使用することで、例えば、プレイヤーと敵との「距離」が差分として算出されます。このとき一緒に「方向」の情報も取得できます。

<2点間の距離と方向の算出>
  float distination = ゲームオブジェクトAの位置情報 - ゲームオブジェクトB の位置情報;

 この計算機能を持つメソッドが Vector3.Distance メソッドです。



 第1引数と第2引数に指定したVector3型の2点間の距離を、float型に変換して距離として戻してくれるメソッドになります。
戻り値に合わせて、左辺にfloat型の変数を用意して代入させることもできますし、比較処理の結果として利用することも出来ます。

 // 目的地に近づいたら
  if (Vector3.Distance(transform.position, destination) <= 0.15f) {
    // 停止させる
      agent.ResetPath();
  }

 今回の実装例では、キャラクターの位置と目標地点とを比較し、その戻り値の値が 0.15f 以下になった際には
ほぼ目標地点に到着しているものと判断し、そのタイミングで if 文内の処理が実行されて NavMeshAgent が停止する命令が実行されるロジックとなっています。

 
参考サイト
Unity公式スクリプトリファレンス
Vector3.Distance


8.<NavMeshAgent に用意されている変数とメソッド>


 NavMeshAgent クラスには多くの変数とメソッドが用意されています。
この機能を上手く活用することにより、AI による NavMeshAgent のルートの自動移動を実装することができます。

 NavMeshAgent 型をスクリプト内で宣言し、各変数やメソッドを利用するためには using UnityEngine.AI; の宣言が必要です。

 今回は実装に利用した機能のみを抜粋して掲載しています。
すべての機能は紹介できませんので、自分で調べてみましょう。


1.NavMeshAgent.destination 変数(SetDestination メソッド)

 NavMeshAgent 目標地点を設定することができる Vector3 型の変数です。
この情報をセットすることで、NavMeshAgent に目的地へ移動することを伝え、移動を開始させることができます。

 目標地点の設定方法にはもう1つ、SetDestination メソッドも用意されており、そちらでも同じように目的地の設定が可能です。

 SetDestination メソッドには bool 型の戻り値があり、正常に目的地の設定が要求されているかどうかを評価することが出来ます。
目的地が正常に要求されていれば true、要求に失敗した場合には false が戻ります。

 用途に応じて使いわけるようにしましょう。


 // 目的地の更新
  //agent.SetDestination(nextPos);  // どちらの処理で設定をしても問題なし
  
 agent.destination = nextPos;

<参考サイト>
Unity 公式スクリプトリファレンス
NavMeshAgent.destination
https://docs.unity3d.com/jp/current/ScriptReferenc...
Unity 公式スクリプトリファレンス
NavMeshAgent.SetDestination
https://docs.unity3d.com/jp/current/ScriptReferenc...
Unity 公式マニュアル
NavMeshAgent に目的地へ移動することを伝える
https://docs.unity3d.com/ja/current/Manual/nav-Mov...


2.NavMeshAgent.speed 変数

 NavMeshAgent によるルート移動時の最大速度の設定値です。0 にすることで移動は停止します。
NavMeshAgent コンポーネントをアタッチした際の初期値は 3.5 になっていますので、ゲームの内容に応じて設定を行います。
今回の実装例のように、スクリプトから制御も可能です。

 // 移動速度の設定
  agent.speed = 3.0f;

<参考サイト>
Unity 公式スクリプトリファレンス
NavMeshAgent.speed
https://docs.unity3d.com/jp/current/ScriptReferenc...


3.NavMeshAgent.ResetPath メソッド

 NavMeshAgent の現在の経路を削除します。
そのため、SetDestination メソッドなどによって再度目標地点を設定しない限り、動作しなくなります。

<参考サイト>
Unity 公式スクリプトリファレンス
NavMeshAgent.ResetPath
https://docs.unity3d.com/jp/current/ScriptReferenc...


9.GamblerCat ゲームオブジェクトに PlayerNavigationController スクリプトをアタッチして設定を行う


 ヒエラルキーにある GamblerCat ゲームオブジェクトを選択し、PlayerNavigationController スクリプトを
ドラッグアンドドロップしてアタッチしてください。

 スクリプトをアタッチしたら、必ずインスペクターを確認して、アタッチされていることを確認してください。

 PlayerNavigationController スクリプトに記述している RequireComponent 属性により、
自動的に NavMeshAgent コンポーネントが追加されています。


インスペクター画像




 追加したスクリプトとコンポーネントの確認と設定を行います。

 PlayerNavigationController スクリプトについては、移動速度の設定が行えますので、任意の値を設定してください。
移動速度については、ステージの広さなどにもよりますので、適宜調整を行うとよいでしょう。

インスペクター画像




 続いて、NavMeshAgent の設定を行います。

 Speed の値についてはスクリプトによって制御を行うようになりますので、設定不要です。
初期値のままでもよいですし、0 に戻しておいても構いません。

 それ以外の項目については、下記の画像を参考に設定してください。


インスペクター画像



 以上で設定は完了です。


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


 スクリプトの制御について、理解を深めてからゲームを実行します。
どのように動作すれば正しい挙動であるのか、それを自分で判断できる状態になってから、デバッグを行うようにしてください。

 ステージのフロア部分のゲームオブジェクトをマウスの左クリックしたとき、その地点を移動目標として
GamblerCat ゲームオブジェクトが移動を開始し、その地点に着いたら移動を終了して停止すれば、制御成功です。

 移動中であっても、別のフロアのゲームオブジェクトがクリックされた場合には、
そちらを移動目標として変更すれば制御成功です。

 またフロアのゲームオブジェクト以外の場所をクリックしたときには、その地点には移動しないように制御されていれば
それも制御成功です。この制御が行えていないと、ステージの外にも移動するようになってしまい、ゲームが成立しなくなります。

 Unity の教科書のアップルキャッチでのバスケットの移動制限を思い出してみてください。


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


 いまはまだアニメーションの設定をおこなっていないので、ゲームオブジェクトが移動だけすれば問題ありません。



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

 => 次は 手順8 −キャラクターのアニメーション遷移設定− です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

3Dトップビューアクション(白猫風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



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

管理人/副管理人のみ編集できます