Spawning Objects in a Not-So-Infinite Loop
Automation is one of the fanciest advantages of programming cycles, but why automate an irrigation system to keep watering dirt where plants no longer live? This is a challenge in writing polished systems, particularly when working with spawn managers. In the 2D Space Shooter, a spawn manager is essential for instantiating waves of enemies non-stop… Actually, spawning them until the player is no longer able to play.
If a while loop has no way to exit the loop, many bugs may arise from such code. This example shows how code communication helps defining when a Spawn Manager should stop sending enemies to the player. In this case, when the player is dead, no more enemies should be spawned to optimize performance.
First, a look at the While loop working inside the Spawn Manager:
private bool _stopSpawning = false;
IEnumerator SpawnRoutine()
{
while (_stopSpawning == false)
{
Vector3 posToSpawn = new Vector3(Random.Range(-8f, 8f), 7, 0);
GameObject newEnemy = Instantiate(_enemyPrefab, posToSpawn, Quaternion.identity);
newEnemy.transform.parent = _enemyContainer.transform;
yield return new WaitForSeconds(5.0f);
}
}
public void OnPlayerDeath()
{
_stopSpawning = true;
}
the _stopSpawning bool serves as a key to cut the engine of the spawn manager. It starts set to false, and while it remains false, the SpawnRoutine will remain active, spawning enemies every 5 seconds.
This next snippet of code is inside the Player.cs, but called to take action from the Enemy.cs. Every time an enemy hits the player, the Enemy.cs calls the Player.cs’ void Damage(); when the player has taken enough damage to die, then the Player.cs tells the SpawnManager.cs to call the OnPlayerDeath() method, which then turns the _stopSpawning bool to true and the while loop exits the spawning cycle.
public void Damage()
{
_currentHealth -= 20;
if (_currentHealth < 1)
{
_spawnManager.OnPlayerDeath();
Destroy(this.gameObject);
}
}
Using public functions to make sure that the interaction between game objects actually took place is a great way to assert that all the code does not run from the same script, delegating tasks accordingly to the different game objects. The Enemy.cs should not destroy the player game object, because there are many enemies but one player; it is easier to regulate that behavior from inside the Player.cs. In the same way, the Spawn Manager should not stop spawning by itself, but when the Player tells it to. Code interdependence is a great mean to accomplish a clockwork behavior involving all the gears that run an experience.