Skip to content

Instantly share code, notes, and snippets.

@fiskefyren
Created October 11, 2015 21:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fiskefyren/165230f20f6d19c1619d to your computer and use it in GitHub Desktop.
Save fiskefyren/165230f20f6d19c1619d to your computer and use it in GitHub Desktop.
using UnityEngine;
using System.Collections;
public class WaveSpawner : MonoBehaviour {
public enum SpawnState { SPAWNING, WAITING, COUNTING };
[System.Serializable]
public class Wave {
public string name;//name of the wave
public Transform enemy;//reference to prefab
public int count;//the amount of enemies for a wave
public float rate;//the spawn rate, the higher the number the faster they spawn
}
public Wave[] waves;
private int nextWave = 0;//stores the index of the next coming wave
public Transform[] spawnPoints;//the enemies spawn from these points
public float timeBetweenWaves = 5f;//stores the time between waves in seconds
private float waveCountdown;//?
private float searchCountdown = 1f;//this is used for our EnemyIsAlive checker method, so that it updates for every second rather than every frame
private SpawnState state = SpawnState.COUNTING;
void Start() {
if (spawnPoints.Length == 0) {
Debug.LogError("No spawn points referenced.");
}
waveCountdown = timeBetweenWaves;//which is currently 5 seconds
}
void Update () {
//killing off the entire wave before a new one spawns
if (state==SpawnState.WAITING) {
//check if enemies are still alive
if (!EnemyIsAlive()) {//this will check if we've any enemies in the screen, FYI !EnemyIsAlive() is the same as EnemyIsAlive()==false
//begin a new round
WaveCompleted();
return;
}
else {//if we still have enemies alive then we want to return
return;
}
}
if(waveCountdown <= 0) {
if (state != SpawnState.SPAWNING) {
//start spawning wave
StartCoroutine(SpawnWave(waves[nextWave]));
}
}
else {
waveCountdown -= Time.deltaTime;//makes sure that the countdown timer stays relevant to time rather than to frames drawn/second, which is currently going to count down from 5
}
}
void WaveCompleted() { //being new round
Debug.Log("Wave completed");
state = SpawnState.COUNTING;//counting down
waveCountdown = timeBetweenWaves;
if (nextWave + 1 > waves.Length - 1) { //current wave + 1 = next wave, waves.Lenght is the number of waves
nextWave = 0;//it'll go back and spawn the first wave again
//here would be the ideal place to put a finish screen e.g. "Yay! You've finished the game!" or increase the stats of the enemies
Debug.Log("Completed all waves! Looping...");
}
else {
nextWave++;//if you haven't reached the final wave and completed it yet, then this will just continue you to the next level
}
}
//this is very resource demanding, so rather than updating for every frame it should only be updated every second
bool EnemyIsAlive () {
searchCountdown -= Time.deltaTime;
if (searchCountdown <= 0f) {//if searchCountdown is less or equal to 0 seconds then it will run the next if statement below
searchCountdown = 1f;//when our countdown reaches 0 and enemies are still alive then we want the countdown to check again in one second
if (GameObject.FindGameObjectsWithTag("Enemy") == null) {//returns an array of all enemies/gameobjects with this game tag
return false;//meaning that no enemies are alive, so if that's the case then the next wave WILL spawn
}
}
return true;//meaning that some enemies are alive, so if that's the case then the next wave WON'T spawn
}
IEnumerator SpawnWave(Wave _wave) {//waits a certain amount of seconds inside of the method, which is why we're using IEnumerator rather than a void
Debug.Log("Spawning Wave: "+ _wave.name);
state = SpawnState.SPAWNING;
//spawn
for (int i = 0; i < _wave.count; i++) {//will run the amount of enemies we want to spawn
//spawn an enemy
SpawnEnemy(_wave.enemy);
yield return new WaitForSeconds(1f / _wave.rate);//waits a certain amount of seconds before looping again and spawning a new enemy, this is why we're using IEnumerator
}
state = SpawnState.WAITING;//?
yield break;//will return nothing, always use this when dealing with IEnumerator
}
//remember to go to prefabs and tag the enemy as "Enemy" in the inspector for all the enemies you want to be spawning
void SpawnEnemy (Transform _enemy) {
Debug.Log("Spawning Enemy: " + _enemy.name);
Transform _sp = spawnPoints[Random.Range(0,spawnPoints.Length)];//?
//enemy spawn point
Instantiate(_enemy, _sp.position, _sp.rotation);
//Instantiate(_enemy, transform.position, transform.rotation);//spawn point location //you can also use Vector3 if you like
}
}
/*
after finishing the code:
create an empty gameobject in Unity -> name it EnemySpawnPoint -> give it an icon so it's easier to see -> make it into a prefab ->
then you can make multiple spawn points if you desire (the Random.Range at line 110 should make enemies spawn from one of the spawn points randomly) ->
drag all of the spawn points into the spawn points elements where the C# Script has been added to -> hit apply and you should be done!
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment