Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
9
Question by useless.unity.user · Mar 16, 2012 at 02:21 PM · coroutinewaithold

Hold or Wait while Coroutine finishes

In the example below, how can I get FinishFirst() to complete first before running DoLast(), while still retaining the 'public void StartPage()' signature?

I'm trying to avoid making "StartPage()" return an IEnumerator as that would force me to change it in the interface. It would be great if my Interface for StartPage() supported both IEnumerator and Void without needing to implement both.

 public void StartPage()
 {
 
     print("in StartPage()");
     StartCoroutine(FinishFirst(5.0f));
     DoLast();
     print("done");
 
 }    
 
 IEnumerator FinishFirst(float waitTime)
 {
 
     print("in FinishFirst");        
     yield return WaitForSeconds(waitTime);
     print("leave FinishFirst");
 }    
 
 void DoLast()  
 {  
     print("do after everything is finished");  
 }

Comment
Add comment · Show 3
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Eric5h5 · Mar 16, 2012 at 02:40 PM 1
Share

In the future, please format your code with the code button. It takes 2 seconds.

avatar image useless.unity.user · Mar 19, 2012 at 03:36 AM 0
Share

sorry for that, actually I was looking for the "code" format button but didn't recognize it...will keep that in $$anonymous$$d, thanks.

avatar image Fattie · Jul 12, 2018 at 06:06 PM 0
Share

All the answers here other than Eric's are totally wrong.

6 Replies

· Add your reply
  • Sort: 
avatar image
19
Best Answer

Answer by Eric5h5 · Mar 16, 2012 at 02:40 PM

You would need to do "yield return StartCoroutine..." and have StartPage return IEnumerator. StartPage cannot return void in this case.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image dimitris_baud · Jan 30, 2020 at 05:20 PM -1
Share

THIS is the only answer to this question!

avatar image
46

Answer by Nition · Aug 02, 2013 at 12:21 AM

I know this is an old question but the popular answer is wrong. It's using two Coroutines, DoLast is constantly checking to see if FinishFirst is done, and even then there'll be up to a 100ms delay after FinishFirst completes before DoLast is called.

Why not just call DoLast at the end of FinishFirst? If you don't know what method will need to be called at the end, you can pass it as an Action parameter:

 public void StartPage() {
     print("in StartPage()");
     StartCoroutine(FinishFirst(5.0f, DoLast));
 }
 
 IEnumerator FinishFirst(float waitTime, Action doLast) {
     print("in FinishFirst");
     yield return new WaitForSeconds(waitTime);
     print("leave FinishFirst");
     doLast();
 }
 
 void DoLast() {
     print("do after everything is finished");
     print("done");
 }
Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Eric5h5 · Aug 02, 2013 at 01:07 AM 6
Share

You can yield on FinishFirst, as I mentioned (but unfortunately did not elaborate on) in my answer. That would be the simplest and most flexible method.

 public IEnumerator StartPage() {
     print("in StartPage()");
     yield return new StartCoroutine(FinishFirst(5.0f));
     DoLast();
 }
 
 IEnumerator FinishFirst(float waitTime) {
     print("in FinishFirst");
     yield return new WaitForSeconds(waitTime);
     print("leave FinishFirst");
 }
 
 void DoLast() {
     print("do after everything is finished");
     print("done");
 }
avatar image Nition · Aug 02, 2013 at 01:10 AM 0
Share

The reason I didn't take that road was that in the original question he says "I'm trying to avoid making "StartPage()" return an IEnumerator as that would force me to change it in the interface." Otherwise yeah, that's the most logical.

avatar image Eric5h5 · Aug 02, 2013 at 01:15 AM 1
Share

Good point.

avatar image Rambit · May 08, 2014 at 05:16 PM 1
Share

Just a quick note for other people using this solution:

Do

yield return StartCoroutine (FinishFirst(5.0f));

I got an error when having new between return and StartCoroutine. I now see that Eric5h5 have posted this in the answer below...

avatar image
12

Answer by PaxNemesis · Mar 16, 2012 at 02:47 PM

You could either call DoLast() after the yield in the FinishFirst function or you could make DoLast a coroutine too with a loop that yields while the FinishFirst coroutine is running.

Something like:

 bool inFirst = false;
 
 public void StartPage() {
  
    print("in StartPage()");
    StartCoroutine(FinishFirst(5.0f));
    StartCoroutine(DoLast());
    print("done");
 }
 
 IEnumerator FinishFirst(float waitTime) {
    inFirst = true;
    print("in FinishFirst");        
    yield return new WaitForSeconds(waitTime);
    print("leave FinishFirst");
    inFirst = false;
 }
 
 IEnumerator DoLast() {
 
    while(inFirst)       
       yield return new WaitForSeconds(0.1f);
    print("Do stuff.");
 }
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image useless.unity.user · Mar 19, 2012 at 03:54 AM 0
Share

thanks pax it halfworks, it will run whatever I put after the yield in DoLast() after FinishFirst(), but I also wanted to main StartPage() to hold as well (sorry I didn't state that). There is, as expected, a bit of concurrency with FinishFirst() and DoLast() (hence the statements needing to be put after the yield) that I was hoping to avoid...and I think that needing to use two StartCoroutines in this manner may be indicative of a redesign anyway. $$anonymous$$y appreciation for the answer, i still learned something!

avatar image PaxNemesis · Mar 19, 2012 at 11:58 AM 0
Share

If you want to hold the StartPage function you have to make that a coroutine too. And there yield where you want.

avatar image
3

Answer by baddie · Jun 25, 2017 at 10:00 PM

Here's a simple extension class I wrote that adds a callback to UnityWebRequest.Send.

     public static class NetworkingUtils
     {
         public static void Send(this UnityWebRequest request, MonoBehaviour behavior, Action onFinished)
         {
             behavior.StartCoroutine(routine(request,onFinished));
         }
         
         private static IEnumerator routine(UnityWebRequest request, Action onFinished)
         {
             yield return request.Send();
             if (request.isError)
                 Debug.LogError(request);
             else
             {
                 Debug.Log("Results for " + request + ":\n" + request.downloadHandler.text);
                 onFinished();
             }
         }
     }

Then you can use it by passing an action in to Send that will get called on completion. You'll also need to stick in a Monobehaviour so the coroutine works.

 request.Send(monoBehavior, ()=>print("Done"));

You'll probably want to modify it to do more with errors (a different callback perhaps).

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by 5argon · May 24, 2017 at 11:29 AM

Much late, but if you want to check if a coroutine had finished or not instead of waiting and then run the next code sequentially, other than the obvious way of declaring an additional boolean flag you can use setup the IEnumerator type variable instead of doing StartCoroutine( on the method directly. (Which is the same, since the method returns IEnumerator.

This variable is useful for StopCoroutine, but if you set that variable to null at the end of the coroutine it can doubles as a way to check if a coroutine ended or not by null checking it.

I use this so players cannot input while the story is advancing. For example, defines :

 private IEnumerator advanceStoryDelayRoutine;
 IEnumerator AdvanceStoryDelayRoutine()
 {
     yield return new WaitForSeconds(3.5f);
     advanceStoryDelayRoutine = null;
 }

When using it

         //this check is necessary for the first time or StopCoroutine will stop to nothing, resulting in a run time error
         if(advanceStoryDelayRoutine != null) 
         {
             StopCoroutine(advanceStoryDelayRoutine);
         }
         advanceStoryDelayRoutine = AdvanceStoryDelayRoutine();
         StartCoroutine(advanceStoryDelayRoutine);

And then the input code can check against this variable

     if(advanceStoryDelayRoutine != null)
     {
         //still hasn't finished yet
     }
Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image aditya007 · May 24, 2017 at 11:46 AM 0
Share

Doesn't WaitForSeconds only take float as an argument?.

avatar image 5argon aditya007 · May 24, 2017 at 11:50 AM 0
Share

Yeah, sorry. That advanceStoryDelayTime was defined out of pasted code. That variable is indeed a float type. Edited to constant value.

avatar image Nition · May 24, 2017 at 09:02 PM 0
Share

Yeah good answer, I've used that same system quite often. Worth noting that you do have to set the coroutine you've assigned manually back to null after the coroutine is done (which you've done in your example, it's just good to mention for others) - it doesn't go back to null automatically when it's over.

  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

17 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Waiting for input using yield and coroutines 1 Answer

How to wait in editor with EditorApplication.update 0 Answers

Ienumerator wait for event 0 Answers

Wait until movment animation ends 0 Answers

Can't return a string after value is true in coroutine 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges