Building a 3D Tower Defense Game — Wave Spawner

Simon Pham
2 min readNov 5, 2023

--

In this article, we’ll be looking at creating a simple wave spawning system. The first thing I want to do is to create an empty GameObject called “GameManager” and create a C# script for it called “WaveSpawner”.

Wave Spawner

We need to get a reference to the enemy prefab, the spawn position, time between waves, wave count, and how many waves we need to spawn.

 [SerializeField] private GameObject _enemyPrefab;
[SerializeField] private GameObject _spawnPos;

[SerializeField] private float _timeBetweenWaves = 5f;
[SerializeField] private float _countdown = 2f;
private int _waveIndex = 0;
private int _maxWave = 5;

I want it to spawn only 5 waves. The first wave should be spawned after 2 seconds, and each subsequent wave should be spawned after 5 seconds. Since we need to execute the spawning after each interval, this would be good use case for a Coroutine.

void Update()
{
if (_countdown <= 0f)
{
StartCoroutine(SpawnWave());
_countdown = _timeBetweenWaves;
}
if (_waveIndex < _maxWave)
{
_countdown -= Time.deltaTime;
}
}

Now let’s create the logic for the SpawnWave fucntion.

IEnumerator SpawnWave()
{
_waveIndex++;
Instantiate(_enemyPrefab, _spawnPos.transform.position, Quaternion.identity);
yield return null;
}

So each time the SpawnWave function is executed, the _waveIndex variable is incremented by 1 and a new enemy will be spawned using the Instantiate method.

Wave UI

I also created a canvas GameObject for the UI, which will inform the player about the current wave they are on and display the countdown between waves.

Let’s create a C# script for the canvas.

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class GamePlayUI : MonoBehaviour
{
[SerializeField] TMP_Text _waveText;
[SerializeField] TMP_Text _timeText;
private int _maxWave = 5;

public void UpdateWaveText(int waveIndex)
{
_waveText.text = "Wave " + waveIndex + "/" + _maxWave;
}

public void UpdateTimeText(float time)
{
_timeText.text = "Incoming Wave In " + string.Format("{0:0.00}", time);
}
}

And here’s the full code for the Wave Spawner with the UI elements incorporated:

using UnityEngine;
using System.Collections;

public class WaveSpawner : MonoBehaviour
{
[SerializeField] private GameObject _enemyPrefab;
[SerializeField] private GameObject _spawnPos;

[SerializeField] private float _timeBetweenWaves = 5f;
[SerializeField] private float _countdown = 2f;
private int _waveIndex = 0;
private int _maxWave = 5;

[SerializeField] private GamePlayUI _gamePlayUI;

void Start()
{
_gamePlayUI.UpdateWaveText(_waveIndex + 1);
}

void Update()
{
if (_countdown <= 0f)
{
StartCoroutine(SpawnWave());
_countdown = _timeBetweenWaves;
}
if (_waveIndex < _maxWave)
{
_countdown -= Time.deltaTime;
_gamePlayUI.UpdateTimeText(_countdown);
}
}

IEnumerator SpawnWave()
{
_waveIndex++;
if (_waveIndex > 1)
{
_gamePlayUI.UpdateWaveText(_waveIndex);
}
Instantiate(_enemyPrefab, _spawnPos.transform.position, Quaternion.identity);
yield return null;
}

}

And here’s the result:

--

--

No responses yet