I’m creating a Tower Defense game, and thus need a Wave Spawner script, I’m still inexperienced in Unity, and c#. I made this script, which allows me to control the flow of the wave 100% however I recognize that this potentially isn’t the best way to do things, I tried my best to comment it to help anyone willing to help me, understand the code better, I’d really appreciate any type of input.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class EnemyStructure
{
//Enemy clusters
[HideInInspector] public string Name;
[Header("Required")]
public GameObject enemyType;
public int amount = 1;
public float timeToNextEnemy;
[Header("MultiEnemy")]
public float multiEnemySpacing;
public bool ignoreSpacingTime;
}
[System.Serializable]
public class Waves
{
//Waves holding the enemy clusters
[HideInInspector] public string Name;
public EnemyStructure[] enemiesInWave;
}
public class WaveSpawner : MonoBehaviour
{
[Header("References")]
[SerializeField] Transform enemyHolder;
[Header("Properties")]
[SerializeField] float waveCooldownTime;
[SerializeField] bool autoStartWaves;
[Header("Waves")]
[SerializeField] int currentWave;
[SerializeField] bool spawning;
[SerializeField] Waves[] totalWaves;
List<bool> waitQueue = new List<bool>();
int waitQueueIndex;
float waveCountdown;
Transform spawnPoint;
private void OnValidate()
{
LableArrays();
}
void LableArrays()
{
//Loops through all Waves and Enemies In Waves, and lables them in the Inspector
for (int i = 0; i < totalWaves.Length; i++)
{
totalWaves[i].Name = "Wave " + (i + 1);
for (int x = 0; x < totalWaves[i].enemiesInWave.Length; x++)
{
totalWaves[i].enemiesInWave[x].Name = "Enemy(ies) " + (x + 1);
}
}
}
void Start()
{
//Start function, what do you expect? We are setting variables
spawning = false;
waveCountdown = waveCooldownTime;
currentWave = 0;
spawnPoint = Waypoints.waypointsStatic[0];
waitQueueIndex = -1;
}
void Update()
{
//If no enemies exist in the map, and the spawner is done spawning
if(!spawning && enemyHolder.childCount == 0)
{
//If waves start automatically, countdown, then start wave
if (autoStartWaves)
{
waveCountdown -= Time.deltaTime;
if (waveCountdown <= 0)
{
TryStartNextWave();
}
}
}
//Start next wave if we press "P"
if (Input.GetKeyUp(KeyCode.P))
{
TryStartNextWave();
}
}
IEnumerator SpawnWave()
{
//Setting variables we need
int waveIndex = currentWave;
spawning = true;
waveCountdown = waveCooldownTime;
//Here as well
bool clusterWait = false;
waitQueueIndex++;
int queueNumber = waitQueueIndex;
waitQueue.Add(clusterWait);
//Loop through as many enemies/enemy clusters there are in the wave
for (int i = 0; i < totalWaves[waveIndex-1].enemiesInWave.Length; i++)
{
//List of bools to act as local variables for whether or not to
//wait for enemy clusters to spawn
clusterWait = !totalWaves[waveIndex - 1].enemiesInWave[i].ignoreSpacingTime;
waitQueue[queueNumber] = clusterWait;
//Spawn in the enemy(ies) in the cluster
StartCoroutine(EnemyCluster(waveIndex, i, clusterWait, queueNumber));
//Wait if we want all enemies to spawn in the current cluster before the next cluster
while (waitQueue[queueNumber])
{
yield return null;
}
//Wait for the time to next enemy cluster
float timeToNextEnemyCluster = totalWaves[waveIndex - 1].enemiesInWave[i].timeToNextEnemy;
if (timeToNextEnemyCluster > 0)
{
yield return new WaitForSeconds(timeToNextEnemyCluster);
}
}
//Tell game we're done spawning in enemies for this wave
if(currentWave == waveIndex)
{
spawning = false;
}
}
IEnumerator EnemyCluster(int waveIndex, int spawnSpot, bool resetWait, int queueNumber)
{
//Loop through all enemies to spawn in the enemy cluster
for (int x = 0; x < totalWaves[waveIndex - 1].enemiesInWave[spawnSpot].amount; x++)
{
//Spawn in an enemy
SpawnEnemy(totalWaves[waveIndex - 1].enemiesInWave[spawnSpot].enemyType);
//If enemy spacing exists, wait
float spacingTime = totalWaves[waveIndex - 1].enemiesInWave[spawnSpot].multiEnemySpacing;
if (spacingTime > 0)
{
yield return new WaitForSeconds(spacingTime);
}
}
//If we decided to wait for all enemies in cluster to spawn before the next one, reset the queue
if (resetWait)
{
waitQueue[queueNumber] = false;
}
}
void SpawnEnemy(GameObject enemy)
{
//Creates enemy at spawnpoint
GameObject spawnedEnemy = Instantiate(enemy, spawnPoint.position, Quaternion.identity);
//Set enemies parent to the enemy holder for tracking
spawnedEnemy.transform.SetParent(enemyHolder);
}
public void TryStartNextWave()
{
//Increment wave number and start next wave
if (currentWave < totalWaves.Length)
{
currentWave++;
StartCoroutine(SpawnWave());
}
else
{
Win();
}
}
void Win()
{
print("Player Won!");
}
}