Unityに関連する記事です

 引き続き、実装を行ったイベント用のデータベースである EventDataSO スクリプタブル・オブジェクトをゲーム内で活用する処理について実装を行います。


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


手順14 −イベント用のデータベースの利用−
24.DialogController スクリプトと NonPlayerCharacter スクリプトを修正して、EventData の情報を参照する処理に変更する


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

 ・スクリプタブル・オブジェクトを利用する方法
 ・引数と戻り値を使った処理の実装例



24.DialogController スクリプトと NonPlayerCharacter スクリプトを修正して、EventData の情報を参照する処理に変更する

1.設計


 EventDataSO スクリプタブル・オブジェクトをゲーム内で利用できる状態にしましたので、
この手順では実際にその情報を活用していく処理の設計を行って実装を行います。

 現在、NPC 用の会話イベントのデータとしてゲーム内で利用されている情報は、DialogController スクリプトにある、以下の2つの情報です。

  [SerializeField]
    private string titleName = "dog";

    [SerializeField]
    private string dialog = "ワンワン!";

 いままではこちらの変数に対してインスペクターより設定を行って数値を決めていました。
そのため、2つ以上の NCP 用ゲームオブジェクトを作成した場合、その都度、この部分に直接データを打ち込んで登録する必要があります。
数体ならば管理できますが、これがゲーム全体に数十体登場させるとなると、登録以上に管理が難しい状態になります。
 


 この設定の部分に、今回作成した EventDataSO スクリプタブル・オブジェクトの会話イベントのデータを利用するように処理の変更を行います。
NPC の会話イベントの内容・情報に対して、会話イベントのデータを反映することによって会話イベントの振る舞いを変更します。

 この処理を自動化して、NPC と会話イベントのデータの情報に合わせて、プレイヤーキャラが話しかけた際に会話イベントの内容(振る舞い)が自動的に変わるようにします。

 このような設計にすると、1つのゲームオブジェクトに対してデータベースに登録されているすべての会話イベントを作り出すことが可能になります。
この手法は他のデータベースでも同じように利用できます。例えば、キャラ用のプレファブが1つあり、キャラの情報が登録されているスクリプタブル・オブジェクトがあれば
1つのゲームオブジェクトから、キャラ用のデータベースに登録されているすべてのキャラを作り出し、そのように振る舞わせることが出来ます。

 DialogController スクリプトの修正内容としては上記の内容になります。
こちらではゲーム画面に情報を表示する処理を行う部分は変わりませんが、受け取った EventData に応じて、振る舞いが変わるようになります。

 会話イベント1番の EventData を情報として受け取っている場合には、その EventData の内容を表示するように、
表示する内容の制御方法を EventData の情報に基づいた設計ロジックに修正します。



 肝心の EventData ですが、DialogController スクリプト側では、この情報を受け取って利用をする設計になります。
そのため、いままでのように、DialogController スクリプト自体にデータ情報を登録する方法ではなくなります
 
 そうなるといずれかのスクリプトで EventData を取得して、その情報を DialogController スクリプトへと送る処理が必要になります。
現在、DialogController スクリプトの情報は NonPlayerCharacter スクリプトにおいて管理していますので、
こちらにて EventData を取得して登録を行うようにし、その情報をメソッドを通じて、DialogController スクリプトへと送ってもらう設計を考えます。

 以上の設計から、今回スクリプタブル・オブジェクトを利用して処理を実装していくためには、DialogController スクリプトだけではなく、
NonPlayerCharacter スクリプトにも処理の修正が必要になります。



 NonPlayerCharacter スクリプトでは、スクリプタブル・オブジェクトより EventData を取得して登録しておく処理を実装します。
また、DialogController スクリプトの OpneDialog メソッドを実行する際に、引数を通じて EventData を送信できるようにも修正を行います。

 そのためには事前準備として多くの処理の実装が必要になります。

<ロジックの流れ>
◇1.NonPlayerCharacter スクリプトと DialogController スクリプト内に、EventData 型の情報代入するための変数を用意しておく
◇2.NonPlayerCharacter スクリプトから DataBaseManager の GetEventDataFromNPCEvent メソッドを実行し、
     EventDataSO スクリプタブル・オブジェクトから必要となる EventData を探して用意しておいた EventData 型の変数に取得して代入する
△3.プレイヤーキャラが会話イベントを実行した際に、NonPlayerCharacter スクリプトから DialogController スクリプトの DisplayDialog メソッドを実行する際に、EventData の情報を引数を通じて渡す
△4.DialogController スクリプトの DisplayDialog メソッドにおいて、引数で取得した会話イベント用の EventData を利用して、ゲーム画面に、NPC の名前やメッセージを表示する

 ◇の部分は新しく実装する変数や処理、△は修正を行う処理になります。

 まず最初に◇1のために、EventData 型の変数を、それぞれのスクリプト内に宣言して用意しておきます。

 EventDataSO スクリプタブル・オブジェクトにはすべての会話イベントのデータが登録されていますが、
実際に利用する際には、利用実態に合わせて必要な情報を作成して運用していくことが必要になります。
つまり、スクリプタブル・オブジェクト自体はゲームのマスターデータとして利用し、ゲーム内ではそれを上手く活用して運用していくという形式になります。

 今回の場合、すべての会話イベントのデータの中から特定の会話イベントのデータを探す、という処理を実行して、それを EventData として
NonPlayerCharacter スクリプトに登録しておきます。そして、その情報を、DialogController スクリプトに渡す処理の流れになります。



 ◇2では、DataBaseManager スクリプトに用意してあるゲッターメソッドを利用して、必要となる EventData をスクリプタブル・オブジェクトのデータから探して取得します。
この処理を NonPlayerCharacter スクリプト内に追加することで、空の EventData に会話イベントで利用する EventData を取得します。
メソッドはすでに作成済ですので、適宜なタイミングでこのメソッドを実行すれば、EventData を取得出来ます。

 スクリプタブル・オブジェクトには複数の会話イベントのデータがありますので、NonPlayerCharacter スクリプト内に登録する会話イベントの番号を使って検索して取得を行うようにします。
そのため、GetEventDataFromNPCEvent メソッドにも引数として int 型の情報を取得して活用できる設計になっています。見直してみてください。



 △3では、NonPlayerCharacter スクリプト内で DialogController スクリプトの DisplayDialog メソッドを実行している場所があり、この処理を行うことによって
ゲーム画面に会話イベントが表示されることになります。このメソッドに引数を追加しておくことで、NonPlayerCharacter スクリプト内にある EventData の情報を
DialogController スクリプト側へと引数を通じて送信することが出来ます。

 最後の△4では、DialogController スクリプトの DisplayDialog メソッドを実行する際に、いままでは固定値として表示していた情報を
引数を通じて届いている EventData の情報を参照することよって、会話イベントの表示内容を EventData の内容に変更するように、処理を修正します。



 以上がロジックの流れになります。
 スクリプタブル・オブジェクトのデータを抽出して必要な EventData を取得したり、その際にメソッドの引数と戻り値を活用するなど、
今まで以上にプログラムの処理の理解を深めていくことが重要になります。



2.DialogController スクリプトを修正し、EventDataSO スクリプタブル・オブジェクトのデータを参照して反映する処理を追加する


 設計に基づいて、インスペクターで設定していた情報を EventDataSO スクリプタブル・オブジェクトの EventData クラスの情報を参照するように変更します。

 まずは EventData クラスの情報を扱えるように、EventData 型の変数を用意します。この変数に、会話イベントとして必要なすべてのデータが入ることになります。
イベントの種類、NPC の名前、メッセージなどの情報が変数として入っていますので、このデータを利用することで「どのような会話イベントとして振る舞うか」決まります。
この変数を利用することによって、EventData クラスの情報を参照して利用出来るようになります。

 この EventData クラスの情報は、外部のスクリプトから引数で受け取るように設計します。
いままで SetUpEnemy メソッドで bool 型のボスの有無の情報を受け取っていましたが、これを削除して、代わりに EventData 型を宣言して、ここでエネミーのデータを受け取れるようにします。


 ここで大切なポイントがあります。

 EventData クラスの情報を決定するのは、DialogController スクリプト側ではありません
DialogController スクリプトではあくまでも引数として届いた EventData クラスの情報を利用して設定を行うことであって、
会話イベントのデータを反映して会話イベントにそのデータに即した役割を与えることが仕事です。

 会話イベントのデータを決定し、「この情報を使って会話イベントに役割を与えて振る舞いを変えてください」と命令を出すのは NonPlayerCharacter スクリプト側になります。

 この役割分担の考え方についてもしっかりと学習して理解を深めてください。

 以上のことから、最初にも書いたように、この EventData クラスに含まれている情報については、この DialogController スクリプト内で個別に設定を行う必要がなくなります。
対象となる変数は titleName 変数と dialog 変数です。
なお変数を修正したり、削除する場合には、変数を管理してるスクリプト内だけではなく、この変数が外部のスクリプトにおいても利用されていないかを確認してから修正してください。



 EventData クラス内の変数はすべて public 修飾子によって宣言されています。
そのため、EventData クラスの情報を取得している変数からは、これらの public 修飾子の変数の情報をすべて利用できます。
例えば、EventType を参照したい場合には以下のようになります。

  // eventData 変数内に代入されている EventData 内の EventType の情報が EventType に登録されている列挙子の内、Talk の列挙子である場合
  if(evetData.eventType == EventData.EventType.Talk) {  }


 以前に学習したように、変数に代入されている情報からは、public 修飾子の情報をさらに取得して利用できます。
ピリオドを使った処理について、この機会にしっかりと覚えていきましょう。


DialogController.cs

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


 スクリプトを修正したらセーブします。



 ヒエラルキーにある NPC 用ゲームオブジェクト内の DialogCanvas ゲームオブジェクトを選択し、DialogController スクリプトのインスペクターを確認します。
新しく SerializeField 属性で宣言した変数が追加され、不要な変数が削除されています。


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



 上記の EventData 変数部分に、実際にゲームにおいて表示するための情報が自動的に登録されるようにします。
現在は空のままで問題ありません。


3.NonPlayerCharacter スクリプトを修正する


 設計に基づいて処理のロジックを組んでいきます。
設計で提示したロジックの流れと実装していく内容を1つずつ確認しながら、処理の内容を理解していきましょう。

 いままでと決定的に異なる部分は、DialogController スクリプト内で登録を行っていた
TitleName(NCP の名前)とDialog(メッセージ)がなくなり、そのための情報を EventData として取得して利用するという点です。
そしてその情報は、この NonPlayerCharacter スクリプトによって取得され、その情報を DialogController スクリプトへと渡すという処理の流れに変更になっている、という部分です。

 シングルトンクラスである DataBaseManager スクリプトにあるメソッドを実行するためには、事前の変数への代入や取得処理は不要です。
実行する際には、【クラス名.クラスの情報が代入されている static 変数.実行したメソッド名】の記述で処理が実行できます。
今回であれば、【DataBaseManager.instance.GetEventDataFromNPCEvent(引数の指定)】と記述すれば、メソッドを実行できることになります。
ピリオドを使った処理になりますので、しっかりと読み解けるようにしておきましょう。

 会話イベント用の EventData ですが、スクリプタブル・オブジェクト内のデータベースの番号(EventData.no)と同期する番号の設定のみを行うようにします。
この番号を利用して NCP 用の会話イベントを取得していく設計になっています。

 そのため、各 NPC のゲームオブジェクトに登録する番号が重要になってきます。
この番号の情報を使って、必要な EventData の情報を受け取る流れになるためです。


NonPlayerCharacter.cs

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


 スクリプトを修正したらセーブを行います。



 NPC 用のゲームオブジェクトのインスペクターを確認します。
新しく SerializeField 属性で宣言した変数が追加されています。


NPC 用のゲームオブジェクト インスペクター画像



4.処理を1つずつ読み解いていく


 今回追加された処理は新しい処理がたくさんあります。
順番に1つずつ処理を見直して、どのような内容になっているかを読み解いてみてください。

 例えば、戻り値の処理はどのように動いているのか、メソッドを追いかけて読んでください。

<NonPlayerCharacter.cs / Start メソッド>
 // DataBaseManager に登録してあるスクリプタブル・オブジェクトを検索し、指定した通し番号の EventData を NPC 用の EventData として取得して代入
 eventData = DataBaseManager.instance.GetEventDataFromNPCEvent(npcTalkEventNo);
   ↓ 上記処理の左辺の変数には、こちらのメソッド処理結果が代入される。何故ならば、このメソッドは EventData 型の戻り値を持つメソッドであるため
<DataBaseManager.cs / GetEventDataFromNPCEvent メソッド>
    /// <summary>
    /// NPC 用のデータから EventData を取得
    /// </summary>
    /// <param name="npcEvent"></param>
    /// <returns></returns>
    public EventData GetEventDataFromNPCEvent(int npcEventNo) {

    // EventDataSO スクリプタブル・オブジェクトの eventDatasList の中身(EventData)を1つずつ順番に取り出して、eventData 変数に代入
        foreach (EventData eventData in eventDataSO.eventDatasList) {

      // eventData の情報を判定し、EventType が Talk かつ、引数で取得している npcEventNo と同じ場合
            if (eventData.eventType == EventData.EventType.Talk && eventData.no == npcEventNo) {

        // 該当する EvenData であると判定し、その情報を戻す
                return eventData;
            }
        }

    // 上記の処理の結果、該当する EvenData の情報がスクリプタブル・オブジェクト内にない場合には、null を戻す
        return null;
    }
    ↓ 以上のことから、この1行の処理は、次のような処理になっている
 // 左辺と右辺の型が同じ EnemyData 型なので、代入処理が成立する
 eventData = DataBaseManager.instance.GetEventDataFromNPCEvent(npcTalkEventNo); => このメソッドの処理結果の EnemyData が戻ってくるので、型の情報は EventData 型

 変数を型で見た場合、EventData 型 = EventData 型になっていることがわかります。

 このように、1つずつの処理を順番にしっかりと読み解いていくことが大切です。
 

5.NPC 用のゲームオブジェクトの設定を行う


 インスペクターより、npcEventNo 変数に数字を登録します。
この数字がスクリプタブル・オブジェクト内で List で管理されている各 EventData の no 変数と一致したものを
会話イベント用の EventData として取得する設計になっています。

 現在、EventData は3つ作成してあると思いますので、0 - 2 のいずれかの数字を登録しておいてください。
また、スクリプタブル・オブジェクトの no の値が重複していないか、確認してください。重複していると正常な取得が行えません。


NPC 用のゲームオブジェクト インスペクター画像



 以上で設定は完了です。


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


 すべての実装が完了しましたので、ゲームを実行して順番に処理の内容を確認していきます。

 ゲーム実行したら ヒエラルキーにある NPC 用のゲームオブジェクトを選択してインスペクターを確認します。
NonPlayerCharacter スクリプトの Start メソッドにおいて、スクリプタブル・オブジェクトから1つの EventData を取得して、
空であった EventData 型の変数へ代入処理が行われているはずです。各変数に値が代入されているかを確認してください。


<NonPlayerCharacter スクリプトの EventData の値がそれぞれ異なり、この情報を設定して異なる会話イベントとして振る舞っている>





<スクリプタブル・オブジェクトの no と NonPlayerCharacter の npcEventNo がリンクしていることがわかる>




 データが反映されていたら、会話イベントを発生させてみてください。
NonPlayerCharacter スクリプトにある EventData の情報がメソッドを通じて DialogController スクリプトにも送られて、そのデータを利用してゲーム画面に表示されます。


<実装画像 ‘韻献押璽爛ブジェクトだが、EventData を参照することで、異なる会話イベントが発生する>



<実装画像◆‘韻献押璽爛ブジェクトだが、EventData を参照することで、異なる会話イベントが発生する>



<実装画像 同じゲームオブジェクトだが、EventData を参照することで、異なる会話イベントが発生する>



 スクリプタブル・オブジェクトをデータベースのように活用することにより、このように、1つのゲームオブジェクトに異なる振る舞いをさせることが可能になります。
同じ手順で NPC の画像自体を変更することもできますので、NPC 自体の振る舞いを変更し、1つのゲームオブジェクトから異なる NPC を作り出すことも出来ます。

 今回のケースであれば、犬の画像、村人の画像、店員の画像を用意することができれば、
データを利用することで1つの NPC のゲームオブジェクトに異なる NPC としての振る舞いを与えることが出来ます。


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

 次は 手順15 ーランダムエンカウントの実装ー です。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

3Dレールガンシューティング(応用編)

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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