Best way to spawn enemies based on time
I have been looking for a solution to this, and I apologise if this has been answered before.
I am working on a Vertical Style Scrolling shooter, for instance 1942 image
The plan is to spawn enemies in waves after a certain amount of time. I have been trying to do this in different ways. My knowledge of Unity is limited as I am new, and have only been working through the basics thus far.
I have been trying to use this:
void Start () {
spawnTimer = 7.0f;
}
void Update () {
timer += Time.deltaTime;
if(timer==spawnTimer){
print("7 secs passed");
Spawner(1.2f);
}
}
void Spawner(float whichNPC){
if(whichNPC == 1.2f){
SendMessage("SpawnNPC1M");
totalNPCSpawned += 5;
print(totalNPCSpawned);
}
The problem seems to arise with using "if(timer==spawnTimer){" I guess this is due to the time not being in exact values. I know its possible to use > but the plan is to use the variable "timer" again, once further time has expired, and to stop it from calling the "Spawner" function over and over again causing multiple enemies to keep spawning.
Hope this makes any sense?
Is it perhaps better to use WaitForSeconds each time?
Thanks in advance.
Answer by OncaLupe · Dec 14, 2015 at 01:03 AM
You are correct in why it's not triggering. Comparing floats with == can often miss. Even when manually changing the values (like adding 0.1f), trying to compare to 1.0f can still miss due to rounding issues. Positions are also common to being just slightly off.
For this situation, there are a few ways I can think off of the top of my head. First is to use if(timer >= spawnTimer)
, and reset timer to 0 on trigger. You can also adjust spawnTimer if you want different times between waves.
using UnityEngine;
using System.Collections;
public class SpawnWaves : MonoBehaviour
{
float spawnTimer = 7f;
float timer = 0f;
int waveNumber = 0;
void Update ()
{
timer += Time.deltaTime;
if(timer >= spawnTimer)
{
Spawner();
}
}
void Spawner()
{
//Switches are cleaner than using many ifs when checking one variable.
switch(waveNumber)
{
case 0://If waveNumber == 0
//Spawn first wave
break;//End switch
case 1:
//Spawn second wave
break;
}
++waveNumber; //Increment by 1. Same as: waveNumber = waveNumber + 1;
timer = 0f;
//Optional, randomize wave times.
spawnTimer = Random.Range(7f, 10f);
}
}
The other thing that comes to mind is using WaitForSeconds as you mentioned in a Coroutine. Simpler to code, but if you need to adjust things mid run (like triggering a wave early) isn't as easy as the first way.
void Start()
{
StartCoroutine("Spawner");
}
//IEnumerator is the keyword for Coroutines, which can run over multiple game frames.
//Can be stopped by calling: StopCoroutine("Spawner");
IEnumerator Spawner()
{
return new WaitForSeconds(7f); //Pauses the coroutine
//Spawn first wave
return new WaitForSeconds(7f);
//Spawn second wave
//..etc
}
Hi there,
Firstly thanks a lot for your response. I am going to give both of these methods ago today. I will probably end up using all of this for different parts of my game.
I do have a question with regards to Coroutine's: -when stating "return new WaitForSeconds(7f);" will that only start counting again once this has finished calling what ever I put below, or does will it immediately start to count the 7 seconds?
I have my NPC's spawning on a time delay as well at spawn points which are invisible game objects e.g.
//spawn npc1 on delays
void SpawnNPC1L () {
spawnLeft = true;
SpawnDelay00 (); //0 sec delay
Invoke("SpawnDelay05", 0.5f); //0.5 sec delay
Invoke("SpawnDelay10", 1); //1.0 sec delay
Invoke("SpawnDelay15", 1.5f); //1.5 sec delay
Invoke("SpawnDelay20", 2); //2.0 sec delay
}
void SpawnDelay00 () {
if(spawnLeft){
SpawnNPC(npc1Prefab, spawn1a, "npc1LS1a"); //spawn prefab 1, @ spawn1a, with name npc1LeftSide1a
//npcCounter ++;
}
}
void SpawnDelay05 () { //spawn enemies with 0.5 second delay
if(spawnLeft){
SpawnNPC(npc1Prefab, spawn1b, "npc1LS1b");
//npcCounter ++;
}
}
void SpawnDelay10 () { //spawn enemies with 1.0 second delay
if(spawnLeft){
SpawnNPC(npc1Prefab, spawn1c, "npc1LS1c");
//npcCounter ++;
}
}
void SpawnDelay15 () { //spawn enemies with 1.5 second delay
if(spawnLeft){
SpawnNPC(npc1Prefab, spawn1d, "npc1LS1d");
//npcCounter++;
}
}
void SpawnDelay20 () { //spawn enemies with a 2.0 second delay
if(spawnLeft){
SpawnNPC(npc1Prefab, spawn1e, "npc1LS1e");
}
spawnLeft = false;
}
void SpawnNPC(GameObject npc, Transform spawnTrans, string npcName){
GameObject newNPC = Instantiate(npc, spawnTrans.position, spawnTrans.rotation) as GameObject; //instantiate enemy
newNPC.name = npcName;
}
}
-So after the 7 seconds have elapsed, this function is being called to spawn the particular set of NPC's in a formation of sorts.
So I think that I have figured this out through process of eli$$anonymous$$ation. Using the two examples you have given me I have come up with the following:
// Update is called once per frame
void Update () {
/*
timer += Time.deltaTime;
if(timer==spawnTimer){
print("7 secs passed");
whichNPC = 1.1f;
Spawner();
}*/
}
IEnumerator SpawnerControl(){
yield return new WaitForSeconds(4f); //will only call this after every 4 seconds
whichNPC = "1.2";
Send$$anonymous$$essage("SpawnNPC1$$anonymous$$");
yield return new WaitForSeconds(4f); //will only call this after every 4 seconds
print("test");
}
void Spawner(){
switch(whichNPC){
case "1.1":
Send$$anonymous$$essage("SpawnNPC1L");
break;
case "1.2":
Send$$anonymous$$essage("SpawnNPC1$$anonymous$$");
break;
default:
print("No NPC spawn assigned to value");
break;
}
}
}
Which, until the next problem arises, is working a treat, and will seem to be future proof for a little while. Thank you very much for your help!