Coroutine not starting

I am trying to make a script that fades between scenes. The “fade-in” works just fine, but when I try to fade out, it all breaks down.

Right now, I have the following functions that handle the “fading-out” and the RestartScene() is assigned to a button. Consequently, when the button is pressed, the scene should fade out and reload itself, but it doesn’t. Here is the code:

    public void RestartScene()
    {
        StartCoroutine("Restart");
    }

    public IEnumerator Restart()
    {
        float fadeTime = GetComponent<Fading>().BeginFade(1); //gets the fadingTime and starts the fade
        yield return new WaitForSeconds(fadeTime); //waits for the fade to end
        SceneManager.LoadScene(SceneManager.GetActiveScene().name); //reloads the scene
        Time.timeScale = 1f; //resumes the timeScale (the game is frozen when the button appears)
    }

I tested and the coroutine is not starting AT ALL.

public void RestartScene()
    {
        StartCoroutine(Restart());
    }
    IEnumerator Restart()
    {
        Debug.Log("Restart is running");
        float fadeTime = GetComponent<Fading>().BeginFade(1); //gets the fadingTime and starts the fade
        yield return new WaitForSeconds(fadeTime); //waits for the fade to end
        SceneManager.LoadScene(SceneManager.GetActiveScene().name); //reloads the scene
        Time.timeScale = 1f; //resumes the timeScale (the game is frozen when the button appears)
    }

What’s the coroutine attached to? When you change the scene, it clobbers gameobjects. If the coroutine was attached to a gameobject that got clobbered, it dies.

You’ll need to start the coroutine using a gameobject that’s been marked DontDestroyOnLoad

3 Likes

Did this and the message gets shown in the console, so why isn’t the rest of the code working?

Did that and it’s still not working

run this and lets see where it stops.

public void RestartScene()
    {
        StartCoroutine(Restart());
    }
   
IEnumerator Restart()
    {
        Debug.Log("Restart is running");
        float fadeTime = GetComponent<Fading>().BeginFade(1); //gets the fadingTime and starts the fade
        Debug.Log("fadeTime is set to : " + fadeTime);
        yield return new WaitForSeconds(fadeTime); //waits for the fade to end
        Debug.Log("wait complete");
        SceneManager.LoadScene(SceneManager.GetActiveScene().name); //reloads the scene
        Debug.Log("Scene Load complete");
        Time.timeScale = 1f; //resumes the timeScale (the game is frozen when the button appears)
        Debug.Log("reset time complete");
    }

I managed to fix it. The problem was that I was setting the timeScale to 0 before the yield, so it was going forever. Now, I have another problem :smile:. When I reload the scene, the colliders stop signaling the OnCollisionEnter2D function.

4 Likes

This helped me resolve my issue. I had an object with several child elements. I was trying to destroy all the child elements and then destroy the parent element. I was calling the destroy for the child elements on a coroutine, but for the parent, I was simply calling the destroy function right there.

My coroutine for the child objects wasn’t starting according to the debugger, but when I commented out the line for destroying the parent object, lo and behold! the coroutine started. I’ll probably load the destroy parent in a coroutine as well to make sure the child has time to finish.

I would put a Debug.Log(“Function Run”) in the function o see if you are not calling the function, because the corouine looks fine

This happened to me when Coroutine X in scene B appeared not to start after a script in scene A loaded scene B. The problem was I had a coroutine in Scene A and (unknowingly) with the same name as the coroutine in Scene B. When I made the names different it worked.

2 Likes

Thanks for this! I had the same issue, basically having 2 coroutines with the same name, but in different objects of different types. First one starts, second one starts only in the editor. Coroutines are a joke…

Coroutines are simply a tool. They have very specific uses. They work in very predictable ways. They are not a good solution for somethings things, but not others. In fact most things should NOT be a coroutine.

If you have not yet understood them, here’s some reference links to help you learn.

Coroutines in a nutshell:

https://forum.unity.com/threads/destroying-the-object-then-restarting-the-scene.1044247/#post-6758470

https://forum.unity.com/threads/proper-way-to-stop-coroutine.704210/#post-4707821

Splitting up larger tasks in coroutines:

https://forum.unity.com/threads/best-way-to-split-a-long-running-function-so-its-non-blocking.1108901/#post-7135529

Coroutines are NOT always an appropriate solution: know when to use them!

“Why not simply stop having so many coroutines ffs.” - orionsyndrome on Unity3D forums

https://forum.unity.com/threads/things-to-check-before-starting-a-coroutine.1177055/#post-7538972

https://forum.unity.com/threads/heartbeat-courutine-fx.1146062/#post-7358312

Our very own Bunny83 has also provided a Coroutine Crash Course:

EDIT:
Here’s the new link

1 Like

You should update your “blurp” :slight_smile: UnityAnswers is gone and the redirect doesn’t work. Here’s the new link.

Well, don’t start coroutines with a string. Unity should have removed that long ago. You start coroutines by invoking the actual generator method and then pass it to StartCoroutine. Any kind of string binding comes with tons of potential issues and performance hits. So you’re just using it wrong.

1 Like

Kurt-Dekker , I agree with most of the things that you mentioned, but most people are still using coroutines in Unity for delayed calls because Unity lacks a good timers manager, like Unreal Engine has https://docs.unrealengine.com/5.2/en-US/API/Runtime/Engine/FTimerManager/ . I think a timers manager is quite essential and am surprised Unity doesn’t have one that’s not based on strings (for obvious reasons). Saying coroutines are predictable considering they need to have different name signatures despite them being in 2 separate classes, is a bit of a stretch.

// in the editor, both start, but on an android device only 1 starts

public class ClassA : MonoBehaviour
{
    protected void Start() {
        StartCoroutine(DoSomething());
    }

    private IEnumerator DoSomething()
    { ... }
}

public class ClassB : MonoBehaviour
{
    protected void Start() {
        StartCoroutine(DoSomething());
    }

    // if this is renamed to something else, it works
    private IEnumerator DoSomething()
    { ... }
}

I was not starting them using a string (didn’t even know one could do that), please check the post above. Let me know if there’s something wrong there

I highly doubt that. Coroutines are actually internal compiler generated classes. Calling a coroutine / generator method is nothing different from calling any other method. Though coroutines / generators do not run their code but return a new instance of that internal class which represents your coroutine code as a state machine. It’s highly unlikely that generators from different classes would clash in any way. This is not even Unity related as the yield keyword which is responsible for that is 100% C#. So I would say you misinterpreted your results and your issue is elsewhere.

Note that you can run coroutines on different MonoBehaviours since the actual IEnumerator object that is returned is a closure / object instance which can be run by any active and enabled MonoBehaviour. Maybe you disabled the MonoBehaviour that was running the coroutine which would terminate the coroutine?

You could even run coroutines cross-over. So even this does work:

public class ClassA : MonoBehaviour
{
    public ClassB b;
    protected void Start() {
        StartCoroutine(b.DoSomething());
    }
    public IEnumerator DoSomething()
    { ... }
}
public class ClassB : MonoBehaviour
{
    public ClassA a
    protected void Start() {
        StartCoroutine(a.DoSomething());
    }
    public IEnumerator DoSomething()
    { ... }
}

Here the Start of ClassA would start a coroutine on its own instance but runs coroutine DoSomething from instance b. ClassB on the other hand runs the coroutine DoSomething of “a” on his instance. As I said, the actual “DoSomething” method literally has only one line of code which is a return statement which returns a new instance of the internal statemachine class. It’s very very unlikely that C# would mess that up.

Note that you can write your own IEnumerator classes and pass them to StartCoroutine. Unity doesn’t care what that class is you pass in. As long as it’s implementing the IEnumerator interface it works. That means you can even use a List as “coroutine”, though that would be pretty useless ^^.

List<object> stuff = new List<object> {null, null, new WaitForSeconds(5), null };
StartCoroutine(stuff.GetEnumerator());

This would start a coroutine that first waits 2 frames, then waits 5 seconds and then another frame until it finishes. Of course there’s no code in between the “yields” so it’s completely useless. But it does work anyways.

Whatever your issue was, I’m 99.99% sure it’s not an issue with the coroutine / generator method itself. If the compiler would mess those fundamental things up, nothing would ever work.

So you hijacked this thread for your own different issue? :slight_smile: Because that’s what the OP was about.

Note that you can actually check what each generator returns. Use GetType on the object it returns before passing it to any StartCoroutine call. See the type name of that internal class (which is quite weird as you will see). StartCoroutine doesn’t care and doesn’t even know the name of the generator method. All it gets is the statemachine that was created by the generator method.

IEnumerator obj = DoSomething(); // create statemachine object
StartCoroutine(obj); // hand this instance to Unity to start it as a coroutine.

So the name of the method can’t have an influence here. The string version is different as it can only start coroutines which are defined in the same class. Also you can’t pass arguments to the generator method. The string version in general is a bad idea.

For the future, please start a separate thread and include more details about your issue, how your setup looks like and what your exact results are. Saying “it doesn’t work” is insufficient. I’m also very sceptical about @grahamlynch_1 's statement

1 Like

Ok, I made a simple project and the naming signature doesn’t seem to have any impact, so I was probably doing something else wrong. Sorry for my rant

1 Like

Thanks for the heads-up Bunny!!

Oddly, this link redirects correctly:

https://answers.unity.com/questions/1581543/send-email-with-unity.html

to:

https://discussions.unity.com/t/send-email-with-unity/217895

I’ll have to test the rest of my answers.unity.com linkies…

1 Like