- Home /
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:
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.
Answer by Cornelis-de-Jager · Jul 11, 2017 at 10:46 PM
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--;
}
}
Cool ill give it a try and let you know if it works for me
Answer by Cynikal · Jul 11, 2017 at 11:45 PM
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();
Regarding the "which spawner spawned it" that's what I am trying to figure out. I tried using a public void function I could call but I still need to identify it.
Answer by Scruffy250 · Jul 12, 2017 at 03:58 PM
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.
Hmmm okay I would just need to find out how to put a instantiated gameobject all a child. Ill give it a try
Hey your method worked the based for me thanks. What do you think?
void Start()
{
spawnNum = transform.childCount;
}
void Update()
{
timer += Time.deltaTime;
spawnNum = transform.childCount;
SpawnEnemy();
}
void SpawnEnemy()
{
if (spawnNum < spawnLimit)
{
if (timer > spawnTimer)
{
GameObject enemyObj = Instantiate(enemy, transform.position, transform.rotation) as GameObject;
enemyObj.transform.parent = this.gameObject.transform;
timer = 0f;
}
}
}
Answer by Milo_del_mal · Jul 12, 2017 at 04:39 PM
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);
}
}
Your answer
Follow this Question
Related Questions
instantiating objects problem 1 Answer
copy enemy prefabs 1 Answer
NavMesh giving jerky like motion 0 Answers
SOLVED - Accessing a C# script value from another GameObject's JavaScript 2 Answers
Combine objects instantiated at runtime 2 Answers