Search Unity

Resolved Instatiating Enemies with a delay between each instantiation.

Discussion in 'Scripting' started by casezack177, Mar 30, 2023.

  1. casezack177

    casezack177

    Joined:
    Aug 10, 2021
    Posts:
    6
    Hello folks, I'm trying to create a wave spawning system for a Tower Defense game. My current code is set up to take an array of prefab monsters and an array of quantities of how many of each to spawn. IE: [Monster1, Monster2, Monster3], [3,3,3] Spawning 3 of Monster1, 3 of Monster2, and 3 of Monster3. It all works but I have occasionally noticed that the monsters will either spawn just fine or get jumbled up and begin slowing each other down due to what I believe is the Instantiate speed. I am trying to use a Coroutine with WatiForSeconds to create a small gap between each spawn time with the code below.

    Code (CSharp):
    1. void Update()
    2.     {
    3.         currentWave = waves[currentWaveIndex];
    4.         if (!EnemyAliveCheck() && spawnState == SpawnerState.Waiting)
    5.         {
    6.             Debug.Log("All Enemies are dead.");
    7.             currentWaveIndex++;
    8.             spawnState = SpawnerState.Inactive;
    9.             nextWaveButton.interactable = true;
    10.         }
    11.        
    12.  
    13.         if(spawnState == SpawnerState.Spawning)
    14.         {
    15.             StartCoroutine(SpawnNextWave());
    16.         }
    17.     }
    18.  
    19.     IEnumerator SpawnNextWave()
    20.     {
    21.         spawnState = SpawnerState.Spawning;
    22.         int arrayIndex = 0;
    23.         foreach (Transform enemy in currentWave.enemyPrefabs)
    24.         {
    25.            
    26.             for (int i = 0; i < currentWave.numToSpawnByIndex[arrayIndex]; i++)
    27.             {
    28.                 yield return new WaitForSeconds(1f / currentWave.spawnSpeed);
    29.                 SpawnEnemy(enemy);
    30.                 arrayIndex++;
    31.                
    32.             }
    33.         }
    34.        
    35.         spawnState = SpawnerState.Waiting;
    36.  
    37.     }
    38.  
    39.     private void SpawnEnemy(Transform enemy)
    40.     {
    41.         Instantiate(enemy, spawnPoint.position, Quaternion.identity);
    42.     }
    The problem I'm finding is that no matter where I put the yield return WaitForSeconds() instead of getting 3 of Monster1 3 of Monster2 and 3 of Monster3 there are about 30-40 monsters spawning in a mix of each type. I have tried making both SpawnEnemy() and SpawnNextWave() the IEnumerator and moved the WaitForSeconds return around in both but anytime I try to wait the enemies spawn like crazy. The loops do eventually end but this is not the intended amount for the wave I am creating. Where should I be putting the WaitForSeconds return in order to space out the spawning of each individual monster so I can alter the rate at which they spawn during different waves?

    Here are some screen shots of what I am dealing with.

    This is with the WaitForSeconds anywhere in the loop.
    Screenshot_1.png

    This is when the enemies will bunch up together. This causes them to move slower as well.
    Screenshot_2.png

    This is the best iteration of the script and it seems to randomly flip between the second screen shot and this screen shot when I am not using WaitForSeconds.
    Screenshot_3.png

    Thank you for your help and consideration!
     
  2. Magiichan

    Magiichan

    Joined:
    Jan 5, 2014
    Posts:
    403
    Add another state named
    Code (CSharp):
    1. SpawnerState.StartSpawning
    If the current spawnState is StartSpawning, start the coroutine & change the spawnState to Spawning.
    Make sure you change the spawnState to Spawning outside of the coroutine so the change is executed immediately.
     
    casezack177 and Bunny83 like this.
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,990
    When you control the spawning with a coroutine, why do you actually use Update in parallel? Why don't you just use a coroutine? Almost a decade ago I've written this simple yet powerful wave spawner framework. The "WaveAction" could be extended to include other things as well.

    Since we now have the SerializeReference attribute, this could actually be changed to include some polymorphic OOP classes. Though that would require additional editor scripting work, so probably not worth it.
     
    Magiichan and casezack177 like this.
  4. casezack177

    casezack177

    Joined:
    Aug 10, 2021
    Posts:
    6
    This has definitely worked. I appreciate your quick response! I guess I just skipped over the fact that it would continue to create coroutines faster than it would be able to complete one since I was trying to wait between them. The additional SpawnerState ensures that the coroutine is only executed once.

    This is an excellent framework. I am still new to Coroutines and will definitely be using your code as a reference. I hadn't thought of using a coroutine in the Start method to ensure that it is only called once. I do have a similar wave class to yours but I also hadn't considered creating a separate WaveActions class to modify the effects of each wave. Definitely have some more reading to do. Thank you so much!
     
    Magiichan likes this.