i-school - 2Dタップシューティングゲーム 発展12
 エネミーに攻撃方法を追加し、一定の間隔でバレットを発射してくるように処理を追加します。


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


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

発展12 −エネミー用のバレットの作成と自動生成処理の実装−
23.エネミー用のバレットを作成してプレファブにする
24.エネミーの種類に応じて、バレットを自動生成を行う処理を実装する



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

 ・エネミーとプレイヤーで同じスクリプトを利用する
 ・コルーチンメソッドを利用した while 文の実装例



23.エネミー用のバレットを作成してプレファブにする

1.設計


 エネミーの移動については一旦終了し、ここではエネミーからの攻撃を考えて実装します。

 現在は拠点に侵入してくることでエネミーの攻撃を表現していますが、ボスの場合、何も攻撃方法がありません。
そのため、エネミー側にもバレットを用意し、ボスと、一部のエネミーからは、バレットを発射して攻撃を行ってくるように設計します。

 新しく作成するバレットですが、すでにプレファブとして作成してあるプレイヤーのバレットを活用して作成していくようにします。
プレファブになっているゲームオブジェクトはアンパックという手順を行うことによって、プレファブではない、通常のゲームオブジェクトの状態に戻すことが可能です。

 この機能を利用し、プレイヤーのバレットをアンパックし、エネミー用のバレットを作成し、それをまた新しいプレファブにしましょう。
アンパックしても、プレイヤーのバレットのプレファブはそのまま残っているので心配ありません。


2.Canvas ゲームオブジェクトの子オブジェクトとして、Bullet プレファブを設置する


 Prefabs フォルダにある Bullet プレファブのゲームオブジェクトを、Canvas ゲームオブジェクトの子オブジェクトとして設置します。
対象のプレファブを Canvas の子オブジェクトとしてドラッグアンドドロップしてください。


ヒエラルキー画像



Sceneビュー画像



 続いて、プレファブをアンパックし、新しくエネミ―用のバレットとしての設定を行っていきましょう。


3.Bullet プレファブをアンパックして、名前を EnemyBullet に変更する


 Bullet プレファブの上で右クリックをしてメニューを開き、Prefab => Unpack Completly を選択してください。
これでプレファブではなくなり、通常のゲームオブジェクトに戻ります。
 ヒエラルキーの Bullet ゲームオブジェクトのアイコンの色と名前が青色ではなく、通常のゲームオブジェクトと同じになっていることを確認します。


ヒエラルキー画像



 Bullet ゲームオブジェクトの名前を EnemyBullet に変更してください。


ヒエラルキー画像



 最後に設定を行って、プレファブ化します。


4.EnemyBullet ゲームオブジェクトの設定を行い、プレファブにする


 Tag を Enemy に設定してください

 サイズやコライダーなどの設定はそのままで問題ありません。
 
 バレットの速度と攻撃力の値は、プレイヤーのバレットとは異なる値にします。
速度は少し低めにしておきましょう。下記のインスペクター画像を参考にしてください。


インスペクター画像



 設定が終了したら、EnemyBullet ゲームオブジェクトを Prefabs フォルダへドラッグアンドドロップしてプレファブにします
ヒエラルキーにある EnemyBullet ゲームオブジェクトは不要になりましたので削除してください


 以上でエネミー用のバレットの完成です。


24.エネミーの種類に応じて、バレットを自動生成を行う処理を実装する

1.設計


 バレット関連の実装は手順が非常に多い処理になりますので、少しずつ実装していくようにします。

<設計内容>
◇1.特定のエネミーが一定の間隔でバレットを自動生成し、エネミーから真っすぐ下方向へ発射する
 2.エネミーのバレットに接触した際に、拠点の耐久力を減算する処理を追加する
 3.エネミーのバレットの発射する方向を真っすぐ下方向から、プレイヤーのいる方向へ発射するように修正する
 4.バレットの親子関係を変更する

 この手順では、【◇1】の処理のロジックを考えて設計を行い、実装していきます。



 まずは最初に、このロジックを考えるにあたり、どのスクリプトを修正するのが適切であるかを考えます。
エネミーがバレットを生成する、という流れになりますので、今回は EnemyController スクリプトを修正することで設計を行います。

 特定のエネミーの指定ですが、これについては EnemyData クラスにある情報を利用することで参照する情報は色々考えられます。
後々に変更することを前提に、今回は移動方法が MoveType.Staraight のエネミーのみ、バレットを発射するエネミーと指定します。

 一定の間隔でバレットを自動生成、という処理ですが、こういった処理の多くは Update メソッドを利用する処理のイメージがすぐにわくと思います。
その手法でも問題ありませんが、現在は EnemyController スクリプトに Update メソッドは設計上ありません(追加は可能ですが、あえて設計上から外して使わないようにしています)ので、
Update メソッドは利用せずに、別の手法でこの処理を考えてみます。

 今回はコルーチンメソッドと while 文を組み合わせた処理を設計して、バレットを1回生成したら一定時間処理を中断し、
再開したら再度また1回バレット生成し、また一定時間処理を中断する、再開する、という処理の繰り返しのロジックで考えます。

 無事にバレットを生成することが出来ても、発射する方向が分からなければその場から動かない状態になってしまいますので、
まずは最初は、プレイヤーのバレットを発射する処理を実装したときと同じように、まずは、まっすぐ下方向へと発射するようにしてみましょう。
バレットの生成と発射までの処理はプレイヤーのバレットを発射する際の処理を参考にしてください。


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


 処理のイメージがつかめたら、記述する場所を考えて、処理を実装してみましょう。
なお、この EnemyController スクリプトは 発展11 の処理を実装した状態で追記していますので、
発展11 を実装していない場合には、自分の EnemyController スクリプトの処理を優先して、不要な処理を書いたりしないように気を付けてください。

 バレットを生成するために必要な変数や、プレファブからクローンの生成処理などはすでに学習済です。
先ほども解説しましたが、プレイヤーのバレットを発射する処理を参考にしてください。


EnemyController.cs


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



 Prefabs フォルダにある EnemySet プレファブ・ゲームオブジェクトのインスペクターを確認し、
新しく SerializeField 属性で宣言した変数が追加されていることを確認してください。


EnemySet ゲームオブジェクト インスペクター画像




3.<コルーチンメソッドを利用した while 文の実装例>


 while(ホワイル) 文は反復処理と呼ばれる処理です。条件を満たしている限り、繰り返し処理を行います。

 今回のケースでは条件が「true」です。この条件の指定の場合、無制限の繰り返し処理を行います。
そのため、この処理はゲーム実行中ずっと繰り返されて終わることのない処理になります。

    private IEnumerator EnemyShot() {

        // 条件に true を指定すると無制限のループ処理になる
        while (true) {
            // エネミーのバレットのクローンを生成し、Bullet スクリプトを取得して、ShotBullet メソッドを実行する
            Instantiate(enemyBulletPrefab, transform).GetComponent<Bullet>().ShotBullet(-transform.up);

      // 5秒間処理を中断する(待機する)
            yield return new WaitForSeconds(5.0f);
        }
    }

 while 文内の処理は2つあり、1つはバレットの生成と発射メソッドの実行処理です。
もう1つは yield による中断(待機・遅延)の処理です。 yield return new WaitForSeconds メソッドは引数でした秒数だけ処理を中断します。

 そのため、この while 文による繰り返しの処理は次のような挙動になります。

 1.エネミーのバレットをプレファブのクローンとして生成し、そのゲームオブジェクトにアタッチされている Bullet スクリプトを取得して、ShotBullet メソッドを実行する
 2.5秒待つ
 3.【1】の処理に戻る

 Update メソッドを利用していませんが、しっかりと一定の間隔でバレットを自動生成する処理を実装することが出来ました。

 なお、while 文ではとくに今回のような無制限の繰り返し処理を実装する場合、処理を中断する処理を挟まないと
すごい数のエネミーのバレットを生成する処理が実行されて、Unity のエディターが動かなくなります
こうなってしまうと再起動するしかなくなりますので、while 文は特に気を付けて作業してください


参考サイト
未確認飛行 C 様
反復処理
https://ufcpp.net/study/csharp/st_loop.html


 他にも自動生成の処理は考えられます。色々な処理を試しておくことで処理の引き出しが広がり、
より多くの処理を実装できるようになりますので、いつも使っている処理だけではなく、新しい技術も取り入れていきましょう。


4.EnemySet プレファブ・ゲームオブジェクトの設定を行う


 Prefabs フォルダにある EnemySet プレファブ・ゲームオブジェクトのインスペクターの一番上にある Open Prefab を選択してプレファブの編集モードに切り替えます。
新しく追加されている変数へ対象となる情報をドラッグアンドドロップしてアサインしてください。


EnemySet ゲームオブジェクト インスペクター画像



 以上で設定は完了です。


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


 すべての実装が完了しました。ゲームを実行して、想定している挙動になっているかを確認していきます。

 MoveType が Straight に設定されているエネミーが、自分の位置から下方向(拠点方向)に向けてバレットを生成し、発射すれば制御成功です。
その後、一定の間隔でバレットを自動生成すれば while 文による繰り返し処理も制御出来ています。

 万が一、バレットを自動生成しなかったり、Untiy エディターが動かなくなってしまった場合には
while 文のエラーになりますので、Unity を再起動し、修正を行ってからゲームを起動してください。
修正せずに起動すると、またエディターが動かなくなりますので注意しましょう。
  

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


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

 次は 発展13 ーバレット関連の追加処理の実装− です。