ENEMY SPAWNER - THIS IS A TOUGH ONE

So, I have been trying to think of how to do this for weeks. Can’t figure it out. Here’s what I’m looking at:

My brother and I are making a game that has a few different levels. Each level has a set number of enemy waves, and each wave has a set number of enemies. We wrote out a list of all the enemies and how many are in each wave of each level. We have thought about having them in a certain order and at a certain time, but that seems insane, so for now, just a certain number of each enemy, in a random order.

Basic Functionality:

Wave 1 of level 1 would always spit out, say, 3 bats and 6 goblins, one at a time, in a random order. Wave 2 would always spit out, say, 5 bats, 14 goblins, and a fire elemental in a random order. So on and so forth.

Thoughts:

  • Since there are multiple levels, each
    with their own set of enemies, I
    think I would want the spawner to
    pull a list of the enemies for each
    wave from a script that’s attached to
    a game object in each level.
  • The spawner would then add up
    the total number of enemies for that
    wave, and while that number is > 0,
    it would spawn an enemy. The hard
    part is getting the quantity for each
    enemy and only spawning that enemy if
    there are some of that enemy left.
  • I know the spawner will need a list of all enemy prefabs that it can pull from, and I think the best way would be to use a switch statement. So it will pull a list of all the enemies and put them in a local list, but the part I can’t figure out is the quantity for each enemy. Should I be using a 2D array somehow for the enemy name and quantity? So, the spawner will instantiate a goblin IF… A1 == “goblin” && A2 >= 1?

Anyone have any wisdom on how this can be done!? D:

Thanks for the help in advance!

P.S. I have already made a spawner that randomly spits out enemies until the total enemy count is 0, but doesn’t adhere to any structure, just a random enemy each time until the TOTAL count is 0. This uses coroutines and stuff, so I got the timing and everything down, but if anyone has suggestions on ANY part of this, I’ll take it! Just need to learn a lot still!

So if I understood your problem right you have waves. Each wave will specify how many enemies of each type should be spawned in that wave. You want to only spawn a single enemy at a time. The enemy should be choosen randomly from the available pool of enemies for the current wave.

You haven’t specified how your “list” looks like. I would go with something like this:

[System.Serializable]
public class EnemyItem
{
    public GameObject prefab;
    public int count;
}

[System.Serializable]
public class Wave
{
    public List<EnemyItem> enemies;
    public List<GameObject> GetWavePool()
    {
        var res = new List<GameObject>();
        foreach(var item in enemies)
        {
            for(int i = 0; i < item.count; i++)
                res.Add(item.prefab);
        }
        // scramble list
        for(int i = 0; i < res.Count-1; i++)
        {
            var tmp = res*;*

int rnd = Random.Range(i, res.Count);
res = res[rnd];
res[rnd] = tmp;
}
return res;
}
}

public class Spawner : MonoBehaviour
{
public List waves; // assign in inspector

IEnumerator Spawning()
{
foreach(var wave in waves)
{
var pool = wave.GetWavePool();
foreach(var prefab in pool)
{
Instantiate(prefab);
yield return new WaitForSeconds(1);
}
}
}
}
So for each wave we simply create a temporary list of all prefabs we want to instantiate. We simply add as many references as required for each enemy / prefab type. Once all elements have been added we simply scramble the list to get a random spawning when iterating through the pool.

This is interesting as I was once encountered the same situation like you and never been able to get back to the game I was making.

I come up with this solution. Check it out

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

[System.Serializable]
public class Enemies{
	public GameObject enemyType;
	public int count;
}

[System.Serializable]
public class Levels{
	public Enemies[] noOfEnemyType;
}

public class LevelManager : MonoBehaviour {

	public int currentLevel; // Level 1 starts at 0

	public Levels[] levels;

	public void SpawnEnemy(){

		// Get available Enemy Type at current level. Store all available enemy type in a List.
		List<int> availEnemyType = new List<int> ();
		for (int i = 0; i < levels[currentLevel].noOfEnemyType.Length; i++) {
			if (levels [currentLevel].noOfEnemyType *.count > 0) {*
  •  		availEnemyType.Add (i);*
    
  •  	}*
    
  •  }*
    
  •  if (availEnemyType.Count > 0) { // Check if not null*
    
  •  	int randEnemyIndex = Random.Range (0, availEnemyType.Count); // Randomly pick from available enemy type*
    
  •  	Instantiate (levels [currentLevel].noOfEnemyType [availEnemyType [randEnemyIndex]].enemyType, this.transform); // You know this already :)*
    
  •  	levels [currentLevel].noOfEnemyType [availEnemyType [randEnemyIndex]].count -= 1; // Reduce spawn count of enemy instantiated.*
    
  •  } else {*
    
  •  	// What do you want to do after there are no more enemies available? I wonder... Stop spawning I guess.*
    
  •  	Debug.Log ("No More Enemies");*
    
  •  }*
    
  • }*
    }
    You can also use a dictionary or multidimensional array but the problem with those is that they don’t appear in the inspector as “[Unity doesn’t know how to serialize a Dictionary][1]” or multidimensional array.
    Reference: [Initializing 2D array via inspector - Questions & Answers - Unity Discussions][2]
    [1]: Unity - Scripting API: ISerializationCallbackReceiver
    [2]: Initializing 2D array via inspector - Questions & Answers - Unity Discussions