Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Running coroutine in 1 frame?

Discussion in 'Scripting' started by Milionario, Jun 30, 2020.

  1. Milionario

    Milionario

    Joined:
    Feb 21, 2014
    Posts:
    138
    Yeah i know, coroutines are meant to be used across frames, to distribute work.

    But.

    I am building a procedural city generator which is too much work to do in just one frame, so I am using coroutines and its nice.
    There are occasions where I would want to run the coroutine instantly such as at the Start of the game.

    Then later I use coroutines normally to build the city little by little.

    Is there a way to do this?
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    Just make your yield conditional:
    Code (CSharp):
    1. if (!runInstantly) {
    2.   yield return null;
    3. }
    You can make
    bool runInstantly
    a parameter of the coroutine.
     
  3. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    You might want to consider refactoring the coroutine so that all of the work is done by submethods that run instantly, and the coroutine is just a scheduler that decides how long to wait between them. Then you can easily write multiple functions with different scheduling (including "no waiting") while keeping the scheduling rules separate from the what-actually-happens procedures.
     
    Yoreki and PraetorBlue like this.
  4. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    265
    Since coroutines in Unity are just C# iterator methods, you are able to manually control their execution. Using this, you can run a coroutine synchronously with a simpe function:
    Code (CSharp):
    1. public static void ExecuteCoroutineSynchronously(IEnumerator coroutine)
    2. {
    3.     while (coroutine.MoveNext())
    4.     {
    5.         if (coroutine.Current is Coroutine)
    6.         {
    7.             // We can't wait on a "Coroutine" object synchronously.
    8.             throw new InvalidOperationException("A coroutine that yields a Coroutine object cannot be executed synchronously.");
    9.         }
    10.         else if (coroutine.Current is IEnumerator enumerator)
    11.         {
    12.             if (enumerator is WaitForSecondsRealtime ||
    13.                 enumerator is WaitWhile              ||
    14.                 enumerator is WaitUntil)
    15.             {
    16.                 // These yield operations implement IEnumerator, so unless
    17.                 // we skip over them, we'll potentially freeze the game while
    18.                 // waiting for them to end. This is not always the case for
    19.                 // WaitWhile and WaitUntil, but they are still skipped here
    20.                 // just to be safe. You can remove those checks if you need
    21.                 // them to still function.
    22.                 continue;
    23.             }
    24.  
    25.             // If we have a nested coroutine, we can just
    26.             // run ExecuteCoroutineSynchronously recursively.
    27.             ExecuteCoroutineSynchronously(enumerator);
    28.         }
    29.     }
    30. }
    You'd use this via ExecuteCoroutineSynchronously(MyCoroutine()).
    Keep in mind that this is a last resort oh-god-I-need-to-release-this-patch situation, it's a much better idea to tweak your code to be callable synchronously without the need to "syncify" a coroutine.
     
    MihaPro_CarX likes this.