データとしてのウェーブ
CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 22/50。
レベルのウェーブはリストです。グラントが3体、次にブルートが2体、その後にボスが登場します。スポーナーのコードに記述すると、レベルごとに専用のコードが必要になります。データとして記述すれば、リストはアセットに格納され、レベルごとに1つのアセットを用意し、1つのスポーナースクリプトが渡されたアセットを読み込みます。各要素は[System.Serializable]クラスなので、アセットのインスペクターにリストが表示されます。
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Wave
{
public GameObject enemy;
public int count = 1;
public float spacing = 1f;
}
[CreateAssetMenu(menuName = "Game/Wave Set")]
public class WaveSet : ScriptableObject
{
public List<Wave> waves;
public float restBetweenWaves = 3f;
}これはすべて1つのファイル、WaveSet.csに記述します。ScriptableObjectにはクラス名と同じ名前のファイルが必要で、通常のWaveクラスはその隣に置けます。WaveSetアセットを選択すると、インスペクターにSizeとElement 0、Element 1の行があるWavesが表示され、それぞれにEnemy、Count、Spacingがあります。+ボタンでウェーブを追加できます。スポーナーはコルーチンでリストを順に処理します。
public class WaveSpawner : MonoBehaviour
{
public WaveSet waveSet;
void Start()
{
StartCoroutine(SendWaves());
}
IEnumerator SendWaves()
{
foreach (Wave wave in waveSet.waves)
{
for (int i = 0; i < wave.count; i++)
{
Instantiate(wave.enemy, transform.position, Quaternion.identity);
yield return new WaitForSeconds(wave.spacing);
}
yield return new WaitForSeconds(waveSet.restBetweenWaves);
}
Debug.Log("Last wave sent");
}
}Level1に、0.5秒間隔でグラントが3体、その後にブルートが2体設定されている場合、グラントは0秒、0.5秒、1秒に出現し、最後のグラントの後の間隔と3秒の休止時間が続き、最初のブルートは4.5秒に出現します。Level 2のスポーナーには、より難しいウェーブを設定したLevel2アセットを割り当てます。スクリプトはそのままです。
チャレンジ
中級ブロックレイン:ブロックがリズムに合わせて空から降ってくるので、矢印キーで避けます。Dropperは、lanes配列の各レーンに、常に1秒間隔でブロックを落とします。リズムをデータにして、どの曲もアセットにできるようにしましょう。
DropPattern.csで、[System.Serializable]を付けたクラスDropを記述します。そこには、publicフィールドlane(int型:-1は左、0は中央、1は右)とdelay(float型:このブロックを落とす前に待つ秒数)を持たせます。その下に、[CreateAssetMenu]を付けたScriptableObjectのDropPatternを記述し、publicフィールドblockPrefab(GameObject型)、laneWidth(float型)、drops(List<Drop>型)を持たせます。Dropperでは、2つのフィールドを、DropPattern型のpublicフィールドpatternに置き換えます。各ドロップを順番に処理し、そのdelayの時間だけ待ってから、Dropperの位置をx方向にlane×laneWidthだけ移動した場所に、パターンのブロックを落とします。最後のブロックを落とした後、Pattern doneをログに出力します。
プロジェクトには、レーン幅が2で、4つのドロップを持つSong1アセットがあります。Inspectorでは、これがDropperのpatternフィールドに設定されています。プレイを押して避けてから、チェックを押しましょう。
自分で試してみよう
using System.Collections.Generic;
using UnityEngine;
// Drop(1つのブロック:そのレーンと、ブロックが現れるまでの待ち時間)とDropPattern(アセット)をここに記述する
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。