Unityに関連する記事です

 3回に分けて、プレイヤーキャラと NPC(ノン・プレイヤー・キャラクター)との会話イベントの実装を行います。

 実装する処理、および処理の考え方についてはかなり深い部分での学習になりますので、1回の学習で難しくても復習しながら進めていってください。


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


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

手順16 ーNPC との会話イベントの実装ー
20.プレイヤーの向いている方向に NPC がいる場合に会話イベントが発生する処理を実装する



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

 ・RaycastHit2D 型と Physics2D.Raycast メソッド
 ・Debug.DrawLine メソッド
 ・LayerMask.GetMask メソッド
 ・TryGetComponent メソッドと out キーワード宣言



20.プレイヤーの向いている方向に NPC がいる場合に会話イベントが発生する処理を実装する

1.設計


 プレイヤーキャラには向いている方向の情報が設定されています。
これは移動の際のキー入力より取得していますので、現在の最新の方向を取得出来ています

 この情報を活用して、プレイヤーキャラの向いている方向に対して NPC が存在している場合には
会話イベントの Debug.Log メソッドが実行されるように処理を組み立てていきます。



 処理の実装方法には色々な方法がありますが、今回はキャラの向いている方向の情報を利用して、Ray という見えない光線を投射する機能を活用します。

 Ray はゲームオブジェクトの持つコライダーに反応をします。
この処理を活用し、特定のボタンを押したら、キャラの向いている方向に Ray を投射し、その一定方向にコライダーを持つゲームオブジェクトが存在していたら
Ray がそのゲームオブジェクトにぶつかって情報を取得します。

 この時点では「どの」ゲームオブジェクトであるかは判明していませんので、Ray がぶつかったゲームオブジェクトのレイヤーを基準に判定を行います
Ray がぶつかったコライダーを持つゲームオブジェクトのうち、レイヤーが NPC に設定されているゲームオブジェクトである場合には、
そこで初めて「会話する対象のゲームオブジェクト」として認識するように制御を行うようにします。

 これが今回の会話イベントを発生させるための設計ロジックです。

 レイヤーで判定を行っているため、今回は NPC にのみ反応をしていますが、この部分を例えば「宝箱」のレイヤーや、「障害物」のレイヤーというように
ゲームオブジェクト単位で目的に応じたレイヤーの設定を行っておくことにより、プレイヤーキャラは特定のボタンを押すだけで、
その対象物のレイヤーを判別する制御処理があることによって、1つのボタンで複数のイベントを発生させることも可能です。

 これは、ドラクエの便利ボタンや FF のアクションボタンのように、対象物によって自動的に処理を分岐するようにする設計方法です。


2.PlayerController スクリプトを修正する


 設計で考えた内容とロジックを元にして、キャラの現在の方向の取得と、
その方向に合わせた移動アニメの再生の制御処理を実装します。

 また会話イベント発生時用に判定用の変数を用意しています。
この情報を利用することで、会話イベント時には移動のキー入力を受け付けずに移動を出来ないように制御しています。

 このように書くと非常に簡単に見えますが、そこに至るまでの過程を説明します。
この部分を考えて実装を行うのがプログラマーの仕事になるためです。



 すべての分岐制御処理には、その判断基準となるための情報があります。
すでにある情報を活用することで分岐を作成できるものもあれば、新しく変数を用意して、分岐のために運用する必要があるものもあります。

 今回のケースでは「会話イベント中であるかどうか」という判断が行うことができれば、その情報を元に分岐を作成し、
「会話イベント中であれば移動のキー操作を行えないようにする」という制御処理を実装することが可能になります。

 ですが現在はまだ、この「会話イベント中であるかどうか」を判断できる情報はどこにもありません
どこにもない場合、その判断するための情報としての意味を持たせて、判断用に利用する変数を新しく用意する必要があります。

 新しく変数を用意する、ということは、その変数には明確な目的や意味が必要になります。
そうしないと、変数を利用したり、運用したりということが行えません。この意味付けをするのがエンジニアの役割でもあります。
つまり、この変数の持つ情報とは、どのようなときに利用するのか何の判断要素となりえるのかという部分を考えて運用していく必要があるということになります。
 


 今回の場合であれば、「会話イベント中であるかどうか」という判定に利用したい、という目的があります。
この時点で新しく作成する変数には明確な運用目的がありますので、あとは、その情報をどのように活用していくかに着目します。

 例えば bool 型の変数を作成するとした場合、値には真偽のいずれかの情報が代入されますので、
真(true)の場合にはどのような状態偽(false)の場合にはどのような状態、という設定を自分で考えて、その考えに沿った分岐を作成することで
プログラム内での運用が行えるようになります



 そういった部分に注目しながら、今回のプログラムを見ていってください。
そして、どの部分にどのような変数が使われていることで分岐が発生して処理が制御されているのかを、1つずつ確認してみてください。


PlayerController.cs

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


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


3.InputManager の設定を行う


 Unity Editor の左上のメニューより、Edit => Project Settings を選択し、Project Settings ウインドウを開きます。
左側の項目より、Input Manager を選択します。

 Vertical の下にある設定内容である Fire1 の Name 内の文字列を "Action" に変更してください。
この文字列を PlayerController スクリプト内のキー入力の情報として利用しています。
Fire1 の部分も Action に変更になります。
もしも Fire1 のまま利用するのであれば、同スクリプトの文字列を "Action" ではなく "Fire1" に修正してください。


InputManager



 以上で設定は完了です。


4.<RaycastHit2D 型と Physics2D.Raycast メソッド>


 新しく学習した処理について順番に説明を行います。
基本的にはこの説明を読んで終わりではなく、Unity の公式マニュアルなどを読んだり、
他にも参考になるサイトがありますので、ぜひ自分で調べていただいて、より深い知識として吸収できるよう復習に努めてください。



 Physics2D クラスの持つ Raycast メソッドは、空間のある地点から特定の方向にめがけて、見えない光線(レイ)を投射する処理です。
この光線はコライダーを持つオブジェクトにヒットをして、そのヒットしたオブジェクトの情報を、RaycastHit2Dという型として戻り値を返してくれます
そのため、左辺に RaycastHit2D 型の hit 変数を用意しています。

参考
Unity公式スクリプトリファレンス
Physics2D.Raycast
https://docs.unity3d.com/ja/current/ScriptReferenc...
Unity公式スクリプトリファレンスRaycastHit2D
https://docs.unity3d.com/ja/current/ScriptReferenc...

 今回の実装例です。

 // Player の位置を起点とし、Player の向いている方向に 1.0f 分だけ Ray を発射し、NPC レイヤーを持つゲームオブジェクトに接触するか判定し、その情報を hit 変数に代入
  RaycastHit2D hit = Physics2D.Raycast(rb.position, lookDirection, 1.0f, LayerMask.GetMask("NPC"));

 今回の処理では、Player ゲームオブジェクトの位置を起点(第1引数 = rb.position)とし、Player の向いている方向(第2引数 = lookDirection)に 1.0f 分(第3引数 = 1.0f)だけ Ray を発射しています。
そのため、あまりに離れているゲームオブジェクトのコライダーとは接触しないようになっています。

 このとき、NPC レイヤーを持つゲームオブジェクトに接触するか判定し(第4引数 = LayerMask.GetMask("NPC") メソッドの戻り値)、取得した情報を hit 変数に代入しています。

 hit 変数の情報は RaycastHit2D 型ですので、この情報からは、Collider 型の情報を取得することが出来ます。

参考
うら干物書き様
【Unity】マウスのある場所にオブジェクトを配置したい
https://www.urablog.xyz/entry/2017/04/28/213010


5.<Debug.DrawLine>


 この機能は、Sceneビューにて機能します。

 上記の Raycast メソッドや、Linecast メソッドといった、見えない光線を可視化するためのDebug機能です。
引数には、Raycasy メソッドや Linecast メソッドで設定した内容と同じ内容で設定を行うことで、
どの位置からどの方向に向かって、どの位の距離まで Ray が投射されているのかを確認することが出来ます。


 // Scene ビューにて Ray の可視化
  Debug.DrawRay(rb.position, lookDirection, Color.blue, 1.0f);


Scene ビュー画像




 キャラの中央から縦に青い線が見えると思います。これが Raycast メソッドの実行内容であり、それを可視化しています。
青い線がキャラの向いている方向に約 1 マス分( 1.0f )だけ投射されていることがわかります。
この部分が「Ray とぶつかる」位置として判定されます。そのため、この青い線とコライダーを持つゲームオブジェクトがぶつかる
その情報が hit 変数に戻り値として取得出来るようになっています。Debug.DrawLine メソッドは、それを可視化する処理です。

 このように処理を可視化することで、どのような処理が実行されているかを確認できます。
非常に重要なことですので、積極的に利用してデバッグをスムースにして捗るようにしましょう。

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


6.<LayerMask.GetMask メソッド>


 引数に指定した LayerMask の文字列を int 型の値に変換してくれるメソッドです。

  LayerMask.GetMask("NPC")

 今回の場合、NPC を引数に指定していますので、NPC を登録している Layer の番号である 8 の値が戻り値として取得出来ています。
これは、Physics.Raycast メソッドの第4引数の指定値が int 型で Layer を指定するように要求されているためで、それに情報を合わせるためです。

Layer



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


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


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

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

 // そのゲームオブジェクトにアタッチされている NonPlayerCharacter クラスが取得できた場合
  if (hit.collider.TryGetComponent(out NonPlayerCharacter npc)) {

 今回はこのような処理として利用しています。hit 変数の持つ collider 情報から NPC のゲームオブジェクト へとアクセスし、
NPC のゲームオブジェクトに対して TryGetComponent メソッドを実行しています。

 out 以降には、そのゲームオブジェクトから取得したい型と変数を宣言します。今回は、 NonPlayerCharacter 型npc 変数を用意しておきます。

 もしもこの TryGetComponent メソッドの処理結果が true であるならば、つまり、ゲームオブジェクトに NonPlayerCharacter スクリプトがアタッチされているのであれば、
out として用意した npc 変数に NonPlayerCharacter スクリプトの情報が代入されて、さらに、if 文内に処理が実行されます
また if 文内の間はこの npc 変数が使用できることになります。(スコープがif文ブロック内であるためです

 TryGetComponent メソッドの処理結果が false の場合には NonPlayerCharacter スクリプトの取得ができなかったため、npc 変数は null のままで、false が結果として戻り、
このif文内の処理は実行されないままで終了します

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

参考
Unity公式スクリプトリファレンス
Component.TryGetComponent
https://docs.unity3d.com/ScriptReference/Component...


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


 Action のボタンに割り当てられているキーを押してみてください。
Sceneビュー 上に、Ray が可視化されていれば Ray の制御は成功です。


<実装動画 Ray の可視化>
動画ファイルへのリンク



 この状態で、Game ビューに設置してある NPC のゲームオブジェクトに Ray が当たるようにキーを押してください。
確認すべき点が複数ありますので、順番に確認します。

 まずは、Console ビューに Debug.Log で設定した "会話ウインドウを開く" の文字列が表示されれば制御成功です。

 この確認ができたら、Player ゲームオブジェクトの PlayerController スクリプトの isTalking 変数も同じようにキー操作に合わせて切り替わっているかを確認しましょう。
この時点ではスイッチが入って true の状態になっているはずです。
この変数を元に、プレイヤーキャラの移動が制御されるようになっていますので、
会話ウインドウが開いてる状態のときにはプレイヤーキャラの移動が出来ないように制御されていれば、こちらも制御成功です。

 最後に、NPC ゲームオブジェクトのインスペクターを確認しながら、NonPlayerCharacter スクリプトの isTalking 変数のスイッチが入って true になっているかも一緒に確認します。
ここまでが会話ウインドウが開いたときに確認すべき項目になります。

 すべて問題がなければ、次の確認に進みます。



 会話ウインドウが開いている状態(isTalking 変数が true)のときに、もう一度、キーを押すと、
Console ビューに Debug.Log で設定した "会話ウインドウを閉じる" の文字列が表示されれば制御成功です。
この状態になると、プレイヤーキャラが再度移動できる状態になります。この処理がどの部分で制御されているかを、しっかりと把握しておいてください。

 NPC ゲームオブジェクトのインスペクターを確認しながら、NonPlayerCharacter スクリプトの isTalking 変数のスイッチが切り替わって false になっているかも一緒に確認します。


<実装動画◆Console ビューで動作を確認>
動画ファイルへのリンク



 デバッグを行う際に複数のインスペクターを確認したい場合には、インスペクターを複数個同時に表示しておくと便利です。

 インスペクタータブの上で右クリックをしてメニューを開き、Add Tab => Inspector を選択すると増やすことが出来ます。
インスペクター右上部に錠のアイコンがありますので、常に表示していたいゲームオブジェクトのインスペクターの内容にしてからこのアイコンを押すと
ヒエラルキーのゲームオブジェクトを切り替えてもインスペクター表示を選択しているゲームオブジェクトに固定することが出来ます。


右上の錠のアイコン インスペクターに表示するゲームオブジェクトを固定する機能



表示内容固定中



 例えば、NPC 用のゲームオブジェクトを選択した状態でインスペクターの錠のアイコンを押すと、
このインスペクターでは常に NPC 用のゲームオブジェクトの情報を表示します。



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

 次は 手順17 −会話イベント用のデータの作成−? です。

コメントをかく


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

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

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

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

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

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

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

レースゲーム(抜粋)

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

3D脱出ゲーム(抜粋)

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

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

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

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

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

VideoPlayer イベント連動の実装例

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

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

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

private



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

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