Search Unity

Invoke with a Coroutine

Discussion in 'Scripting' started by hassank, Nov 1, 2016.

  1. hassank

    hassank

    Joined:
    Nov 18, 2015
    Posts:
    48
    Does anyone know how Invoke can be used to start a Coroutine? I've tried without success and want to know since I need a delay before starting a Coroutine. An alternative is to delay at the start of the Coroutine but I am curious why Invoke hasn't worked with Coroutines.
     
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    First off if you have an IEnumerator SomeCoroutine, you can't call it directly yourself. You need to use StartCoroutine(SomeCoroutine). Invoke can't handle paramaters. You can only use it to call a method with no paramaters. So to start your Coroutine you'd need to Invoke on StartCoroutine with the paramater of SomeCoroutine which you can't do. There are lots of hoops and ways to get around this, but its much easier to just add a delay to your Coroutine. You can even make it so it has a default delay of 0, so you can call it normally without the delay like this:

    Code (CSharp):
    1. IEnumerator SomeCoroutine(float delay  = 0.0f)
    2. {
    3.        if (delay != 0)
    4.            yield return new WaitForSeconds(delay);
    5.         // The rest of your coroutine here
    6. }
    You could call it with or without a delay like this:
    Code (CSharp):
    1. void Start()
    2. {
    3.        StartCoroutine(SomeCoroutine());
    4.        StartCoroutine(SomeCoroutine(5f));
    5. }
     
  3. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    I would avoid MonoBehaviour.Invoke. I don't understand why Unity would let people use a string to start a method, or encourage it, but this way of starting a method seriously just shouldn't exist. Use delegates, or get an object reference, or something else.
     
    hassank likes this.
  4. hassank

    hassank

    Joined:
    Nov 18, 2015
    Posts:
    48
    Thanks for the explanation @takatok and I agree @Dameon_. The signature of Invoke is really odd. I like the concept but not the use of a string.
     
  5. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
  6. RomanB205

    RomanB205

    Joined:
    Jun 24, 2015
    Posts:
    5
    Hey there! I also happen to love coroutines, so I made an extension method that invokes the coroutine after a certain amount of time. Here's the snippet :

    Code (CSharp):
    1.  
    2.     /// <summary>
    3.     /// Makes a coroutine that invokes the coroutine after x seconds.
    4.     /// </summary>
    5.     /// <param name="coroutine">The coroutine to be invoked</param>
    6.     /// <param name="seconds">the amount of time awaited before invoking the coroutine.</param>
    7.     public static IEnumerator After(this IEnumerator coroutine, float seconds)
    8.     {
    9.         yield return new WaitForSeconds(seconds);
    10.         yield return coroutine;
    11.     }
    Feel free to add this to your utility classes!
     
    AnteNomspa, gamerr91 and djweaver like this.
  7. djweaver

    djweaver

    Joined:
    Jul 4, 2020
    Posts:
    105
    @RomanB205 you should check out the More Effective Coroutines the asset store (there is a free version but I have pro)

    You can do all kinds of cool stuff like using them without monobehaviours, assigning groups and layers to pause/cancel/resume specific ones at-will. And on top of that, they are wickedly faster than unity coroutines. For better or for worse I'm addicted and have replaced all my update loops with them and I don't see this changing anytime soon.
     
    AnneAtMarel likes this.
  8. RobertJamesIV

    RobertJamesIV

    Joined:
    Aug 24, 2023
    Posts:
    2
    Hmm kind of a necro post but you know you can just setup a function to handle the invoke then setup an IEnumerator to be handled by the function. It's a little more code but allows for greater control of the IEnumerator in case you wanted to run safe code before the coroutine, Since it's extremely dangerous to run or change code already being run by a coroutine so you could have a void change the variable in between loops based on other data, I mean it's code right so there is a billion ways to do it but I just posted because there is nothing wrong with Invoke and you can just do so easily.

    Invoke is essentially just the same as a delegate :3 the added wait time is helpful

    Another bonus is you can hard feed the coroutine data as a parameter from the function after it gets invoked to make sure the data the coroutine is receiving is never wrong. Since even a small slight error in a coroutine can be dangerous and lead to memory leaks.

    Code (CSharp):
    1. private void Initializer()
    2. {
    3.   ImprovedStart("HelloWorld");
    4. }
    5.  
    6. private void ImprovedStart(string name)
    7. {
    8.      Invoke(name, 0f);
    9. }
    10.  
    11. private void HelloWorld()
    12. {
    13.      Debug.Log("I was invoked, Hi World");
    14.  
    15.      StartCoroutine(HelloWorldCor());
    16. }
    17.  
    18. private IEnumerator HelloWorldCor()
    19. {
    20.      Debug.Log("Let's randomly wait for ten seconds");
    21.      yield return new WaitForSecondsRealtime(10f);
    22.      yield break;
    23. }
    There is lot's of ways you can do so
     
    Last edited: Aug 27, 2023