Unityに関連する記事です

 2回に分けて、プレイヤーキャラと NPC(ノン・プレイヤー・キャラクター)との会話イベントの実装を行います。
前回デバッグして会話イベントの制御を確認してありますので、会話イベント発生時に会話イベント用のウインドウを表示し、その中にメッセージを表示する制御機能を実装します。


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


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

手順11 ーNPC との会話イベント用ウインドウの実装ー
19.NPC 用のゲームオブジェクト用の会話イベントウインドウを作成する
20.DialogController スクリプトを作成し、NPC との会話イベント時に会話イベントウインドウが表示・非表示する処理を実装する



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

 ・CanvasGroup コンポーネント
 ・GetComponentInChildren メソッド



19.NPC 用のゲームオブジェクト用の会話イベントウインドウとスクリプトを作成する

1.設計


 会話用ウインドウを作成し、Player ゲームオブジェクトが NPC ゲームオブジェクトに対してキー操作を行った際に、
この会話用ウインドウを表示し、会話用のメッセージを表示するように制御を行います。

 会話用のウインドウについては、実装する方法が多くあります。これは既存のゲームを元に考えてみてください。
ドラクエなどは、常に画面の下方向に会話イベント用のウインドウが開きます。
他のゲーム(ロマサガなど)は、話しかけた相手の近くに会話用のウインドウが開きます。

 そのため、会話用のウインドウ、と一口にいってもどのような形式で表示を行うのか、という部分から仕様を設計しておく必要があります。
それが確定してはじめて、会話用のウインドウの製作が行えるようになります。
 
 今回は、話しかけた NPC の近くに会話用のウインドウを表示させる方式で実装を行います。


<実装画像>



 なおこの方式の会話用のウインドウは、プレイヤーキャラが話しかける位置によっては画面から見切れてしまう場合があります。
もしも実装できるイメージが沸いたら、会話用のウインドウを表示させる位置を自動的に制御するようにもしてみましょう。


<実装画像>



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



2.NPC 用ゲームオブジェクトの子オブジェクトとして Canvas ゲームオブジェクトを作成し、設定を行う


 ヒエラルキー上の NPC 用のゲームオブジェクトの上右クリックをしてメニューを表示し、
UI => Canvas を選択して Canvas ゲームオブジェクトを作成します。ヒエラルキーに Canvas ゲームオブジェクトが作成されます。

 一緒に EventSystem も作成されます。このゲームオブジェクトはタップ感知などを行うものなので、削除しないでください。
これは Canvas ゲームオブジェクトと1セットで扱いますのでそのままでヒエラルキーにあっても問題ありません。

 名前を DialogCanvas に変更してください。


ヒエラルキー画像



 続いて DialogCanvas ゲームオブジェクトの設定を行います。



 通常 Canvas コンポーネントがアタッチされているゲームオブジェクトは Scene ビューではなく、専用の編集スペースを持つゲームオブジェクトになります。
今回はこのゲームオブジェクトを Canvas のスペースではなく、Scene ビュー内に設置して、通常のゲームオブジェクトと一緒にゲーム画面内に表示するようにします。
そのための設定を最初に行います。

 DialogCanvas ゲームオブジェクトのインスペクターを確認し、Canvas コンポーネントの項目を設定します。

 Render Mode を World Space に変更します。これで DialogCanvas ゲームオブジェクト を Scene ビュー内に直接配置出来るようになります。

 Event Camera には Main Camera ゲームオブジェクトが自動的にアサインされますが、もしも抜けている場合にはドラッグアンドドロップしてアサインしてください。

 Sorting Layer は表示の優先順位ですので、Chara のSorting Layer を設定してください。これで NPC 用ゲームオブジェクトよりも画面の前面に表示されるようになります。
この設定を行わないと表示された Canvas が NPC 用のゲームオブジェクトよりも背面になるため、文字が隠れてしまいます。

 以上の設定で Sceneビュー内の他のゲームオブジェクトと同じように移動したり、大きさを変更したりすることが出来ます。
またカメラを通じてゲーム画面に映るようになっていますので、配置によってはカメラに映らないようにもすることも出来ます。


参考サイト
Unity公式マニュアル
World Space UI の作成
https://docs.unity3d.com/ja/2019.4/Manual/HOWTO-UI...



 RectTransform コンポーネントの Scale の値を調整し、サイズを調整しましょう。

 Position については適宜な位置に調節してください。
NPC 用のゲームオブジェクトの少し上位になるように配置しておくといいでしょう。

 Width と Height がこのゲームオブジェクトの上下左右のサイズになりますので、こちらも適宜な大きさに変更してください。

 Canvas Renderer コンポーネントと Graphic Raycaster コンポーネントは変更の必要はありません。


インスペクター画像



Sceneビュ−画像




 設定が完了しましたので、最後にコンポーネントを追加します。

 インスペクターの一番下にある Add Component ボタンを押して、Canvas Group コンポーネントを探して追加してください。
設定は変更しなくて問題ありません。

 Canvas Group コンポーネントは、このコンポーネントがアタッチされているゲームオブジェクトと、その子のゲームオブジェクトがグループ化されます。
これにより、グループ全体の透明度を変更したりすることができます。
そのため、透明度(Alpha)を操作した場合、グループ化されているため、子要素も一緒に透明になったり、元に戻ったりします。
例えば、子オブジェクトが3つあった場合、それらをまとめて表示したり、あるいは非表示にしたり、という操作が可能になります。

 次の手順以降では、DialogCanvas ゲームオブジェクトに子オブジェクトを追加していきますので、
それらをまとめて操作制御するためにこのコンポーネントを利用していきます。

Unity公式マニュアル
CanvasGroup
https://docs.unity3d.com/ja/2020.1/Manual/class-Ca...
TechProjin様
【Unity】Canvas Groupってこんなに便利だったのか…
https://tech.pjin.jp/blog/2017/03/20/unity_ugui_ca...


3.DialogCanvas ゲームオブジェクトの子オブジェクト群を作成する


 DialogCanvas ゲームオブジェクトの子オブジェクトとして作成するゲームオブジェクト群は任意です。
ここには通常の Canvas 内と同じように、Text や Image などのコンポーネントを持つゲームオブジェクトを配置出来ます。

 今回の場合は、次のようなゲームオブジェクトを用意しています。

 ・imgBackground    UI => Image にて作成。メッセージ表示時の背景用の画像を設定するゲームオブジェクト
 ・txtDialog      UI => Text にて作成。メッセージ表示を行うゲームオブジェクト
 ・imgTitleBackground  UI => Image にて作成。メッセージ表示時の NPC の名前表示を行う部分の背景用の画像を設定するゲームオブジェクト
 ・txtTitleName     UI => Text にて作成。NPC の名前表示を行うゲームオブジェクト


ヒエラルキー画像



 今まで学習してきた復習になりますので、自分のイメージに沿ったゲームオブジェクトの配置と設定を行ってみてください。
フォント、文字の位置、大きさなど、レイアウトの学習になります。

 参考画像は載せておきますが、この通りにする必要はありません。(こちらは画像は未設定で、色の設定しかしていません)

 完成したら、各 Text コンポーネントの Text プロパティ欄の文字列は空白にしておいてください。
こちらにはスクリプトを利用して文字列を表示するように制御を行います。


4.imgBackground ゲームオブジェクトの設定


インスペクター画像



Scene ビュー画像




5.txtDialog ゲームオブジェクトの設定


インスペクター画像



インスペクター画像



Scene ビュー画像




6.imgTitleBackground ゲームオブジェクトの設定


インスペクター画像



Scene ビュー画像




7.txtTitleName ゲームオブジェクトの設定


インスペクター画像



インスペクター画像



Scene ビュー画像



 以上で DialogCanvas ゲームオブジェクトは完成です。

 Raycast Target や、Cull Transparent Mesh などのスイッチがどのような機能があるのか、
1つずつ確認しながら設定を行って丁寧に作成してください。


20.DialogController スクリプトを作成し、NPC との会話イベント時に会話イベントウインドウが表示・非表示する処理を実装する

1.設計


 Player ゲームオブジェクトの制御を PlayerController スクリプトが行っているように、
作成した DialogCanvas ゲームオブジェクトの制御を行うためにも、専用のスクリプトを作成して制御できるようにします。

 スクリプトを利用することにより、例えば、Text コンポーネントに会話用の文字列を表示したり
CanvasGroup コンポーネントを制御して会話用ウインドウを表示・非表示の切り替えをしたりといった
DialogCanvas ゲームオブジェクト全体の制御を行うことが出来ます。

 このスクリプトは DialogCanvas ゲームオブジェクト以外にアタッチしても、DialogCanvas ゲームオブジェクトを制御することは可能です。
ですが、スクリプトによって制御管理するゲームオブジェクトが確定している場合には、制御したいゲームオブジェクトにアタッチしておいた方がわかりやすいでしょう。
PlayerController スクリプトが Player ゲームオブジェクトにアタッチされているのと同じ理由です。



 DialogCanvas ゲームオブジェクトにアタッチするスクリプトには、先ほども例にあげたように表示・非表示の切り替えなどの制御をさせる処理を記述します。
これらの処理はこのスクリプトの中に記述はされているものの、その処理を呼び出す元はスクリプト内とは限りません

 今回のケースであれば、プレイヤーキャラが NPC の方向を向いてキー操作を行った際に、会話用ウインドウが表示されることが求められます
つまり、DialogCanvas ゲームオブジェクトを制御する命令については、これらのタイミングに合わせて行われることが適切なタイミングであると考えられます。

 PlayerController スクリプトの命令を受けて、NonPlayerCharacter スクリプト内の処理が実行され、Debug の処理が制御されていることは確認しました。
この続きで、NonPlayerCharacter スクリプト内の Debug の処理の部分に、DialogCanvas ゲームオブジェクトを表示・非表示の切り替え処理を呼び出す命令を実装すれば
一連の処理の流れが完成し、Player のキー操作に合わせて、会話用ウインドウが開く、という制御処理が出来上がります
非表示する場合も同様です。
 


 効率の良い制御をするための設計を行うには、このように複数のスクリプトを経由して実行される処理が多くあります
逆に考えると、1つのスクリプトに記述した処理をすべてそのスクリプト内で完結させる必要はまったくありません

 制御する実処理、それを実行するタイミング、この2つを分けて考えていくことが大切になります。



 例えば、電話帳のアプリをイメージしてください。
電話帳内はあいうえお順に並んでいますが、上から順番にかけていく、なんてことはまずありません。

 誰しも、電話帳に登録した相手には、必要な時だけ連絡を取ると思います。
登録されているからといって、用事がなければ、やはり連絡は取りません。

 これと同じことをスクリプトでも実行していると考えてみてください。

 スクリプト(クラス)が電話帳です。電話帳には、仕事先用、プライベート用と、いくつかの種類があります。

メソッドは誰かの電話番号です。仕事先用の電話帳には、仕事の連絡先がはいっていることでしょう。
メソッドの引数は、相手が求めている用事です。あなたは、電話をしたときには、その要件を伝えると考えてください。

 あなたは必要なタイミングで、要件を伝える目的で電話をかけます => 引数を用意してメソッドを呼び出します。



public class 仕事先用電話帳 {

   public [戻り値 = 電話の返事・結果] [メソッド名 = 取引先_Aの電話番号] (引数 = 電話をかけるときに伝える用事){   <= 用事があるときに、用事を伝えて、かけます

      // この取引先で使う情報 

    // 伝えた用事の件も何か情報が更新されるかもしれません(引数を使う)

    // 要件によっては電話の結果がある場合もあります(戻り値)
  }
}

 こんなイメージです。
 

2.DialogController スクリプトを作成する


 DialogCanvas ゲームオブジェクトの制御を行うためのスクリプトを作成します。
このスクリプトを利用して、DialogCanvas ゲームオブジェクトを表示・非表示を切り替えます。
また、会話イベントのメッセージなども表示させます。

 これらの処理は表示用と非表示用として、それぞれメソッドにまとめておき、
外部のスクリプトより呼び出されることを前提に作成を行います。

 先ほどの電話帳を思い浮かべてください。
ここでは電話帳内に電話番号を登録している作業です。
public で電話番号を登録できれば、いつでも電話をかける(外部のスクリプトから命令を出す)ことができます。


DialogController.cs

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


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


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


 NPC 用のゲームオブジェクトの子オブジェクトである DialogCanvas ゲームオブジェクトに
DialogController スクリプトをドラッグアンドドロップしてアタッチします。

 SerializeField属性で宣言している情報がインスペクター上に表示されますので、
それらの変数を利用して制御を行いたいコンポーネントの情報を持つゲームオブジェクトをドラッグアンドドロップしてアサインしてください。
自動的に対象となるコンポーネントの情報が登録されます。


インスペクター画像



 以上でゲームオブジェクトの設定は完了です。


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


 DialogController スクリプトを利用することで会話イベント用のゲームオブジェクトを制御することができるようになりました。
あとは、そちらに用意したメソッドに対して命令を出す処理を実装することにより、
任意のタイミングで会話イベント用のウインドウの開閉が可能になります。

 ヒントとしましては、先ほどの手順で Debug を利用して制御を確認してありますので、
TODO 機能を利用して記述してある部分に対象となる命令文を実装していきましょう。

 次にどの処理を書きたい、この処理をいずれ書きたい、というイメージがある場合には
忘れずに TODO 機能を利用して残しておくようにしてください。
特に処理のタイミングまで把握して記述しておくことができれば、該当する部分に対してすぐに実装命令を記述することが可能になります。

 こちらも、先ほどの電話帳のイメージのうち、電話をかける方を思い浮かべてください。

 まずはヒントを参考に、実装例を見ずに、自分で処理を書いて実行してみてましょう。
実装例をみるのはそれからでも遅くありません。


NonPlayerCharacter.cs

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


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


4.<GetComponentInChildren メソッド>


 指定したゲームオブジェクトの子オブジェクトをすべて検索し、<型>で指定したコンポーネントの情報を取得するメソッドです。
取得した情報は戻り値を利用して戻されますので、左辺に変数を用意しておくことで代入処理が実行されます。

  GetComponentInChildren<DialogController>();

 今回の実装の場合、GetComponentInChildren メソッドの前に他の変数の情報はありませんので、この場合は
GetComponent メソッドと同様で、このスクリプトがアタッチされているゲームオブジェクトを基準に処理が実行されます。

 NonPlayerCharacter スクリプトは NPC 用のゲームオブジェクトにアタッチされていますので、
このゲームオブジェクトから見て、子オブジェクトにあたる DialogCanvas ゲームオブジェクトにアタッチされているコンポーネントの中から、
<DialogController> の情報を探して取得します。


ヒエラルキー画像



 今回は NPC 用のゲームオブジェクトから見て子オブジェクトは DialogCanvas ゲームオブジェクトのみですので、
DialogCanvas ゲームオブジェクトのみが対象になります。子オブジェクトが複数ある場合には、それらをすべて検索して、指定されたコンポーネントを1つだけ取得を行います。


参考サイト
Unity公式スクリプトリファレンス
GameObject.GetComponentInChildren
https://docs.unity3d.com/ja/current/ScriptReferenc...


 注意したいのは、DialogCanvas ゲームオブジェクトの子オブジェクト、つまり、NPC 用のゲームオブジェクトからみて孫にあたるゲームオブジェクトは
このメソッドの対象外になるという部分です。あくまでもこのメソッドで取得できる対象のゲームオブジェクトは基準となるゲームオブジェクトから見た子オブジェクトのみです。
なお、複数の子オブジェクトがある場合には、深さ優先で、それらの中から1つだけコンポーネントを取得します。
もしも複数の子オブジェクトから同じタイプのコンポーネントを複数取得したい場合には GetComponentsInChildren という別のメソッドがあります。


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



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


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

 次は 手順12 ーイベント用のデータベース作成ー です。

<応用>NonPlayerCharacter スクリプトを修正する


 プレイヤーキャラがキー操作を行った位置によって、会話用のウインドウを表示する位置を
ゲーム画面の上側か下側かを自動的に制御するようにします。

 自動的に制御を行うということは、何らかの情報を評価・判定して、その結果としてウインドウを表示する位置を変更させるようにします。

 方法はいくつかありますが、今回は、プレイヤーキャラの Y 軸の位置と NPC Y 軸の位置によって判定を行うようにしています。
NPC の Y 軸の位置からみて、プレイヤーキャラの方が高い位置にいるのであれば、ウインドウを表示する位置をゲーム画面の上側に、
逆の場合にはゲーム画面の下側にしています。

 このように、プレイヤーキャラが NPC からみてどの位置にいるかが分かれば見切れることを防ぐことが出来ます。
Player の位置情報ですが、PlayTalk メソッドの引数には、PlayerController スクリプトより、プレイヤーキャラの位置情報が Vector3 型でちゃんと届いています。
これを活用してみてください。TODO の部分もヒントになります。


NonPlayerCharacter.cs

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


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



 処理にはコメントを割愛してあります。
自分でコメントを書いてみましょう。しっかりと処理が読めていればコメントを書くことができると思います。

 ゲームを実行して、プレイヤーキャラの位置で会話ウインドウの位置が制御されるか、確認してください。

コメントをかく


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

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

Menu



技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

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

3D脱出ゲーム(抜粋)

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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