Access a instantiated gameobject from a enemy spawner

Hey guys I am stuck on a issue.

Okay I have two scripts a enemy health script and a spawner script. They are very basic however I am running into a issue that has to do with the enemy is being destroyed.

What is happening?

  • when the enemy is instantiated the “int” value numTargets gets incremented by 1;

  • When it reaches the spawn limit the enemies spawner will stop spawning.

My problem:

-I cant seem to access the spawner script from my enemyHealth script to reduce the numTargets value by one. Because I want a new enemy to spawn after the current one is defeated.

I want several different spawn points using this script and I want the enemy that was spawned from a certain spawner only access that particular game object to reduce the numTargets variable.

Note: you will notice in my code I tried to use a spawnID to identify the particular spawner I wanted the enemy to target but I couldn’t get it working.

I am stuck on this and would love any help. Scripts below:
Enemy spawner script

public class EnemySpawn : MonoBehaviour 
{
    public GameObject enemy;
    public float spawnTimer;
    public int spawnLimit;
    public int spawnID;

    private EnemyHealth enemyHealth;
    private int spawnNum;
    private float timer;

    void Awake()
    {
       enemyHealth = enemy.GetComponent<EnemyHealth>();
    }

    void Start()
    {
        spawnID = Random.Range(1, 20);
    }

    void Update()
    {
        timer += Time.deltaTime;

        SpawnEnemy();
    }

    void SpawnEnemy()
    {
        if (spawnNum < spawnLimit)
        {
            if (timer > spawnTimer)
            {
                Instantiate(enemy, transform.position, transform.rotation);
                enemyHealth.spawnID = spawnID;
                timer = 0f;
                spawnNum++;
            }
        }
    }

    public void EnemyDestroyed()
    {
        spawnNum--;
    }
}

Enemy Health script:

public int startingHealth = 100;
    public int currentHealth;
    public int spawnID;

    private EnemyMovement enemyMovement;
    private EnemySpawn enemySpawn;

    void Awake()
    {
        enemyMovement = GetComponent<EnemyMovement>();
    }

    void OnEnable()
    {
        currentHealth = startingHealth;
    }

    void Update()
    {
       
    }

    public void TakeDamage(int amount)
    {
        currentHealth -= amount;

        if(currentHealth <= 0)
        {
            Death();
        }
    }
    
    void Death()
    {
        //Add enemy spawner script here.
        Destroy(gameObject);
    }
}

Are there any suggestions other than tags? Cause that would take more work and more problems.

Thank you in advance.

Here is an alternative script you can use. Attach this to a single spawner. It will Have a set number of spawns. And will keep spawning an enemy when the previous one was killed, until it runs out of spawns. It Does not affect the number of spawns in other spawners. (Because I think that is what you want).

In addition with this you don’t have to worry about the scripts interacting with each other. The spawner script will take care of spawning and tracking.

public class EnemySpawn : MonoBehaviour 
 {
     /* Public Variables */
     public GameObject enemy;
     
     /* private Variables */ 
     [SerializeField] // makes it so it will show in inspector but still private
     int spawnNum;
     Transform trackedEnemy;

     void Start()
     {
       trackedEnemy = null;
       spawnNum = 5; // <-------------- Set the spawn Num here 
     }
    
     void LateUpdate () {
          
         if (trackedEnemy == null) // Only spawns when other is killed
            if (spawnNum > 0) // Only spawns when it has spawns left
               SpawnEnemy ();
            else
               // Out of spawns so deactivate
               GetComponent<EnemySpawn> ().enabled = false; 
      }

     void SpawnEnemy()
    {         
           // Instantiate Enemy
           GameObject enemyObj =  Instantiate(enemy, transform.position, transform.rotation) as GameObject;
                                        
            // Start Tracking this particular enemy
            trackedEnemy = enemyObj.transform;

           // Reduce number of spawns
          spawnNum--;


     }
 }

In your enemy health script, on void Death(),

You could do: GetComponent().EnemyDestroyed();

Furthermore, when creating the enemy, you should pass which Spawner spawned it, then reference it in the GetComponent portion…

mySpawner.GetComponent().EnemyDestroyed();

If I came across a problem like this, I would make it so when the enemies spawn they become a child of the spawner. Then what you can do is set the numTargets to the child count of the spawner.

So in example the spawn limit is 4, one of the enemies die. The spawner now only has 3 children.
You would then Instantiate a new enemy.

This means you don’t need to search for other GameObjects or Scripts.

I hoped this helped.

Here is the answer, analyze it, I made it into a unityPackage:

Then, adapt it to your needs, I did not touch your code at all, I made just fresh code so you can figure stuff yourself.

https://drive.google.com/file/d/0ByN7a5K93ruaUzd2U0R2MjBKd2s/view?usp=sharing

Spawner test grabs a gameobject to spawn.
When you press the key, it checks if it can spawn, then, it adds one to the count, spawns the object, stores the GameObject in a variable, and gets the Object’s class, which has a public method call “Register”, I will explain that later, but basically you register the method OnSpawnedObjectDeath to the newly spawned object’s event.

Finally, when OnSpawnedObjectDeath is called, one is reduced from your count, allowing you to spawn another one.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

    public class SpawnerTest : MonoBehaviour {
    	[SerializeField] GameObject goToSpawn; //Appears on inspector, but is private.
    	[SerializeField] KeyCode keyToSpawn;
    	[SerializeField] int spawnLimit = 4;
    	int numOfSpawnedObjects = 0;
    
    	
    	// Update is called once per frame
    	void Update () {
    		if (Input.GetKeyDown (keyToSpawn)) {
    			bool canSpawn = numOfSpawnedObjects < spawnLimit;
    			if (canSpawn) {
    				Spawn ();
    			}
    		}
    	}
    		
    	void Spawn(){
    		numOfSpawnedObjects++;
    		var spawnOffset = new Vector3 (Random.Range (1f, 3f), Random.Range (1f, 3f), 0f);
    		var spawnedGO = GameObject.Instantiate (goToSpawn, transform.position + spawnOffset, Quaternion.identity) as GameObject;
    		spawnedGO.GetComponent<SpawnedObjectTest> ().RegisterDelegateTo (this);
    		//This is a SpawnerTest, specifically, this Spawner test, so, the method OnSpawnedObjectDeath from
    		// this object is called when the object dies.
    
    	}
    
    	public void OnSpawnedObjectDeath(){ //Public to be accesible by references
    		numOfSpawnedObjects--;
    		Debug.Log (gameObject.name + " delegate was called ");
    	}
    }

Next script is: SpawnedObjectTest

The first method is called is “RegisterDelegateTo(SpawnerTest spawner)”. This method is called by the spawner.
It grabs the spawner and caches the reference into m_spawner; why? because when you register events, you must unregister them as well…
Then adds the OnSpawnedObjectDeath Method to the ObObjectDeath event.
Fianlly, it invokes a method to destroy itself in the ammount of time you specify.

When that method is called, you trigger the event, which calls the spawners method, and then you unregister and destroy.

ez.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnedObjectTest : MonoBehaviour {

	public delegate void ObjectEvent();
	public ObjectEvent OnObjectDeath;

	[SerializeField] float tToDestroy;
	SpawnerTest m_spawner;

	public void RegisterDelegateTo(SpawnerTest spawner){
		//Register you method to the event
		m_spawner = spawner;
		OnObjectDeath += m_spawner.OnSpawnedObjectDeath;
		Invoke ("DestroySpawnedObject", tToDestroy);
	}


	void DestroySpawnedObject(){
		if (OnObjectDeath != null) { //Check delegates for null, running 
			//null delegates causes errors.
			OnObjectDeath();
			OnObjectDeath -= m_spawner.OnSpawnedObjectDeath;
		}
		Destroy (this.gameObject);
	}
}