- Home /
Enemy Spawner help
Hello, just to start out i have a spawner that when it turns on, will spawn my creatures for me. but when it turns off through a day and night cycle, when the time comes to turn it on again it wont instantiate the gameobject selected. so the problem i am having is that it will loop the spawn enemy once but when it goes off then back on it wont. here are all the C# codes i have affiliated with my spawner.
this is my spawner
using UnityEngine;
using System.Collections;
public class EnemyController : MonoBehaviour {
public GameObject enemy;
public Vector3 spawnValues;
public float spawnWait;
public float startWait;
public static EnemyController enemycontroller;
void Awake(){
enemycontroller = this;
}
void Start(){
StartCoroutine (SpawnWaves ());
}
void Update(){
SpawnWaves ();
}
IEnumerator SpawnWaves(){
yield return new WaitForSeconds(startWait);
while (true) {
Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, Random.Range (-spawnValues.z, spawnValues.z));
Quaternion spawnRotation = Quaternion.identity;
Instantiate (enemy, spawnPosition, spawnRotation);
Debug.Log ("Enemy Spawned!");
yield return new WaitForSeconds (spawnWait);
}
}
}
this is my day night cycle code
using UnityEngine;
using System.Collections;
public class IslandPicker : MonoBehaviour {
public GameObject[] Island;
public GameObject Spawners;
public int CurrentIsland;
void Start () {
for (var i = 0; i < Island.Length; i++) {
Island [i].SetActive (false);
}
Spawners.SetActive (false);
}
void Update () {
}
void OnTriggerEnter(Collider col){
if (col.tag == "NewDay") {
NewIsland ();
Debug.Log ("NewDay");
}
if (col.tag == "Night") {
Spawners.SetActive (true);
Debug.Log ("Night Has Come!");
}
if (col.tag == "Day") {
Spawners.SetActive (false);
Debug.Log ("Day Has Come!");
DestroyAll ("Wraith");
}
}
void NewIsland(){
int newIsland = Random.Range (0, Island.Length);
//Island [CurrentIsland].SetActive (false);
CurrentIsland = newIsland;
Island [CurrentIsland].SetActive (true);
}
void DestroyAll(string tag){
GameObject[] ObjectsToDestroy = GameObject.FindGameObjectsWithTag ("Wraith");
foreach (GameObject DestroyObject in ObjectsToDestroy) {
Destroy (DestroyObject);
}
}
}
i am not that perfect at coding so forgive the unorganized code :)
Answer by DiegoSLTS · Aug 28, 2016 at 04:22 PM
You have a few problems there:
In your Update your calling SpawnWaves like it's a normal method, but Coroutines don't work like that in C#. If you defined a coroutine you can call it like a normal function but it won't run like a coroutine, it'll ignore all the waits and yields and just return at the first return. You have to use StartCoroutine, like you did on Start.
Calling or starting a coroutine in every update is a really bad idea, remove that, don't use Update to start coroutines unless you're sure the "StartCoroutine" will run only once during the coroutine duration. And even if you do that, it's usually a sign of bad architecture on your code.
When you call SetActive on a gameObject, every script attached to it will execute the OnEnable (for SetActive(true)) and OnDisable (for SetActive(false)) methods. You should start the coroutine in OnEnable if you want to turn the spawner on an off by deactivating the spawner. Relying on Update to start/stop something is a bad idea like I said in the previous point. There are cleaner methods though, like adding methods that start and stop the coroutine with a descriptive name and calling those methods, instead of activating and deactivating the entire gameObject. You can stop a coroutine if you store a reference to it. StartCoroutine returns a coroutine, that you can pass later to StopCoroutine to stop it.
You're starting the coroutine in the Start method of EnemyController and deactivating the Spawner in the Start method of IslandPicker. Starting a coroutine and deactivating the object at the same time makes little sense.
I think something like this should work:
using UnityEngine;
using System.Collections;
public class EnemyController : MonoBehaviour {
public GameObject enemy;
public Vector3 spawnValues;
public float spawnWait;
public float startWait;
private Coroutine spawnCoroutine;
public static EnemyController enemycontroller;
void Awake(){
enemycontroller = this;
}
public void StartSpawnWaves() {
if (spawnCoroutine != null)
Debug.LogWarning("Spawner already running");
else
spawnCoroutine = StartCorouitne(SpawnWaves());
}
public void StopSpawnWaves() {
if (spawnCoroutine != null) {
StopCoroutine(spawnCoroutine);
spawnCoroutine = null;
}
}
IEnumerator SpawnWaves(){
yield return new WaitForSeconds(startWait);
while (true) {
Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, Random.Range (-spawnValues.z, spawnValues.z));
Quaternion spawnRotation = Quaternion.identity;
Instantiate (enemy, spawnPosition, spawnRotation);
Debug.Log ("Enemy Spawned!");
yield return new WaitForSeconds (spawnWait);
}
}
}
And in your day/night script...
using UnityEngine;
using System.Collections;
public class IslandPicker : MonoBehaviour {
public GameObject[] Island;
public EnemyController Spawner; //a reference to the spawner script instead of the GameObject
public int CurrentIsland;
void Start () {
for (var i = 0; i < Island.Length; i++) {
Island [i].SetActive (false);
}
}
void OnTriggerEnter(Collider col){
...
if (col.tag == "Night") {
Spawners.StartSpawnWave();
Debug.Log ("Night Has Come!");
}
if (col.tag == "Day") {
Spawners.StopSpawnWave();
Debug.Log ("Day Has Come!");
DestroyAll ("Wraith");
}
}
...
}
Thank you so very much! i was struggling with this for awhile now. Upvoted and checked answered! though i do have one question. can this work with an array? say i have spawners on my islands and when a island turns on is it possible for it to work the same way? i just have to call it right?
I'm not sure what you mean by "can this work with an array"... An array of EnemyController? Well, yes, just change the "Spawners" type to be an array (EnemyController[]), drop the spawners in the inspector like always and ins$$anonymous$$d of:
Spawners.StartSpawnWave();
do:
foreach (EnemyController spawner in Spawners)
spawner.StartSpawnWave();
The same for StopSpawnWave.