Posted August 14, 2018 by Isometrik
[ 1. Overview ]
The first issue was figuring out the exact parameters required to spawn N of enemy type N at the start of wave N. The "endless" aspect means hard-coding each wave is out of the question (you would go insane after the first 100 waves) and so an algorithm was required to handle the calculations.
[ 2. Kill Threshold ]
This leads into the second issue. How do you determine when a wave is finished (the last enemy of that wave is dead) if the total number of enemies per wave uses procedural generation? Having succumbed to partial insanity after testing a few methods that didn't work, the final solution was a kill threshold. Although it's not possible to know how many will be spawned on a given wave, it is possible to take the algorithm's calculation, and then add it to a kill threshold counter. When the kill threshold is reached, a new wave is started and the threshold is increased based on the algorithm's spawn calculation.
KillThreshold = (KillThreshold + ((CurrentWave * Z) + (CurrentWave * N) + (Mathf.RoundToInt(CurrentWave / H))));
This is how it works: when a new wave starts, the previous kill threshold is added to the total amount of enemies to be spawned that particular round, and that becomes the new kill threshold. This threshold is checked against the total number of kills in order to trigger the next wave (and thus make it truly endless).
if(TotalKills == KillThreshold)
{
if(SwitchedToNextLevel == false)
{
SwitchedToNextLevel = true;
StartNewWave();
}
}
Here's a more detailed breakdown of the system when a new wave is started.
Increment the current wave by 1. This is used both for internal tracking, and to update the game UI.
CurrentWave += 1;
Update the UI for the player.
WaveCounterUI.text = "Wave " + CurrentWave;
Display a notification panel.
"Wave X" to the player at the start of a new round.
StartCoroutine(NewWaveNotification());
Set the new kill threshold required to trigger the next wave. Math.RoundToInt is specifically used to obtain a whole number due to the calculation being a division, rather than a multiplication... because you can't really spawn 50% of an enemy.
KillThreshold = (KillThreshold + ((CurrentWave * Z) + (CurrentWave * N) + (Mathf.RoundToInt(CurrentWave / H))));
Show a countdown timer to the player "wave starts in 10 seconds..."
StartCoroutine(NewWaveCountdownTimer());
Start the internal countdown that triggers a new wave. (This calls a function from one of the custom event managers used to manage various gameplay aspects).
StartCoroutine(NewWaveCountdown());
This is set to false after the new wave kicks in. This then allows a new wave to be triggered again when the new kill threshold is met.
SwitchedToNextLevel = false;