Coroutine couldn't be started because the the game object is inactive!

Hi everyone,

I have a problem about instantiated object’s instance reference.
I have 2 script which names are EnemyController.cs and EnemyAttack.cs.

I am instantiating objects every x seconds and calling method from EnemyAttack.cs with instance reference in EnemyController.cs

Red object instantiated with my code. Error says the yellow object is not active even though I instantiated the red object.

Error is:
Coroutine couldn’t be started because the the game object ‘Zombie_0(Clone)’ is inactive!
UnityEngine.MonoBehaviour:StartCoroutine (System.Collections.IEnumerator)

Sample code here:

EnemyController.cs

public class EnemyController : MonoBehaviour
{
    private EnemyAttack enemyAttack;

    private void Start()
    {
        enemyAttack = EnemyAttack.instance;
    }

    private void StateExecute()
    {
        enemyAttack.Attack(); // not working
        // GetComponent<EnemyAttack>().Attack(); --> this works.
    }
}

EnemyAttack.cs

public class EnemyAttack : MonoBehaviour
{
    public static EnemyAttack instance;

    private void Awake()
    {
        instance = this;   
    }

    public void Attack()
    { 
        // do some works
        StartCoroutine(AttackRoutine());
    }
}

Did you Instantiate() the prefab properly? If not, then it is just lying as a disk asset and cannot run coroutines. It has to be either Instantiate-d into the scene, or already exist in scene to run coroutines.

I’m instantiating to pool with this method.

    public void CreateObjectToPool()
    {
        pooledObjects = new    List<GameObject>();
        GameObject tmp;

        for (int i = 0; i < amountToPool; i++)
        {
            tmp = Instantiate(objectToPool);
            tmp.SetActive(false);
            pooledObjects.Add(tmp);
        }
    }

// Getting from pool

private IEnumerator SpawnRoutine()
    {
        while (isSpawning == true)
        {
            yield return new WaitForSeconds(spawnCountDown);

            GameObject enemy = EnemyPool.instance.GetPooledObject();
            if (enemy != null)
            {
                int selectedSpawner = Random.Range(0, 2);
                Transform spawner   = selectedSpawner == 0 ? leftSpawner : rightSpawner;

                enemy.transform.position = spawner.position;
                enemy.transform.rotation = spawner.rotation;

                enemy.SetActive(true);
            }
        }
    }

Are you doing the coroutine before doing .SetActive(true);?

Find out with Debug.Log()

You could also give active and inactive objects different names when you turn them on and off, then print their names.

tmp.SetActive(false);
tmp.name = "I'm Asleep";

and

tmp.SetActive(true);
tmp.name = "I LIVE!";

which can help you print out names.

I change the names to “zombie 0”, “zombie 1” … “zombie 49” when object actived. Seems like script referring inactive object. Zombie 0 activated but it says “Coroutine couldn’t be started because the the game object ‘zombie 49’ is inactive!”.

I activated to zombie 49 from inspector, code starts work without error.

The screen shot you show is an inactive object.

What exactly are you expecting to change until you activate it?

Activate it in code with .SetActive(true) before you try starting any coroutines on it.

I’m not sure how much clearer I can state it.

1 Like

Here is a short video :
https://www.youtube.com/watch?v=39lteT4Vcbs

My script should work for zombie 0 but it works for zombie 49.

Heh, okay - a few things falling into a language gap here :slight_smile:

When you say it “should work for zombie 0 but it works for zombie 49” , what you mean is “It should be starting the coroutine on zombie 0 (the active one) but instead it is trying to start it on zombie 49 (the inactive one)”

Here is why that is happening:

You are attempting to pass the EnemyAttack component of the most recently spawned zombie to its own EnemyController component by storing it in a static variable on Awake and reading it in Start. This is a terrible, terrible idea for a number of reasons, this bug included. In particular, it is guaranteed to go wrong if you ever spawn two zombies at once.

But anyway, back to this bug.

When you instantiate an active GameObject, or a prefab that contains an active gameobject (so it’s ticked as active when you examine the prefab), both Awake() and OnEnable() will be called before you get a chance to set it inactive.

I tested that myself with a simple script that logs out Awake, OnEnable and Start. Here’s the code that spawns it:

  GameObject go = GameObject.Instantiate(thing);
  go.SetActive(false);

And here’s the debug output from ‘thing’:

8084276--1045403--upload_2022-4-28_0-28-7.png

This means that all 50 zombies set the static instance variable to their personal EnemyAttack component in turn, and then it stays that way until you wake a zombie up.

At that point, Zombie 0 grabs the static instance (now containing Zombie 49’s EnemyAttack component) as its own and a few seconds later tries to use it.

The fix is simple: never, ever use this way of passing components around other than for singletons. Either add a public ‘attack’ field to EnemyController and drag the EnemyAttack into it (best) or use GetComponent() (slower, but still okay).

Also: If your intention is to have things spawn in inactive, make sure that they are inactive in the prefab you’re spawning from, otherwise Awake and OnEnable will be called prematurely.

1 Like

Poor english problems. :frowning:

Oh I see thanks for explantion. it helped a lot. :slight_smile:

hi… i was wondering if you could help me with this and im using the prefab as the game object btw and its active nut its gives me the same error!
and also the coroutine is from another script but im calling it from the first script

8397891--1108548--Screenshot 2022-08-29 011149.jpg