Menu
CoddyTech

Waves as Data

Part of the Game Architecture in Unity section of Coddy's Unity journey. Lesson 22 of 50.

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 icon

Challenge

Medium

Block Rain: blocks fall from the sky to a rhythm, and you dodge them with the arrows. The Dropper drops a block into each lane of its lanes array, always 1 second apart. Turn the rhythm into data, so that every song can be an asset:

  • In DropPattern.cs, write a [System.Serializable] class Drop with the public fields lane (an int: -1 left, 0 middle, 1 right) and delay (a float: the seconds to wait before this drop). Below it, write DropPattern, a ScriptableObject with [CreateAssetMenu] and the public fields blockPrefab (a GameObject), laneWidth (a float) and drops (a List<Drop>).
  • In Dropper, replace both fields with a public field pattern of type DropPattern. For each drop in order, wait its delay, then drop the pattern's block at the Dropper's position moved lane times laneWidth along x. After the last drop, log Pattern done.

The project has a Song1 asset: lane width 2 and four drops, and the Inspector puts it in the Dropper's pattern field. Press Play and dodge, 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
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Game Architecture in Unity