Spawned Enemies: How to Destroy child objects inside their own attached scripts without Destroying the parent object for InvokeRepeating??

I’m creating a (early version) tower defense shooter game with spawned enemies. I have GameObject called SpawnLocation that contains the location in which I would like to spawn my enemies, with a EnemyManager.cs script attached to it. In that, I call InvokeRepeating (“Spawn”, 3f, 3f) in my Start(), and in Spawn(), I call Instantiate (enemy, transform.position, transform.rotation) (enemy being the game object prefab). Attached to that enemy prefab, I have an EnemyController.cs script which detects collisions and Destroy(gameObject).


When I destroy the first enemy, however, I receive an error preventing further spawns:

The object of type ‘GameObject’ has
been destroyed but you are still
trying to access it

I believe it is because since I passed in my enemy object, destroying itself after instantiation in its own separate function still destroys the parent object passed in, which means if I try to invokerepeat with that destroyed object, I’ll have no object to instantiate. So how do I go about this?


I’ve been frustratingly searching for an answer for awhile but couldn’t find one specific to destroying multiple child game objects within their own instantiated scripts. I know Instantiate() returns the clone object when called in the parent, but how do I destroy it from that other attached child function, not the parent function? Deactivate() likely does the same thing. If I instead Destroy() inside the parent function, how do I get the clone object if that object does not have a distinctive ID (and its position moves)? Using an array of enemy clone objects doesn’t really allow me to know if it’s been hit 10 (or however many) times and needs to be destroyed. I’ve tried using coroutines, but seemed to run into problems as well. Here’s a sample code:


public class EnemyManager : MonoBehaviour {
	public GameObject enemy;
	public int playerHealth, spawnCount, deathCount, numEnemies;

	void Start() {
		numEnemies = playerHealth = spawnCount = 10;
		deathCount = 0;

		InvokeRepeating("Spawn", 3f, 3f); //give some time before spawning
	}

	void Update() {
	if(playerHealth <= 0)
		//end game somehow
	}

	void Spawn() {
		if(playerHealth <= 0 || deathCount >= numEnemies)
			return;

		Instantiate(enemy, transform.position, transform.rotation);
		spawnCount += 1; // keeps track of number of enemies spawned
	}
}

public class EnemyController : MonoBehaviour {
	public int enemyHealth;

	void Start() {
		enemyHealth = 10; //hit each enemy 10 times to destroy it
		manager = GameObject.Find ("Spawn Location");
		managerScript = manager.GetComponent<EnemyManager>();
	}

	void Update() {
		//move player on a path
		if(enemyHealth <= 0) {
			managerScript.deathCount += 1; //successful kill of an enemy
			Destroy(gameObject); //or deactivate
		}
	}

	void OnTriggerEnter2D(Collider2D other) {
		if(other.gameObject.CompareTag("Bullet")) { //many triggers on board
			enemyHealth -= 1;
		}
		else if(other.gameObject.CompareTag("EndPath")) {
			managerScript.playerHealth -= 1;
			Destroy(gameObject); //so it doesn't keep on walkin forever
		}
	}
}

Here are a few things that I would do that might help you with your code logic,


  • in the OnTriggerEnter2D in the first if statement ( `if(other.gameObject.CompareTag("Bullet"))` ) after enemyHealth -= 1 add the `if(enemyHealth <= 0)` block after that line so right after taking damage you'll check if there's no health left instead of always checking in the update method
  • When declaring `manager` in the EnemyController class use `gameObject.transform.parent.gameObject` so if you want to create more spawn locations you don't have to worry about being limited to only 1 because you're using GameObject.Find();
  • I hope this helps you somewhat, I’ll be experiementing with your code in my practice project.