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 :slight_smile: 190125-example.png

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.