Hello!
I am making a game where when the game has ran for a certain amount of time, the obstacles spawn faster. I make them spawn by using IEnumerator to where when an obstacle spawns every 3-ish seconds. I tried to stop and start a coroutine in an if statement in void Update, but when it got called, instead of the objects spawning every 3-ish seconds, the obstacles just spawned every frame. Anyone know how I can fix this? Thanks.
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour {
public GameObject obstacle;
Vector3 obstacleSpawnPos = new Vector3 (0.0f, 0.0f, 0.0f);
void Start () {
StartCoroutine (FirstObstacleSpawnRoutine());
}
void Update () {
if (Time.time > 15) {
StopCoroutine (FirstObstacleSpawnRoutine());
StartCoroutine (SecondObstacleSpawnRoutine());
}
if (Time.time > 30) {
StopCoroutine (SecondObstacleSpawnRoutine());
StartCoroutine (ThirdObstacleSpawnRoutine());
}
if (Time.time > 50) {
StopCoroutine (ThirdObstacleSpawnRoutine());
StartCoroutine (FourthObstacleSpawnRoutine());
}
}
IEnumerator FirstObstacleSpawnRoutine () {
while (true) {
Instantiate (obstacle, obstacleSpawnPos, Quaternion.identity);
yield return new WaitForSeconds (Random.Range (3.0f, 5.0f));
}
}
IEnumerator SecondObstacleSpawnRoutine () {
while (true) {
Instantiate (obstacle, obstacleSpawnPos, Quaternion.identity);
yield return new WaitForSeconds (Random.Range(2.5f, 4.25f));
}
}
IEnumerator ThirdObstacleSpawnRoutine () {
while (true) {
Instantiate (obstacle, obstacleSpawnPos, Quaternion.identity);
yield return new WaitForSeconds (Random.Range(2.25f, 3.5f));
}
}
IEnumerator FourthObstacleSpawnRoutine () {
while (true) {
Instantiate (obstacle, obstacleSpawnPos, Quaternion.identity);
yield return new WaitForSeconds (Random.Range(2.0f, 3.0f));
}
}
}
Just make a new coroutine called SpawnObjects or something, and in there start the first wave, then yield wait 15 seconds, then stop the first and start the second, then yield wait for 15 more seconds, then stop the second and start the third, etc… Start the primary coroutine in Start, or via a method, and not in Update. You can delete the Update method entirely.
Honestly though, in this case, you can get away with one or two coroutines. You can have the ObstacleSpawnRoutine just take two parameters for the time to wait between spawns (min and max to use in the Range function), and just stop and start the same routine with different parameters set. Even better would be to use private fields or properties to get those values, and start two coroutines- the first just keep track of the timing of the waves and sets those fields, while the second ObstacleSpawnRoutine just uses the values to spawn objects with that timing.
public GameObject obstacle;
public Vector3 obstacleSpawnPos = Vector3.Zero;
private float minSpawnTime = 3f;
private float maxSpawnTime = 5f;
private WaitForSeconds waveTimer;
private void Awake()
{
waveTimer = new WaitForSeconds(15f);
StartCoroutine("WaveRoutine");
StartCoroutine("SpawnRoutine");
}
private IEnumerator WaveRoutine()
{
minSpawnTime = 3.0f;
maxSpawnTime = 5.0f;
yield return waveTimer;
minSpawnTime = 2.5f;
maxSpawnTime = 4.5f;
yield return waveTimer;
minSpawnTime = 2.0f;
maxSpawnTime = 4.0f;
yield return waveTimer;
// etc...
}
private IEnumerator SpawnRoutine()
{
while(true)
{
Instantiate(obstacle, obstacleSpawnPos, Quaternion.identitiy;
yield return new WaitForSeconds(Random.Range(minSpawnTime, maxSpawnTime));
}
}
If you want to store the spawn timings in a collection of float/float objects, you can just iterate through that collection for the WaveRoutine until it runs out of items as well, so it’s not hardcoded in the routine.
Haha. never thought about that. Works perfectly now.
Thanks!