- Home /
How to prevent a script on a disabled object from firing?
I am making a simple level system for my game. There is a LevelManager class attached to an empty object with 3 animated spawners childed to it. When the game starts the child spawners are all disabled. When the first wave begins a random spawner is enabled. The spawner carries out it's animation and a script attached to it fires off projectiles randomly. When the level is over, all children are disabled like this:
foreach(Transform child in transform)
child.gameObject.SetActive(false);
I can see in the editor that they are all disabled, I assign all the spawners a color and they only appear when a spawner is activated. When the next wave starts, a new random spawner will activate. The problem is that the original spawner from the previous wave begins to fire projectiles. I can see that spawner is disabled in the editor, and it's not animating, but a steady stream of random projectiles continues to fire our in a straight line from it's parked position. It's clear the deactivated spawner is both disabled and parked at it's origin and that the script attached to it is firing..
So how do you tell a GameObject that has been deactivated to not fire off it's scripts? Why does it still fire them when disabled? Below is the code I use to activate and deactivate the spawners.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class LevelManager : MonoBehaviour {
public List<Transform> spawners;
public float levelLengthTime = 45.0f;
public GameManager gameManager;
// Use this for initialization
void Start () {
spawners = new List<Transform>();
foreach(Transform child in transform)
{
child.gameObject.SetActive(false);
spawners.Add(child);
}
}
void StartWave()
{
foreach(Transform child in transform)
child.gameObject.SetActive(false);
int spawnerToEnable = Random.Range(0, spawners.Count);
spawners[spawnerToEnable].gameObject.SetActive(true);
Invoke("StopWave", levelLengthTime);
}
void StopWave()
{
foreach(Transform child in transform)
child.gameObject.SetActive(false);
gameManager.SendMessage("PrepareForNextWave");
}
}
Also, if it helps, here is the script attached to the spawners themselves. This is the script that is firing even after the spawner is disabled:
public class SpawnMissiles : MonoBehaviour {
public GameObject projectileToLaunch;
public float delay = 1.0f;
public int numberToSpawn;
private int enemyCount;
private int spawnCounter;
// Use this for initialization
void Start ()
{
enemyCount = numberToSpawn;
Invoke("Spawn", Random.Range(0.1f, delay));
}
void Spawn()
{
enemyCount--;
GameObject instance = Instantiate(projectileToLaunch, transform.position, transform.rotation) as GameObject;
instance.transform.SetParent(transform.parent, true);
if (enemyCount > 0)
Invoke("Spawn", Random.Range(0.1f, delay));
}
// Update is called once per frame
void Update ()
{
}
}
I think it's because you're using Invoke. Once you've made a call to Spawn(), that call itself generates the next call, and so on. $$anonymous$$aking a component/object inactive doesn't prevent its functions being called so, unlike things like calls to Update() and Coroutines, your self-invocation idiom doesn't need the object to be active.
So, ins$$anonymous$$d you could make Spawn() into a Coroutine, with the delay implemented using WaitForSeconds, and with the Coroutine starting itself as its final action.
That way, when the object is deactivated the spawning will stop, because the Coroutine will be killed.
Another way would be for the Spawn() function to check that the gameobject is active and get it to quit if the object isn't active (the critical part being to make sure that it doesn't Invoke another Spawn() call).
You could also use OnEnable() and OnDisable() to manually enable/disable Invokes.
Ah yes, or even just call CancelInvoke on the objects as well as (or ins$$anonymous$$d of) deactivating them.
Thanks. These methods are unfamiliar to me. I'm sure CancelInvoke() will do the trick.
I added Invoke() under OnEnable() and CancelInvoke() under OnDisable() and it works as expected now. Thanks to you both.