今回からは、「こうやったらより面白くなるんじゃないかな」というポイントをいくつか挙げて、自分流にアレンジしていくよ。具体的には以下の5つを実装していこうと思う。
11.敵の出現をWaveで管理する
12.射撃にリロードを設ける
13.敵に射撃がヒットした時、ノックバックする
14.武器変更と武器強化アイテムを出現させる
15.敵の個性を強くする
それぞれを実装する理由は各記事で解説していくよ。さっそく始めよう!
[追記]コンセプトの整理を忘れていたので次回の記事で、各項目の実装理由を整理しまする。
11.敵の出現をWaveで管理する
面白いゲームプレイには、だんだん上昇していく難易度と目標が不可欠だ。現状では敵の出現は散漫かつやむことがなく、自身が力尽きるまで悪夢が終わることはない。
出現する敵の種類、数を一つのWaveとしてパッケージングし、この問題に対処しよう。
実装概要
EnemyManagerスクリプトの書き換え
* SpawnメソッドにエネミーのPrefabを引数として渡すことで、アタッチするスクリプト1つで完結させる
* 実際にはWaveのさらに細かい概念を用意(便宜上Levelと呼ぶ)、各レベルごとにメソッドSpawnWaveW_L()で、スポーンするエネミーの数、種類を指定する
* 各Waveの開始時には、Wave開始を告げるUIを表示する
* 最終Waveの最終レベルで出現するエネミーを全部倒したらクリア画面に移行する
Spawnメソッドを書き換え、出現する敵をスクリプトで指定できるようにする
ずばりこうじゃ!
1 2 3 4 5 6 7 8 9 10 11 |
void Spawn(GameObject enemy) //Instantiateで生成するオブジェクトを引数にしてやる { if (playerHealth.currentHealth <= 0f) { return; } int spawnPointIndex = Random.Range(0, spawnPoints.Length); Instantiate(enemy, spawnPoints[spawnPointIndex].position, spawnPoints[0].rotation); } |
これで、各GameObjectに設定したPrefabのエネミーをスポーンさせることができる。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public GameObject zomBunny; public GameObject zomBear; public GameObject hellephant; //zomBunnyがInstantiateされる Spawn(zomBunny); //zomBearがInstantiateされる Spawn(zomBear); //hellephantがInstantiateされる Spawn(hellephant); |
Wave毎にメソッドを用意し出現する敵を決める
例えばWave1のLevel1で出現する敵を呼び出すメソッドはこうなる。
1 2 3 4 5 6 7 8 9 |
void SpawnWave1_1() { //Wave1-1 Zombunny*3 for(int i = 1; i <= 3; i++) { Spawn(zomBunny); } } |
超シンプルですね。
では、このメソッドの実行はどこから呼び出そうか?
そのアプローチが次。
Waveクリアを判定し次のWaveへ進む
これには、EnemyManagerクラスのみならずEnemyHealthクラスにも手を加える必要がある。
ざっくり言うと「Levelの初めにスポーンした敵を倒して残りが0体になったら、次のレベルのSpawnWaveメソッドを実行する」という実装です。
ちなみに、Wave1-1はStartメソッドからInvoke関数で実行してます。
まずはEnemyManagerクラスがコチラ。
※Levelと命名すべきところもWaveと命名して実装してしまってます。
実装時は”Wave1-1″でいいや~と思ってましたが、ブログにまとめる段になって”Wave1-1“を説明する言葉がないと不便なことに気づき急遽Levelと呼ぶことにしたためです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
//StartNextWaveでの判定に使う。Levelの通し番号 int numCurrentWave =1; //EnemyHealthクラスのDeathメソッド内で減少させる public static int numEnemy; private void Update() { //Levelクリア処理 //Level内でスポーンしたエネミーが残ってたら何もしない if(numEnemy > 0) { return; }else //numEnemyは0以下 { numCurrentWave++; StartNextWave(); } } void StartNextWave() { switch (numCurrentWave) { case 1: SpawnWave1_1(); break; case 2: SpawnWave1_2(); break; (中略) case 12: SpawnWave3_5(); break; } } void SpawnWave1_1() { //Wave1-1 Zombunny*3 for(int i = 1; i <= 3; i++) { Spawn(zomBunny); } //そのLevelでスポーンするエネミーの数。エネミーが死ぬたびに減少する。 numEnemy = 3; } |
そしてEnemyHealthクラスの調整がコチラ。
1 2 3 4 5 6 7 8 9 |
void Death () { (略) //Wave中に倒した敵のカウント用 //EnemyManagerの各Waveメソッドにて、次Waveの呼び出し条件に利用 EnemyManager.numEnemy--; } |
ここまでできれば機能の実装はほぼ終わったようなもの。
あとはWave開始を知らせるUIとクリア画面を作って表示するだけです。
Wave開始を知らせるUIのアニメ作成とその表示
チュートリアル内でゲームオーバー画面を作った時と同じ要領で、AnimationのClipを追加する。

HUDCanvas下にWaveTextを追加し、見た目を整える。設定はこんな感じ。
HUDCanvasのアニメータにWaveClipを追加して、WaveTextが左から登場して右に消えていくようアニメを作る。設定はこんな感じ。
ここで一瞬詰まったのが、テキストの位置を動かすときにPosition(Z)でなくAnchoredPositionをプロパティにしなければならないということ。(下記Reddit参考)
Animation on Rect Transform I can’t see position X & Y. What is position(Z)? Can I get the X & Y position on position(Z)? from Unity3D
理由を考えるに、画面サイズが変わった時にPositionで指定していると意図しない挙動になりそうだから、とかかしら。
アニメータのNewStateからWaveClipへのTransitionを引き、Waveトリガーを作成しくっつける。
WaveClipからNewStateへ戻るTransitionも忘れずに。こちらのTransitionはHasExitTimeにチェックをつけておこう。
各Wave最初のLevelのエネミースポーンメソッドに、SetTriggerを追記したらOK!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
GameObject hudCanvas; GameObject waveText; Animator canvasAnim; void Start () { (略) //Wave表示アニメ再生のトリガー取得準備 hudCanvas = GameObject.Find("HUDCanvas"); canvasAnim = hudCanvas.GetComponent<Animator>(); //Wave表示アニメのWave数指定準備 waveText = GameObject.Find("WaveText"); } void SpawnWave1_1() { //Wave1開始のUI表示 canvasAnim.SetTrigger("Wave"); waveText.GetComponent<Text>().text = "WAVE 1"; (略) } |
クリア画面のアニメ作成とその表示
こちらもWave表示とやることは同じ。

HUDCanvas下にClearTextを追加。

ClearClipを作成。
Animatorを設定。
Levelクリア処理に、「最終Levelをクリアした時」の条件分岐を追記。ついでにスペースキーでリトライもできるようにしておく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
private void Update() { //Waveクリア処理 if(numEnemy > 0) { return; }else if (isFinalWave == true)//最終LevelのSpawn時にこのフラグはOnになる { //クリアUI表示 canvasAnim.SetTrigger("Clear"); if (Input.GetButton("Jump")) { SceneManager.LoadScene(0); } }else //numEnemyは0以下だがisFinalWaveがOnでない { numCurrentWave++; StartNextWave(); } } //最終Level void SpawnWave3_5() { (略) isFinalWave = true; } |
これで実装は終わり!次は武器の残弾とリロードをやっていくぞ!
[追記]コンセプトの整理を忘れていたので、次回はそれを挟む。実装はそのあとから。
次回はコチラ
前回はコチラ
「Unity公式チュートリアルSurvival Shooter応用Chapter.11「敵の出現をWaveで管理する」」への2件のフィードバック