i-school - 3Dレールガンシューティング 手順9
 ここからも2回の手順に分けて、移動後の各地点において、ミッションが発生するかどうかを判定する機能を実装します。

 RailPathData クラスに新しい変数を追加して、その地点においてミッションが発生するかどうかを判定できるようにします。



手順9 ーミッション発生用機能の追加ー

 新しい学習内容は、以下の通りです。

<学習内容>
 ・クラス内に別のクラスを作成する(入れ子クラス)



1.設計


RailPathData クラス内に登録した経路上の1つの地点に到着するたびに、RailMoveController クラスに用意した CheckArrivalDestination メソッドを利用して
ミッションが発生するかどうかの確認処理を行う機能を実装します。そのためには、RailPathData クラスに修正が必要になります。

 各クラスの役割と役割を実装するための修正は以下の通りです。また、新しく GameManager クラスを作成します。

 ◇RailPathData      新しくミッション判定用の変数を追加する
              現在の状態のまま変数を追加する方法もあるが、ここでは RailPathData クラス内に PathDataDetail クラスを新しく作成して経路の情報を1つのクラスにまとめて運用する

 ・RailMoveController   CheckArrivalDestination メソッド内で GameManager クラス内の CheckMissionTrigger メソッドを実行する

              SetUpRailMoveController メソッドを作成して GameManager クラスから実行し、RailMoveController クラスの初期設定を行う
              合わせて、SetNextRailPathData メソッドを作成して GameManager クラスから実行し、RailPathData クラスの情報を外部のクラスから引数を通じて受け取るようにする
              このメソッド内で移動を実行するメソッドである StartRailMove メソッドを実行するようにする(経路のセットがない限り、移動を実行しないようにする)
              よってデバッグ用に Start メソッド内で実行していた StartRailMove メソッドはコメントアウトする

 ・GameManager       SetMissionTrigger メソッドで、各地点ごとのミッションの発生有無の情報を isMissionTriggers 配列変数として作成しておく
              CheckMissionTrigger メソッドが実行されたら、isMissionTriggers 配列変数を確認して、ミッションの発生有無の判定を行う

              RailMoveController クラス内の2つのメソッドを実行する命令を用意する

 今回の手順は、RailPathData スクリプトの修正を行います。


2.RailPathData クラスの変数の情報を新しいクラスとして実装する


 RailPathData クラスには2つの配列変数があります。
この情報をまとめたクラスを作成して、その中に新しい変数を追加する設計で実装を行います。

 1つのスクリプト・ファイルの中には複数のクラスを記述することができます。
特に、クラスの内部に別のクラスを記述することを入れ子(ネスト)されているクラス といいます。

<参考サイト>
MicroSoft
入れ子にされた型
https://docs.microsoft.com/ja-jp/dotnet/csharp/pro...
@IT 様
内部クラスの使いどころとは?[C#/VB]
https://www.atmarkit.co.jp/ait/articles/1805/09/ne...

<入れ子クラスの構造で作成した場合>



<今までと同じ書式の場合>


 インスペクターの表示が異なっていることがわかると思います。
今回は入れ子クラスを利用した手順で進めていきます。


3.<実装例1> クラス内に別のクラスを作成(入れ子クラス)して利用する方法


 クラス内に入れ子として作成する PathDataDetail はクラスではなく、構造体(struct)でも構いません(クラスの継承を行わないため)。
入れ子となるクラス内の変数は public 修飾子に変更しないとアクセスできませんので注意してください。
同じファイル内に存在していますが、あくまでも違うクラスになるため、ファイル内であってもアクセスする際は外部のものとして扱われます。


RailPathData.cs

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



 セーブしてインスペクターを確認してみてください。表示がいままでと異なることが分かります。
pathDataDetails 配列変数の値を、現在用意してある経路の数に設定してください。
もしもインスペクターに入れ子のクラスの情報が表示されない場合には、 入れ子クラスの前に [System.Serializable] 属性を書き忘れていないか 、確認してください。
pathDataDetails 配列変数が public 修飾子になっていても、PathDataDetail クラスがシリアライズされていないとインスペクター上には表示されません。

 isMissionTrigger 変数には適宜チェックをいれておいてください。チェックがある地点でミッションが発生するという判定に使います。


<RailPathData ゲームオブジェクト インスペクター画像>


 以上で設定は完了です。


4.<クラス内に別のクラスを作成する(入れ子クラス)>


 RailPathData クラスの宣言フィールドにおいて、別のクラスを作成しています。今回は PathDataDetail クラスです。
C# では、1つの独立したクラス(ファイル)としてではなく、あるクラスの中の宣言フィールドに別のクラスを作成しても使用することができます。
このような構造を入れ子(ネスト)クラスと言います。

public class RailPathData : MonoBehaviour {

    // RailPathData クラスの宣言フィールド


    [System.Serializable]
    public class PathDataDetail {

        // PathDataDetail クラスの宣言フィールド

        [Tooltip("移動時間")]
        public float railMoveDuration;

        [Tooltip("移動地点とカメラの角度")]
        public Transform pathTran;

        [Tooltip("ミッションの発生有無。オンで発生")]
        public bool isMissionTrigger;
    }

    // ここからまた、RailPathData クラスの宣言フィールド

    [Header("経路用のパスデータ群")]
    public PathDataDetail[] pathDataDetails;

 特定のクラスでのみ使用することが確定しているような、使用範囲の狭いクラスであれば、このように入れ子クラスにした方がスクリプト・ファイルが増えずに済みます。
 また設計上、ファイルにはしたくない(隠しておきたい)クラスを作成する場合にも用いられます。

 使用方法は他のクラスと同じです。ただし参照する場合は、RailPathData.PathDataDetail という書式で、入れ子クラスのあるクラスの後に、入れ子クラスを順番に記述します

 入れ子のクラスは[System.Serializable] 属性を付与しておくと、インスペクター上に表示させたり、別のオブジェクトに変換することが出来るようになります。

 入れ子にできるクラスの数に制限はありませんが、構造が深くなりすぎると処理を追うのが大変になります。
設計を考えて入れ子クラスにするか、1つのファイルとしてクラスを作成するかを検討していくことが大切です。


5.<実装例2> いままで同じ内容で配列変数を追加する場合


 いままでの書式を利用して、入れ子クラスを作らない場合の記述例です。
今回はこちらの記述での実装は行いませんが、参考例として提示しておきます。

RailPathData.cs

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






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

 => 次は 手順10 ーミッション発生の判定機能ー です。