StartCoroutine can't be called from a GameObject. Am I late to this party?

I recently realized that I can’t call StartCoroutine from a gameObject. Instead, I need a reference to a monobehaviour that is attached to the desired game object.


When was this API changed made? I particularly dislike it for two main reasons.

  1. Coroutines are bound to gameObjects, not monobehaviours. Disabling the monobehaviour that started the coroutine won’t affect the coroutine at all. Disabling the gameObject does.

  1. If I want to start a coroutine from a reference to a gameObject other than the current, I have to either a) hope that gameObject already has a monobehaviour, or B) add a new dummy monobehaviour myself. This can be annoying if the referenced gameObject isn’t always the same. Creating mono behaviours may trigger garbage collection.

So, why doesnt the API just let us do
GameObject go; go.StartCoroutine( coroutine()) ;


Having to find (or create) a mono behaviour on the reference gameObject is almost as nonsensical as having to find (or create) a monobehaviour to activate or deactivate a gameobject.

There hasn’t been a change of the API. You were never able to run a coroutine on a GameObject. Coroutines run on the MonoBehaviour instance of which you use StartCoroutine. Your conclusions based on your observations are actually wrong.

First of all the “enabled” state of a MonoBehaviour only controls if FixedUpdate, Update, LateUpdate, OnGUI are called or not. All other callbacks still work fine when the script is “disabled”. That includes coroutines. So disabling a MonoBehaviour won’t have an effect on running coroutines and won’t prevent you from starting new coroutines.

Try running a coroutine on a MonoBehaviour instance and destroy only the MonoBehaviour instance. The coroutine will be removed as well, even the gameobject is still there.

Deactivating a GameObject on the other hand will “remove” the gameobject from the whole scene. Not in the sense of wiping out the memory but it will have no interactions with any other gameobject. From the scene’s point of view the gameobject doesn’t exist. Deactivated gameobjects won’t receive any messages by Unity and it does cancel running coroutines. Also if you try starting a coroutine on a script of a deactivated gameobject you will get an error that says:

Coroutine couldn’t be started because
the the game object ‘XXX’ is inactive!

So nothing has changed and it still works the same as in Untiy version 2.6 (where i started using Unity).

GameObjects are just containers. They don’t have any functionality themselfs. It’s the components which adds behaviour and other things. A GameObject is only responsible for providing:

  • a container for Components
  • provide fundamental state informations of the object such as: name, tag, layer, containing scene, static flag and the active state.
  • An API to access and add components
  • An API to send messages to attached components.

A Gameobject doesn’t even have a position. That’s handled by the Transform component (which however is always with a GameObject).

I’m not sure what you mean by “can’t call StartCoroutine from a gameObject”. Of course you can. Yes, the GameObject has to have a MonoBehaviour in which to do it. “Having to create a MonoBehaviour on the gameObject,” doesn’t make sense to me. Without a MonoBehaviour, a GameObject has no behaviour and can only be manipulated by other behaviours. MonoBehaviours are how we get GameObjects to do stuff, it’s hardly a restriction.

Or is it just that you’ve just got the code wrong? From one MB you can start a coroutine in another, but you do it using

ComponentType c = go.GetComponent<ComponentType>();
StartCoroutine(c.coroutine());

Being able to do this gives us more control options (the coroutine dies with the calling object).

I appreciate I may be missing something. If so, maybe a bit more code and a fuller description of your intended set-up might help.

[Edit] See comments below for further discussion of the situation including answers to my questions and resolution.

Also, while this accepted answer and thread deals with the “what are you even trying to do here and why?” side of things, and resolves it, the other answer by Bunny83 correctly addresses the “change of API” aspect of the question.