I’ve noticed that in my HandleWinCondition method it gets all of the AttackerSpawner objects and calls StopSpawn on them, this then changes the bool spawn from true to false.
However if this happens whilst the while loop is being processed then Spawn will still get called and you’ll end up with one more enemy from each of your attacker spawners.
Here’s the code that I hope shows this and my little fix
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class AttackerSpawner : MonoBehaviour
{
private bool spawn = true;
[SerializeField] float minTimeToSpawn = 1f;
[SerializeField] float maxTimeToSpawn = 5f;
[SerializeField] Attacker[] attackerPrefabs = null;
[SerializeField] int health = 50;
// Start is called before the first frame update
IEnumerator Start()
{
while (spawn == true)
{
yield return new WaitForSeconds(Random.Range(minTimeToSpawn, maxTimeToSpawn));
SpawnAttacker();
}
}
private void Spawn(Attacker attacker)
{
Debug.Log("Spawned at: " + (int)Time.time + " seconds.");
Attacker newAttacker = Instantiate(attacker, transform.position, transform.rotation) as Attacker;
newAttacker.transform.parent = transform;
Health healthComponent = attacker.GetComponent<Health>();
if (healthComponent == null)
{
Debug.LogError("Health component is null on " + attacker.name);
}
else
{
healthComponent.SetHealth(health);
}
}
private void SpawnAttacker()
{
//One last check, as it's possible spawn was set to false during the while loop, meaning this can still be called even if spawn is false
if (spawn)
{
int attackerPrefabsCount = attackerPrefabs.Length;
int attackerIndex = Random.Range(0, attackerPrefabsCount);
Spawn(attackerPrefabs[attackerIndex]);
}
}
public void StopSpawning()
{
spawn = false;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LevelController : MonoBehaviour
{
[SerializeField]
[Tooltip("In seconds")]
public float loadNextLevelTimer = 5f;
[SerializeField]
[Tooltip("Name of the level to load automatically after the Load Next Level Timer has finished")]
public String level = "";
private int numberOfAttackers = 0;
private GameTimer gameTimer = null;
private GameObject levelCompleteCanvas = null;
private LevelLoader levelLoader = null;
private bool levelComplete = false;
// Start is called before the first frame update
void Start()
{
gameTimer = FindObjectOfType<GameTimer>();
levelCompleteCanvas = GameObject.FindGameObjectWithTag("LevelCompleteCanvas");
if (levelCompleteCanvas != null)
{
levelCompleteCanvas.SetActive(false);
}
else
{
Debug.Log("levelCompleteCanves == null");
}
levelLoader = GetComponent<LevelLoader>();
if (level != "") //level name provided
{
Debug.Log("Level to load automatically is " + level + " in " + loadNextLevelTimer.ToString() + " seconds");
StartCoroutine(levelLoader.LoadLevel(level, loadNextLevelTimer));
}
else
{
Debug.Log("No level name provided to load automatically");
}
}
// Update is called once per frame
void Update()
{
if (gameTimer != null) //Does the game timer exist?
{
Debug.Log("gameTimer is not null");
if ((gameTimer.HasTimerFinished()) && (levelComplete == false)) //If the game timer has finished, and the level isn't yet marked as complete then handle the win condition
{
Debug.Log("gameTimer has finished and level is not complete");
HandleWinCondition();
}
}
}
private void HandleWinCondition()
{
Debug.Log("HandleWinCondition() called");
// Tell the spawners to stop spawning attackers
AttackerSpawner[] attackerSpawners = FindObjectsOfType<AttackerSpawner>();
foreach (AttackerSpawner spawner in attackerSpawners)
{
spawner.StopSpawning();
Debug.Log("spawner.StopSpawning() called");
}
int numberOfAttackers = FindObjectsOfType<Attacker>().Length;
if (numberOfAttackers == 0)
{
Debug.Log("There are 0 attackers left and the game timer has finished, the level is now complete.");
levelComplete = true;
levelCompleteCanvas.SetActive(true);
GetComponent<AudioSource>().Play();
StartCoroutine(levelLoader.LoadNextLevel(loadNextLevelTimer));
}
}
public void Quit()
{
Application.Quit();
}
}