i-school - 2Dタワーディフェンス 手順6
 この手順では、ゲームのベース部分である画面のタップ処理の制御について実装を行います。


<実装動画 画面をタップした際に配置可能な位置である場合には、そのタップした位置にキャラを生成する>
動画ファイルへのリンク


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

手順6 −タイルのタップ感知制御の実装−
 9.タップしたタイルの位置にキャラを生成する
10.タップした際に、配置可能なタイルの位置にのみキャラを生成する



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

 ・Vector3Int 構造体
 ・Camera.ScreenToWorldPoint メソッド
 ・GridLayout.WorldToCell メソッド
 ・Tilemap.GetColliderType メソッド



9.タップしたタイルの位置にキャラを生成する

1.設計


 Unity には画面のタップを感知するための専用メソッドがいくつか用意されています。
そのうちの1つである Camera クラスの管理する ScreenToWorldPoint メソッドは画面のスクリーン座標をワールド座標に変換することによって、
画面のタップした位置情報をゲーム内の位置情報へと変換してくれますので、こちらを利用します。

 今回利用するタイルマップはワールド座標ではなく、タイルマップ内のセル座標という座標体系によって管理されています。
そのため従来の画面のタップを感知するメソッドのみでは、タイルマップ内のタイルを特定することが出来ません

 そこで画面のタップを感知してワールド座標を取得したあとに、ワールド座標をタイルマップのセル座標に変換するメソッドを組み合わせて利用することによって、
画面のタップした位置をタイルマップ内の1つのタイルの地点と紐づけをして座標を指定できるように処理を考えます。

 セルの座標がわかれば、その地点に対して Instantiate メソッドを実行することで、キャラをタイルマップ上に生成することが可能になります。
 
 Unity に用意されている複数のメソッドとそのメソッドの戻り値を上手に活用することによって、今回のタップ処理が実装できることになります。
今後もこのように複合式なロジックや考え方が必要になりますので、しっかりと学習して活かしていきましょう。


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


 画面のタップを感知するためのスクリプトを作成します。
スクリプトを作成する前にはスクリプト専用のフォルダを用意し、その中で作成するようにしてファイル管理をしやすくします。

 Project フォルダの空いている場所で右クリック、あるいは + ボタンを押してメニューを開き、Create => Folder を選択します。
名前を Scripts に変更します。このフォルダ内で同じように再度メニューを開き、Create => C# Script を選択します。

 新しくスクリプト・ファイルが作成されますので、名前を CharaGenerator に変更します。
ダブルクリックすることで Visual Studio エディターが起動しますので、そちらにスクリプトを記述していきます。
 

CharaGenerator.cs

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


 スクリプトを作成したらセーブを行います。セーブは Ctrl + Shift + S キーです。


3.<Vector3Int 構造体>


 Vector3 構造体を int 型で表現するためのものです。通常の Vector3 型との違いは各項目が float 型ではなく、すべて int 型で管理されている部分です。

 今回のタイルマップでは座標情報がワールド座標ではなく、セル座標という体系で管理されています。
これは (3, 4) や(110, 44) のように、すべて整数の Vector3Int 構造体で座標が表現されます。
そのため、セル座標の情報をスクリプト内で扱う場合にも Vector3Int 構造体の情報を利用することで、セル座標を取得したり、利用したりすることが出来ます。

 通常のワールド座標は Vector3 構造体(float 型)、セル座標は Vector3Int 構造体(int 型)という風に、座標の管理している型を覚えてしまうといいでしょう。

Unity 公式スクリプトリファレンス
Vector3Int
https://docs.unity3d.com/ja/current/ScriptReferenc...


4.<Camera.ScreenToWorldPoint メソッド>


 引数で指定したスクリーン座標の情報をワールド座標に変換するメソッドです。

  // タップ(マウスクリック)の位置を取得してワールド座標に変換
  Camera.main.ScreenToWorldPoint(Input.mousePosition);

 タップした位置、あるいはマウスのポインタがあるスクリーン座標の情報(Input.mousePosition 変数)を引数に指定し、
その値を戻り値として Vector3 構造体のワールド座標に変換しています。

 今回はこの値を WorldToCell メソッドを利用して、さらにタイルマップのセル座標に変換しています。

 このメソッドは2Dでは問題なく動作しますが、3Dの場合には Z 軸の情報を考慮しないと正確な計算を行ってくれません。
スクリーン座標は2次元(Vector2 構造体)であるため、Vector3 構造体の値に変換した際、Z 軸には常に 0 になるためです。
こういったケースの場合には、 Z 軸に適切な値を代入して利用します。
またカメラの Projection の設定が2Dの場合には自動的に Orthographic になるのに対し、3Dの場合には Perspective になりますので、その辺りにも注意が必要になります。

Unity 公式スクリプトリファレンス
Camera.ScreenToWorldPoint
https://docs.unity3d.com/ja/current/ScriptReferenc...


5.<GridLayout.WorldToCell メソッド>


 引数に指定したワールド座標(Vector3 型)を、タイルマップ内の座標単位であるセル座標(Vector3Int 型) に変換するメソッドです。

  // タップ(マウスクリック)の位置を取得してワールド座標に変換し、それをさらにタイルのセル座標に変換
  gridPos = grid.WorldToCell(Camera.main.ScreenToWorldPoint(Input.mousePosition));

 今回の実装では、ScreenToWorldPoint メソッドの戻り値として Vector3 構造体の情報を取得して、それをワールド座標の値として引数に指定しています。
WorldToCell メソッドhではその引数の位置の結果をタイルマップ内にあるセル座標として Vector3Int 構造体の情報として変換して取得しています。

 このように座標の情報を変換していくことによって、画面のタップの位置情報をタイルマップ内のタイルの位置情報と紐づけて利用する処理になっています。
Unity 公式スクリプトリファレンス
Grid
https://docs.unity3d.com/ja/current/ScriptReferenc...
Unity 公式スクリプトリファレンス
GridLayout.WorldToCell
https://docs.unity3d.com/ja/current/ScriptReferenc...


6.CharaGenerator ゲームオブジェクトを作成し、CharaGenerator スクリプトをアタッチして設定をする


 ヒエラルキーの空いている場所で右クリックをしてメニューを開き、Create Empty を選択します。
新しい Transform コンポーネントのみがアタッチされているゲームオブジェクトが作成されますので、名前を CharaGenerator に変更します。


ヒエラルキー画像



 先ほど作成した CharaGenerator スクリプトをドラッグアンドドロップして CharaGenerator ゲームオブジェクトにアタッチします。
アタッチしたら必ず、ゲームオブジェクトを選択してインスペクターを確認して、正常にアタッチされているかを目視でチェックします。

 CharaGenerator スクリプトにはインスペクターよりアサインする情報が2つ表示されていますので、こちらを設定します。

 CharaPrefab 変数には、Prefabs フォルダにある Chara ゲームオブジェクトのプレファブをドラッグアンドドロップしてアサインします。

 Grid 変数には Grid_Base ゲームオブジェクトをドラッグアンドドロップしてアサインします。Grid コンポーネントが変数の情報として代入されます。


インスペクター画像



 以上で設定は完了です。


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


 セーブを行い、ゲームを実行して処理を確認しましょう。
どのような処理を記述し、どのような制御処理が動くのか、イメージを作ってから実行してください。

 画面をマウスでクリックしてください。その地点のタイル上にキャラが生成されれば制御成功です。


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

 
 続いては、タップした際の制御処理を追加します。


10.タップした際に、配置可能なタイルの位置にのみキャラを生成する

1.設計


 現在はすべてのタイルをタップで感知してしまうため、キャラがどこでも自由に配置できてしまいます。
このままですとタワーディフェンスゲームとしては成り立たなくなってしまうため、
タップした際に「配置可能なタイル」のみを選別し、その地点にのみキャラを生成する制御処理を実装します。
 
 配置可能なタイルの判定にはタイルの持つ情報の1つである ColliderType を利用します。
この情報が指定した情報と同じである場合に限り、「配置可能なタイル」として認識できるようにします。


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


 CharaGenerator スクリプトを修正して、タップの感知を行ったあとに、そのタップしたセル座標の ColliderType を確認して
指定されたタイプであるときのみ、キャラを生成するように制御を実装します。

 処理を記述する前に、自分でどのような制御が行えればキャラの配置の制御が可能になるのか、イメージを作ってみてから処理を修正しましょう
プログラムのロジックを組み立てる際には、処理のイメージを持つことがとても大切になります。
どんなときに、どうなってほしいのか、そのイメージを日本語化し、さらにプログラムとして言語化していくことが求められます。

 また前回用意しているキャラの生成処理についてはメソッド化しています。
事前に記述してあった処理をどのようにすればメソッド化できるのかも、合わせて学習していきましょう。


CharaGenerator.cs

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


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


3.<Tilemap.GetColliderType メソッド>


 引数に指定したセル座標(タイルマップの座標情報。Vector3Int 型)を渡すことで、そのセル座標にあるタイルの ColliderType を戻り値として取得します。
ColliderType は None、Sprite、Grid の3種類があります。

  // タップした位置のタイルのコライダーの情報を確認し、それが None であるなら
  if (tilemaps.GetColliderType(gridPos) == Tile.ColliderType.None) {

  }

 上記の例では、画面のタップした地点のセル座標を引数として、その座標のタイルの持つ ColliderType の情報を取得し、そのタイプが None である場合には
if 文の条件を満たして処理を行うように制御しています。

Unity 公式スクリプトリファレンス
TileMap
https://docs.unity3d.com/ScriptReference/Tilemaps....
Unity 公式スクリプトリファレンス
TileMap.GetColliderType
https://docs.unity3d.com/ScriptReference/Tilemaps....
コガネブログ 様
【Unity】タイルマップ - Tilemap クラスでよく使う関数
https://baba-s.hatenablog.com/entry/2018/04/08/131...


4.CharaGenerator ゲームオブジェクトの設定をする


 CharaGenerator スクリプトを修正したので、CharaGenerator スクリプトがアタッチされているゲームオブジェクトを選択してインスペクターを確認します。
アサインする情報が新しく1つ表示されていますので、こちらを順番に設定します。

 Tilemaps 変数には Grid_Walk ゲームオブジェクトの子オブジェクトの Tilemap ゲームオブジェクト をドラッグアンドドロップしてアサインします。

 アサインする対象のゲームオブジェクトを間違えないようしてください。
アサインすると、そのゲームオブジェクトにアタッチしている該当するコンポーネントの情報が自動的に変数に代入されます。


インスペクター画像



 以上で設定は完了です。


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


 セーブを行い、ゲームを実行して処理を確認しましょう。

 色々なタイルをタップしてみてください。
Grid_Base ゲームオブジェクト内のタイル(下地部分)のみに反応してキャラが生成されるようになれば、制御成功です。


<実装動画 画面をタップした際に配置可能な位置である場合には、そのタップした位置にキャラを生成する>
動画ファイルへのリンク




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

 次は 手順7 −敵キャラの作成と移動処理の実装− です。