i-school - パズルゲーム 発展16
 引き続き、ボム機能の制作をおこないます。

 この手順ではいままでの機能を統合し、ボムの生成と削除を行えるようにします。


<ボムの生成>
動画ファイルへのリンク


<ボム発動>
動画ファイルへのリンク



<新しく学習する内容>
 ・List<T>.AddRange(IEnumerable<T>) メソッド



GameManager スクリプトを修正する


 ボム用の変数を新しく3つ追加します。

 また、発展14にて干支を削除する処理をメソッド化してありますので、
そちらを活用するためのメソッドを新しく1つ作成します。

 ボムの機能は、効果範囲内にある干支をすべて削除する、という機能ですので、
Bomb スクリプトの方では効果範囲にあるすべての干支の情報を収集する処理を記述しています。
そのため、削除の処理まではありませんので、削除の部分については GameManager に依頼をする、という流れです。


GameManager.cs

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


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


<List<T>.AddRange(IEnumerable<T>) メソッド>


 List に用意されているメソッドです。

 Add メソッドでは要素を1つずつ List に追加することができますが、AddRange メソッドは引数に List を与えることで
与えた List の並びのまま、一括で追加を行ってくれます。List 内の追加される位置は、現在の要素の最後(末尾)の部分からです。

 List の統合とも言えます。

 // 複数の削除候補の干支を削除リストにまとめて追加
 eraseEtoList.AddRange(eraseEtos);
 
参考サイト
MicroSoft
List.AddRange メソッド
ゲーマーときどきエンジニア 様
【C#】リストにリストを追加するAddRangeメソッドを解説します


GameManager の設定を行う


 新しく変数を3つ追加していますので、そちらの設定を行います。


インスペクター画像



 最下段に追加されていますので、Bomb プレハブのアサインと、ボムの生成に必要な干支のチェーン数、ボムの範囲について設定します。


設定場所



 ツムツムのように7つ以上つなげてボムを生成したい場合には、BombGenerateCount 変数を 6 に設定してください。
これは最初の干支を抜かして、チェーンしている数です。つまり、ゲーム上7つ繋がっている、ということは最初の干支を抜かして、6つがチェーンしている、という解釈です。



Bomb スクリプトを修正する


 GameManager 側にメソッドの準備が整いましたので、TODO 部分を実装します。
また、テスト用に作成しておいた Start メソッドの処理はコメントアウトしておきます。


Bomb.cs

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



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


 すべての手順が完成しましたので、実際にゲームを実行して動作を確認します。

 ボムを生成するためには、指定した数の干支をつなげる必要があります。
この指定数を固定で設定しまうと、デバッグがやりにくく、調整する際にもソースコードを直接修正しなければなりません

 そういった事態を避けるため、今回の設計では GameManager に BombGenerateCount 変数を用意してあります。

 よって、デバッグする際には BombGenerateCount 変数の値を小さくすることで、干支をつなげる数が少なくてもボムが生成されます。
しっかりとソースコードを読み解いてみましょう。


<ボムの生成>
動画ファイルへのリンク


<ボム発動>
動画ファイルへのリンク

 
 以前の手順でもお伝えしているように、ゲームのデバッグは繰り返し行う前提です。
効率のよい作業をおこなうためにはどうすればいいのかを考えるようにしてみてください。



 ボムの範囲は GameManager の BombRadius 変数で設定できます。
例えば値を変更すれば、すべての干支を破壊するというボムも作れますし、
複数の種類のボムを作り、それぞれの効果範囲を変えるということもできます。


<すべての干支を削除>
動画ファイルへのリンク


 ソースコードの内容を読み解くことで応用したプログラムを作成できます。
チャレンジしてみてください。


<応用 LINQ を利用した処理のリファクタリング>


 正常にボムの動作することを確認できましたら、Bomb スクリプト内の OnClickBomb 内の処理を LINQ を利用して置き換えてみましょう。

 LINQ の各機能を活用すると、短縮した命令文ですっきりと書けるようになります。
リファクタリングになりますので、既存の処理を置き換えているだけですので、ゲームの見た目や、処理の結果は同じです。


<置き換える処理>
        List<Eto> eraseEtos = new List<Eto>();
        Collider2D[] colliders = Physics2D.OverlapCircleAll(transform.position, bombRadius);
        
        foreach (Collider2D collider in colliders)
        {
            if (collider.TryGetComponent(out Eto eto))
            {
                eraseEtos.Add(eto);
            }
        }

  ↓

<LINQ を利用してリファクタリング>
        List<Eto> eraseEtos = Physics2D.OverlapCircleAll(transform.position, bombRadius)
            .Select(collider => collider.GetComponent<Eto>())
            .Where(eto => eto != null)
            .ToList();

 LINQ の処理はメソッドチェーンを利用して作成されています。
そのため上記のように、ピリオドの位置で改行することで、各処理を分解して紐解いていくことが出来ます。

 各処理の説明をします。

 Physics2D.OverlapCircleAllは、指定した位置(transform.position)を中心として、指定した半径(bombRadius)内のオブジェクトのコライダーを取得します。
OverlapCircleAllメソッドは、指定した位置に重なっているすべてのコライダーを配列として返します。

 Selectメソッドは、配列内の各要素に対して指定した処理を実行し、結果の要素を新しいコレクションにマッピング(射影)します。
この場合、各colliderからGetComponent<Eto>()を呼び出して、Etoコンポーネントを取得します
GetComponent<Eto>()は、指定したコンポーネント(Eto)がアタッチされているかどうかを確認し、アタッチされている場合はそのコンポーネントを返します。

 Whereメソッドは、指定した条件(eto != null)に合致する要素のみをフィルタリングします。
この場合、etoがnullでない要素のみを残します。つまり、Etoコンポーネントがアタッチされている要素だけが残ります
つまり、Select メソッドによって GetComponent した際に、万が一 null の情報があった場合にはそれを除外し、要素の安全性を確保しています。

 ToListメソッドは、コレクションをListに変換します。
この場合、SelectおよびWhereで得られた要素をList<Eto>に変換します。

 以上のような流れにより、最終的に、指定した位置と半径内にあるコライダーを持つオブジェクトの中から、EtoコンポーネントがアタッチされているものだけがeraseEtosリストに追加されます。
リファクタリングする前の処理と同じ内容になります。