Spawning Multiple simultaneous waves

hi, i finished the laser spaceship section of the 2d course, i wanted to implement simultaneous spawning of enemies from different waves, but i can’t get to figure out how to do it
i’ll explain myself better: i already know that putting two scripts of the enemy spawner type get me to spawn multiple parallel enemies:


but doing like this has a problem: i have to follow an exact order, and the waves are not synchronous, what if i want to spawn let’s say the Element 0 of the second enemy spawner when the element 4 kicks in of the first enemy spawner?
it would be cool if i managed to find also a way to get a delay between the spawns, but i think i almost did this, arghh i’m trying to solve this, if anyone could lend a hand it would be much appreciated

This would be useful like if i wanted to put a Final Boss too, after a lot of waves, at first i thought in just using a cououtine to delay it’s spawn for some amount of time, but now it just seems stupid, i think it would be better if i can get some thing to trigger the kicking of each wave, like a “what comes before you” variable? mhh

Is wave configs stored in a list?

the code is pretty much the same as Rick’s

this is the code for the wave config a ScriptableObject where you put wave information, how many enemies, which ones, and the path

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//è una sorta di contenitore di dati di configurazione, dove chiunque puo attingere
[CreateAssetMenu(menuName = "Enemy Wave Config")]
public class WaveConfig : ScriptableObject
{
    [SerializeField] GameObject enemyPrefab;
    [SerializeField] GameObject pathPrefab;
    [SerializeField] float timeBetweenSpawns = 0.5f;
    [SerializeField] float spawnRandomFactor = 0.3f;
    [SerializeField] int numberOfEnemies = 5;
    [SerializeField] float moveSpeed = 2f;

    public GameObject GetEnemyPrefab()  {  return enemyPrefab; }
    public List<Transform> GetWaypoints() 
    {
        var waveWaypoints = new List<Transform>();
        foreach (Transform child in pathPrefab.transform) //aggiungi la transform (posizione) di ogni "child" del path che inserisco nel field (i waypoint quindi) in wavewaypoints che è una list di tipo transform (lista di posizioni)
        {
            waveWaypoints.Add(child);
        }

        return waveWaypoints; 
    }

    public float GettimeBetweenSpawns() {return timeBetweenSpawns; }

    public float GetspawnRandomFactor() { return spawnRandomFactor; }

    public int GetnumberOfEnemies() { return numberOfEnemies; }

    public float GetmoveSpeed() { return moveSpeed; }

}

this is the enemy spawner one, the one where you put the waves and which permits the loop

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawner : MonoBehaviour
{

    [SerializeField] List<WaveConfig> waveConfigs;
    [SerializeField] int startingWave = 0;
    [SerializeField] bool looping = false; 

    // Start is called before the first frame update
    IEnumerator Start()   //HO CAMBIATO tipo a start in IEnumearator per renderlo una COROUTINE!
    {
        do
        {
           yield return StartCoroutine(SpawnAllWaves()); //starta la coroutine e torna (yield) solo una volta che è completata, quando hai finito controlla il bool
        }
        while (looping);
     

    }

    private IEnumerator SpawnAllWaves()
    {
        for(int waveIndex = startingWave; waveIndex < waveConfigs.Count ; waveIndex++)
        {
            var currentWave = waveConfigs[waveIndex];
            yield return StartCoroutine(SpawnAllEnemiesInWave(currentWave)); //finchè non ha finito spawnallenemies
        }
    }

    private IEnumerator SpawnAllEnemiesInWave(WaveConfig waveConfig)
    {
        for (int enemyCount = 0; enemyCount < waveConfig.GetnumberOfEnemies(); enemyCount++)
        {
            var newEnemy = Instantiate(
                waveConfig.GetEnemyPrefab(),
                waveConfig.GetWaypoints()[0].transform.position,
                Quaternion.identity);

            newEnemy.GetComponent<EnemyPathing>().setWaveConfig(waveConfig);
            yield return new WaitForSeconds(waveConfig.GettimeBetweenSpawns());

        }
    }
}

yes it is a list, sorry for the //comments in Italian in the code but i’m italian and they were meant as reminders for me haha

i did different things but they were not really reusable and flexible solutions, i want something that is more reusable and flexible as possible.

like i’m trying to put it as simple as i can, i need to find a way to “play” the first and only wave of the second list of wave configs after the third element of the first wave, and maybe also after a bit of delay

if i can solve this maybe i can extend it to a global solution :confused:

at first i did it like the “RAW” way by simply putting it in a coroutine which waited for some seconds haha

Heres a possible solution for randomly selecting a wave config out of the list:

[SerializeField] int numberOfWaves = 10;
private IEnumerator SpawnAllWaves()
    {
     

        for(int i =0 ; i < numberOfWaves ; i++)
        {
            var currentWave = waveConfigs[Random.Range(0, waveConfigs.Length)];
            yield return StartCoroutine(SpawnAllEnemiesInWave(currentWave)); //finchè non ha finito spawnallenemies
        }

       //After player makes it through all waves, spawn boss
       SpawnBoss();
    }

yeah but i want to have super control about which waves is spawned and how :confused: like the opposite of randomness ahaha i want to have the power to decide which wave of an other EnemySpawner come after the wave of an other enemyspawner and with it also deciding things like delay etc

how is the code right now it only permits the spawn of a wave after the precedent has finished his “spawning of enemies” so to spawn simultaneus waves i have to put TWO or more scripts of type EnemySpawner with waveconfig in it, but i can’t control the timing between the two

Add another yield return WaitForSeconds

eg:

for(int i =0 ; i < numberOfWaves ; i++)
        {
            var currentWave = waveConfigs[Random.Range(0, waveConfigs.Length)];
            yield return StartCoroutine(SpawnAllEnemiesInWave(currentWave)); //finchè non ha finito spawnallenemies
          yield return WaitForSeconds(timeBetweenWaveSpawns);
        }

yeah but the randomness like kills what i want to do .-. , and still i think you didn’t get what i’m trying to achieve

In the WaveConfig you could add another List of waveconfigs that could come after that one and have a public method that returns a random one from that list

public class WaveConfig : ScriptableObject
{
       [SerializeField] List<WaveConfig> wavesFollowing = new List<WaveConfig>();

       public WaveConfig GetFollowingWave()
       {
               return wavesFollowing(Random.Range(0, wavesFollowing.Length));
       }
}

This is what happens with 2 wave config and it’s what i want, but i also want to say like, “ok now let’s spawn this wave after wave 2 (or 3 or whatever) of the first enemy spawner”


this is what happens with only one, it has to wait until all the enemy of a wave spawns before the other wave kicks in, is more of a SERIAL way i want it to be PARALLEL

i don’t know, what if i wanted like 4 “parallel” (spawning at the exact same time) enemies with different paths all kicking in at the same time? i have to do 4 separate lists? :confused:

The list within the waveconfig can be of any length, but does require one so you can make it so one will follow or a few different waves.

sorry but i’m not following you :sob: i have to do a list for every" parallel lines" of enemy waves i want? if yes i kinda not like the idea .-.

I would suggest you press on through the coarse until you’ve gained more experience then come back to this problem and see if you can come up with a solution.

mh ok :c but i’m pretty sure we didn’t understand each other for what i was trying to achieve, cause i don’t want it to be random, i want to exactly determine which waves come in parallel with an other

oh in that case instead of a list, just have a single WaveConfig

public class WaveConfig : ScriptableObject
{
       [SerializeField] WaveConfig waveFollowing = null;

       public WaveConfig GetFollowingWave()
       {
               return waveFollowing;
       }
}

Privacy & Terms