- Home /
Destroy all instantiated prefabs in Scene when Coroutine stops
Hi there,
I'm currently trying to make a rhythm game where the SpawnLeftArrow Coroutine spawns arrows from a list until a certain score is achieved. My Coroutine stops once I reach 500 points but the problem is that the last instantiated arrows are still there in my scene, they won't go away with Destroy(gameObject). My goal is to clear all of the arrows on screen. I feel like I'm misunderstanding something , like how I should access the arrows from my list. A classmate recommended to try with FindObjectsOfType, but I can't seem to understand how it works.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManager : MonoBehaviour
{
public List<GameObject> arrows;
private float spawnRate = 1.0f;
public float beatTempo;
public GameManager gameManager;
// Start is called before the first frame update
void Start()
{
beatTempo = beatTempo / 60f;
StartCoroutine(SpawnLeftArrow());
}
// Update is called once per frame
void Update()
{
}
IEnumerator SpawnLeftArrow()
{
while (gameManager.currentScore < 500)
{
Instantiate(arrows[2], new Vector3(2, 9, 0), arrows[2].transform.rotation);
gameObject.transform.position -= new Vector3(0f, beatTempo * Time.deltaTime, 0f);
if (gameManager.currentScore >= 500)
{
//find objects of type
Destroy(gameObject);
StopCoroutine("SpawnLeftArrow");
}
yield return new WaitForSeconds(spawnRate);
}
}
}
Sorry if it's a stupid question, I'm still a complete beginner. Thank you !
(Here's a picture for explanation purposes :)
Reason the arrows don't go away is that the gameObject means actually this.gameObject that is the GameObject that the SpawnManager is attached to. So you will just destroy the SpawnManger (and it's GameObject), not the Arrows.
There are many ways to find and destroy the instantiated objects.
"Easy" way is to parent your Arrows to a parent GameObject and destroy that one. Just make an empty GameObject to 0,0,0 position. Then add public GameObject parentObject;
variable to SpawnManager and drag & drop the Empty GO there.
change the instantiate line as follows:
Instantiate(arrows[2], new Vector3(2, 9, 0), arrows[2].transform.rotation, parentObject.transform);
when you want all the arrows gone just call Destroy(parentObject);
There are some other rather questionable things in the logic and code but the issue you asked about can be solved as explained above.
PS. You can use also FindObjectsOfType https://docs.unity3d.com/ScriptReference/Object.FindObjectsOfType.html to find the arrows but you need to have some "arrow specific" component in them that you can indentify. So you can store the array of found objects and the loop it trough and destroy the object in then.
PSS: I highly recommend to check ready made instructions and examples about instantiating and destroying objects.. you can find them by just googling.
Answer by Ghostling225 · Dec 22, 2021 at 10:33 AM
You could have the arrow gameobject be tagged as it's instantiated, then get all the gameobjects with that tag and destroy them. Your spawning coroutine would look like this:
IEnumerator SpawnLeftArrow()
{
while (gameManager.currentScore < 500)
{
// Instead of just instantiating the arrow, store it in a variable instantiatedArrow to modify it later
GameObject instantiatedArrow = Instantiate(arrows[2], new Vector3(2, 9, 0), arrows[2].transform.rotation);
instantiatedArrow.tag = "Arrow"; // Use whatever tag name you want.
gameObject.transform.position -= new Vector3(0f, beatTempo * Time.deltaTime, 0f);
if (gameManager.currentScore >= 500)
{
// Get all GameObjects of tag "Arrow" into an array and destroy each one
GameObject[] arrowsToDestroy = GameObject.FindGameObjectsWithTag("Arrow"); // Tag name must be same as before
foreach (GameObject arrowToDestroy in arrowsToDestroy) {
Destroy(arrowToDestroy);
}
StopCoroutine("SpawnLeftArrow");
}
yield return new WaitForSeconds(spawnRate);
}
I tried commenting it so it's obvious what the changes do, but here's a rundown: GameObject instantiatedArrow = Instantiate(...);
instantiatedArrow.tag = "Arrow";
This stores the newly instantiated arrow in the variable instantiatedArrow, so that it can be referenced when changing its tag
GameObject[] arrowsToDestroy = GameObject.FindGameObjectsWithTag("Arrow");
This grabs all the arrows (now easily findable thanks to the tagging earlier) into an array arrowsToDestroy.
foreach (GameObject arrowToDestroy in arrowsToDestroy) {
Destroy(arrowToDestroy);
}
This uses foreach to loop over all the arrows grabbed in the previous step, and runs Destroy(GameObject) on every one to remove them.
Also, not related to the original question, I'd advise moving the destruction of arrows out of the coroutine SpawnLeftArrow()
, because it's misleading to call it "spawn" if it also handles some unrelated score checks and object destruction. The if(gameManager.currentScore >= 500) {...}
if statement could be safely moved out of this coroutine into a different place.
Your answer
Follow this Question
Related Questions
Roll a ball tutorial Problem Please Help 1 Answer
Basic javascript array declaration 2 Answers
2D sprites in a 3D enviroment, beginner help. 1 Answer
Mecanim: getting the gameobject to follow the motion while climbing? 1 Answer
Beginners question with Unity and App42 - Struggling with handling call back on exception 0 Answers