i-school - 2Dタワーディフェンス 発展4
 前回に引き続き、配置したキャラの解除の選択が行えるポップアップ機能の実装を行います。


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


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

発展4 −配置したキャラの解除機能を実装する−
 7.UIManager スクリプトと GameManager スクリプトを修正し、配置されているキャラをタップした際にポップアップが開く処理を追加する
 8.Chara ゲームオブジェクトを修正し、EventTrigger コンポーネントを利用してタップを感知し、登録されたメソッドを実行する機能を追加する


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

 ・EventTrigger コンポーネント
 ・Physics 2D Raycaster コンポーネント



7.UIManager スクリプトと GameManager スクリプトを修正し、配置されているキャラをタップした際にポップアップが開く処理を追加する

1.設計


 配置されたキャラをタップ(クリック)した際の処理の流れをロジック化して設計します。

 配置の解除確認用のポップアップはプレファブの状態になっていますので、タップされたら、それをいずれかのクラスから生成する必要があります。
ポップアップは Canvas ゲームオブジェクトの子オブジェクトとして作成をしていますので、UI の1つであると考えるならば、
生成する機能については、UI 関連の処理を管理している UIManager クラスに任せることが考えられます。

 処理に必要な情報としては、ポップアップのプレファブを登録するための変数と、生成する位置の情報の変数です。
生成する位置は Canvas ゲームオブジェクトの子オブジェクトになるようにしたいので、Transform 型で変数を宣言しておくと親子関係が作れます。

 タップした際には CharaController クラスに用意するメソッドを EventTrigger コンポーネントに登録して実行するようにします。
ただし、CharaController クラスには、UIManager クラスの情報がありません。代わりに GameManager クラスの情報は変数で管理しています。
GameManager クラスには UIManager クラスの情報が変数で管理されていますので、関節的に GameManager クラスに対してアクセスし、そこから UIManager につないでもらうようにします。

 次のようなロジックです。

 1.UIManager クラスにポップアップの生成を行うメソッドを準備する
 2.GameManager クラスに、UIManager に用意した【1】のメソッドを実行するためのメソッドを準備する
 3.CharaController クラスに、GameManager に用意した【2】のメソッドを実行するためのメソッドを準備する

 処理の順番は、3→2→1 の順番になります。
 キャラをタップしたら、CharaController クラスのメソッドを実行し、その中で GameManager クラスにある新しいメソッドを実行します。(3→2)
その後、GameManager クラスのメソッドが実行されて、UIManager クラスにあるポップアップの生成を行うメソッドを実行します(2→1)

 このようなロジックにすることによって、CharaController クラス自体は UIManager クラスを知らない(変数として情報を保持していない)ものの、
UIManager クラスを知っている(変数として情報を管理している) GameManager クラスへアクセスし、仲介してもらうことで UIManager クラスのメソッドを間接的に実行できるようになります。


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


 ポップアップの生成と設定を行うための処理をまとめてメソッドとし、その処理に必要な情報を変数として宣言を追加します。


UIManager.cs

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

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


3.UIManager ゲームオブジェクトの設定を行う


 CanvasTran 変数には Canvas ゲームオブジェクトをアサインしてください。
この位置にポップアップを生成するように制御するためです。


インスペクター画像



 以上で設定は完了です。


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


 CharaController クラスと UIManager クラスへの仲介役として機能を持たせるために、新しいメソッドを1つ追加します。

 CharaController クラスはこのメソッドを実行することによって、GameManager クラスにあるメソッドが実行されて
その中で UIManager クラスのポップアップの生成を行うメソッドを実行することにより、処理の流れをつながています。

 この仲介する役割を持つ処理を設計するためには、各クラスには、外部のクラスの情報がいくつ管理されているかを正確に把握しておく必要があります。

 CharaController クラスには GameManager クラスの情報は変数として管理されていますが、UIManager クラスの情報はありません。
ではこのときにどのようにすれば処理がつながっていくのかを、考えていくようにします。
新しく UIManager クラスの情報を取得して変数で管理できるようにするのがいいのか、あるいは、他に処理をつなげていく方法はないのか、という風にです。

 このときに GameManager クラスには UIManager クラスの情報がある、ということを把握していれば、新しく UIManager クラスの情報を CharaController クラスに用意しなくても
別の方法で処理をつなげていく、という発想・設計が可能になります。

 GameManager クラスは CharaController 型の List を管理しているため、配置を解除したキャラの破壊と、キャラの情報を削除する必要もあります。
そのため、ポップアップが閉じる際に、配置したキャラを解除することを選択している場合には、ポップアップが閉じるのに合わせて、List からキャラを削除する処理も必要になります。

 キャラの破壊処理と List から削除する処理はすでにメソッド化してあるため、ポップアップ側から呼び出すための処理を新しくメソッドを用意しておいて、対応できるようにしています。


GameManager.cs


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

 ここまでで、ポップアップを生成する処理と、キャラの配置を解除する処理が実装できました。
次の手順では、CharaController スクリプトの修正と、2Dオブジェクトのタップ(クリック)の感知とを行い、この機能を完成させていきます。


8.CharaController スクリプトと Chara ゲームオブジェクトを修正し、EventTrigger コンポーネントを利用してタップを感知し、登録されたメソッドを実行する機能を追加する

1.設計


 Canvas 内に設置するボタンとは異なり、2Dのゲーム内に存在するゲームオブジェクトには Button コンポーネントをアタッチしても動きません。
そのため、Unity の持つ EventSystem の機能を活用し、2Dのゲームオブジェクトにクリックやタップを感知させる機能を実装します。

 これには、EventSystem のほかに、EventTrigger コンポーネントとコライダー、そして Physics 2D Raycaster コンポーネントを利用します。
このうち、EventSystem は Canvas ゲームオブジェクトを作成していれば、自動的にヒエラルキーに作成されています。


<2Dオブジェクトのタップ環境を作るための設定>
 1.ヒエラルキーに EventSystem コンポーネントがアタッチされている EventSystem ゲームオブジェクトを用意する
 2.タップ感知させたい2Dのゲームオブジェクト(今回は Chara ゲームオブジェクト)に EventTrigger コンポーネントとコライダーを追加する
 3.カメラのゲームオブジェクトに Physics 2D Raycaster コンポーネントを追加する


ヒエラルキー画像



 EventSystem 以外の機能について順番に実装を行っていきますので、手順を覚えておいてください。


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


 CharaController スクリプトの修正して、EventTrigger コンポーネントに登録するためのメソッドを作成します。
メソッド内では GameManager クラスに新しく用意したメソッドを実行して、UIManager クラスのポップアップを生成する処理につなげてもらいます。


CharaController.cs

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


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


3.Chara ゲームオブジェクトに EventTrigger コンポーネントを追加する


 Prefabs フォルダにある Chara ゲームオブジェクトを選択して、インスペクターの一番上にある Open Prefab ボタンを押して、プレファブ編集モードへ切り替えます。

 再度、Chara ゲームオブジェクトを選択してインスペクターの一番下にある Add Component ボタンを押し、
EventTrigger コンポーネントを追加します。

 このコンポーネントには、イベントという形式で、public 修飾子のメソッドを事前に登録しておくことができます。
 イベントにはたくさんの種類があり、それぞれにイベントには実行されるタイミングが設定されています。
そのため、自分が実行してほしいタイミングに合わせたイベントを設定し、そこにメソッドを登録しておくことで指定のタイミングでメソッドを実行することが出きます。

Unity 公式スクリプト・リファレンス
EventSystems.EventTrigger
https://docs.unity3d.com/ja/2018.4/ScriptReference...



 追加した EventTrigger コンポーネント内にある Add New Event Type を押して、その中から Pointer Down を選択してください

 PointerDown のイベントは「マウスの左クリックをした時か、画面をタップした時」に、登録したメソッドが実行されるイベントです。
ここに、CharaController スクリプトに先ほど追加した OnClickChara メソッドを登録しておきます。


インスペクター画像



 以上でこの部分の設定は完了です。



 注意点があります。

 EventTrigger は、適用しているゲームオブジェクトに子オブジェクトがある場合、
レイヤーの設定により、その子オブジェクトのコライダーに対しても反応します。

 今回の場合、Chara ゲームオブジェクトの子オブジェクトとして AttackAreaRange ゲームオブジェクトがあり、このゲームオブジェクトにもコライダーがアタッチされています。
そのため、AttackAreaRange ゲームオブジェクトのレイヤーが Chara の場合、EventTrigger が反応してしまい、不具合の原因となります。

 EventTrigger による反応を Chara ゲームオブジェクトのコライダーだけにするには、
AttackAreaRange ゲームオブジェクトのレイヤーを Default に設定してください。

 Chara ゲームオブジェクトのレイヤーを設定する際に「親子含めてレイヤーを変更する」を選択していると、
AttackAreaRange ゲームオブジェクトのレイヤーも Chara になっている可能性が高いです。見直しておくとよいでしょう。


インスペクター画像




 EventTrigger コンポーネントについては詳細な記事が多くありますので、調べてみてください。


参照サイト
TECH PROjin 様
【Unity】Event Triggerの種類と用途と使い方【保存版】
https://tech.pjin.jp/blog/2017/09/03/unity_event-t...


4.Chara ゲームオブジェクトに BoxCollider2D コンポーネントを追加する


 2Dオブジェクトの Sprite がタップを感知するようにするために、Chara ゲームオブジェクトにコライダーをアタッチします。
どの形状のコライダーでも構いませんが、BoxCollider2D コンポーネントが適していると思います。

 コライダーのサイズがタップやクリックを感知するサイズになりますので、キャラの大きさに合わせて設定してください。

Scene ビュー画像



インスペクター画像


 以上で設定は完了です。
これでキャラのゲームオブジェクトがタップやクリックに反応するための準備が整いました。

 あとはタップやクリックを感知するための環境を準備します。EventSystem はすでにヒエラルキーにありますので、カメラの設定を行います。


5.Main Camera ゲームオブジェクトに Physics 2D Raycaster コンポーネントを追加する


 ヒエラルキーにある Main Camera ゲームオブジェクトを選択して、インスペクターの一番下にある Add Component を選択して、
Physics 2D Raycaster コンポーネントを追加してください。

Unity 公式マニュアル
Physics2DRaycaster
https://docs.unity3d.com/ja/2019.4/Manual/script-P...


 このコンポーネントをアタッチすることにより、Ray を利用して2Dのゲームオブジェクトにクリックやタップを感知します
このコンポーネントは、カメラのゲームオブジェクトにアタッチすることで機能を有効化します。

 ただし、初期設定のままですと2Dゲームオブジェクトをすべて感知するようになってしまうため、今回は指定した種類の Layer のゲームオブジェクトのみを感知の対象に設定します。

 これは Physics 2D Raycaster コンポーネント内にある Event Mask で設定を行います。
こちらの設定を Chara に変更してください。


インスペクター画像



 以上で設定は完了です。


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


 ゲームを実行してキャラを配置します。
その後、キャラをタップ(クリック)してください。EventTrigger が機能すれば、ポップアップが生成されます。
その際には、ゲームの進行状態も Play ではない状態であるため、カレンシーの加算、敵の生成、敵の移動、味方キャラの攻撃の処理が一時停止するかを確認してください。

 まずは、解除せずにポップアップを閉じてください。ゲームの進行状態が Play に戻って、各処理が再開されれば制御成功です。

 もう一度、キャラをタップしてポップアップを開き、今度は、配置解除を選択してください。
ゲーム画面からキャラが破棄されていなくなれば制御成功です。GameManager ゲームオブジェクトのインスペクターも確認し、
キャラの List から配置されていたキャラの情報が削除されていることも確認しておきます。

 最後に、キャラを配置できる上限値まで配置してください。その後、キャラの配置を解除します。
配置の上限値に空きが出ますので、他のキャラの配置が可能になっていれば、こちらも制御成功です。

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


 確認する部分が多いですが、それだけ処理が複雑になっていますので、チェック漏れがないように
事前にどの部分を確認するのかをイメージしておいて進めることが大切です。そうすることで不具合に気づくことが出来ます。


<ケーススタディ ー配置しているキャラをタップした際に、配置用のポップアップが表示されてしまう場合ー>


 正常に動作している場合、ゲーム内に配置したキャラをタップすると、配置解除用のポップアップが表示されます。

 Console ビューにエラーの表示されない不具合の1つとして、配置しているキャラをタップしたのに配置用のポップアップが表示されてしまうことがあります。

 この原因は、ヒエラルキーに配置用のポップアップが2つ存在している時です。
配置用のポップアップをプレハブにした際、再利用のためヒエラルキーに残しておきました。
ただし、この手順までにはすでにそちらも削除済のはずです。

 2つの配置用のポップアップが存在していると誤作動を起こすため、このエラーが発生します。

 ゲームを停止して、ヒエラルキーに配置用のポップアップが最初から置かれていないか(削除し忘れて、残っていないか)を確認してください。
もしも残っている場合には削除してください。



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

 次は 発展5 −エネミーのアニメーションの自動設定機能の実装− です。