Waves as Data
Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 27 of 64.
A level's waves are a list: three grunts, then two brutes, then a boss. Written in a spawner's code, every level needs its own code. Written as data, the list goes into an asset, one asset per level, and one spawner script reads whichever asset it is given. Each entry is a [System.Serializable] class, so the asset's Inspector shows the list:
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;
}This is all one file, WaveSet.cs: the ScriptableObject needs a file of its own name, and the plain Wave class can sit beside it. Select a WaveSet asset and the Inspector shows Waves with its Size and the rows Element 0, Element 1, each with Enemy, Count and Spacing; the + button adds a wave. The spawner walks the list in a coroutine:
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");
}
}With Level1 holding 3 grunts 0.5 seconds apart and then 2 brutes, the grunts come at 0, 0.5 and 1 second, the spacing after the last grunt and the 3 second rest follow, and the first brute comes at 4.5 seconds. Level 2's spawner gets a Level2 asset with harder waves, and the script stays the same.
Challenge
MediumTurn the Dropper's rhythm into a song asset.
- In
DropPattern.cs, write a[System.Serializable]classDropwith publicint laneandfloat delay. - Below it, write
DropPattern : ScriptableObjectwith[CreateAssetMenu]and publicGameObject blockPrefab,float laneWidth,List<Drop> drops. - In
Dropper, usepublic DropPattern pattern;: per drop, waitdrop.delay, then drop the block moveddrop.lane * pattern.laneWidthalong x.
Press Play: four blocks fall. Then Check.
Try it yourself
using System.Collections.Generic;
using UnityEngine;
// Drop (one block: its lane and the wait before it) and DropPattern (the asset) go here
All lessons in Game Architecture in Unity
1Components, Not Hierarchies
Small ComponentsA Base Enemy ScriptAbstract ComponentsComponents Working TogetherRecap: Modular TurretRecap: Twin Cannon4Serialized Data
Serializable ClassesLists in the InspectorEnums in the InspectorRecap: Loot TableRecap: Roll the Loot2Interfaces in Unity
IDamageableInterfaces and TryGetComponentGetComponentsRecap: Interact KeyRecap: Nearest in Reach5ScriptableObjects
Data AssetsWeapon StatsShared SettingsSave the WindWaves as DataRecap: Item DatabaseRecap: Buy from the ShopPractice on your own: Unity playground