Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
0
Question by backer_s · Jan 05, 2017 at 06:16 PM · coroutinecoroutinescoroutine errors

Why doesn't a coroutine start executing from beginning when I start it again?

I'm working on a simulator projet that has many stages, the execution can be in one and only one stage at a time. I created a coroutine for every stage and created a SwitchManager that switches between stages (coroutines) as needed.

my problem is described in detail as a comment in the right place in the code.

Here's an example code:

StageInfo.cs

 using UnityEngine;
 using System.Collections;
 
 public class StageInfo
 {
     public bool status;
     public IEnumerator Functionality;
     
     public StageInfo(bool status, IEnumerator functionality)
     {
         this.status = status;
         this.Functionality = functionality;
     }
     
 }
 


Main.cs

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 public class Main : Singelton<Main>
 {
     // fields...
     public Machine machine;
     public AudioSource audioSource;
     public NewPlayer player;
     public checklistOne, checklistTwo, checklistThree;
 
     public enum Stage
     {
         Overview,
         ShowChecklistOne,
         TeleportToPositionOne,
         MoveCradle,
         OpenArms,
         RaiseArms,
         MoveSpool,
         LowerArms,
         TeleportToPositionFour,      
         None,
     }
     public SortedDictionary<Stage, StageInfo> stageBox; // the data structure that stores the stages with their status and their coroutines!
 
     private Stage currentStage;
     private IEnumerator currentRoutine;
     public Stage CurrentStage // it lunches the suitable coroutine when you assign a new state
     {
         get { return currentStage; }
         set
         {
             currentStage = value;
             if (currentRoutine != null)
                 StopCoroutine(currentRoutine);
             currentRoutine = stageBox[currentStage].Functionality;
             StartCoroutine(currentRoutine);
         }
     }
 
     // methods & coroutines...
     private new void Awake()
     {
         // initializing stageBox:
         stageBox = new SortedDictionary<Stage, StageInfo>()
         {
             {Stage.Overview,                 new StageInfo(false, Overview()) },
             {Stage.ShowChecklistOne,         new StageInfo(false, ShowChecklistOne()) },
             {Stage.TeleportToPositionOne,    new StageInfo(false, TeleportToPositionOne()) },
             {Stage.MoveCradle,               new StageInfo(false, MoveCradle()) },
             {Stage.OpenArms,                 new StageInfo(false, OpenArms()) },
             {Stage.RaiseArms,                new StageInfo(false, RaiseArms()) },
             {Stage.MoveSpool,                new StageInfo(false, MoveSpool()) },
             {Stage.LowerArms,                new StageInfo(false, LowerArms()) },
             {Stage.TeleportToPositionFour,   new StageInfo(false, TeleportToPositionFour()) },
             {Stage.None, new StageInfo(false, null )},
 
         };
     }
 
     private void Start()
     {
         CurrentStage = Stage.Overview; /*************** ENTRY POINT ***************/
         // this is a property with Set statement that handles coroutine stopping and starting
     }
 
 
     // this method handle the Switch between the different coroutines by stoping one and starting another.
 
     private void ManageSwitch()
     {
         // Switch to the first Stage which status is false
         foreach (Stage s in stageBox.Keys)
         {
             if (stageBox[s].status == false)
             {
                 print("Picked Stage: " + s);
                 CurrentStage = s;
                 return;
             }
         }
         // if all stages are done go to Stage.None:
         currentStage = Stage.None;
     }
 
     /************************************************************************
      *                                                                      *
      *                        STAGES' COROUTINES                            *
      *                                                                      *
      ************************************************************************/
 
     private IEnumerator Overview()
     {
         print("START Overview");
         Highlight.Instance.list.Clear();
         yield return player.FadeIn();
         stageBox[Stage.Overview].status = true;        
         print("END Overview");
         ManageSwitch();
     }
 
     private IEnumerator ShowChecklistOne()
     {
         print("START ShowChecklistOne");
         Highlight.Instance.list.Clear();
         yield return checklistOne.CreateChecklist(new int[] { 0, 1, 2, 3, 4, 38, 39, 40 });
         StartCoroutine(Environment.Instance.ShowMoteAfter(5, checklistOne.moteLocation)); // showing mote after 5 seconds if user didn't interact
         while (true) // waiting for user interaction to move checklist to destionation
         {
             if (Interaction.Instance.GetDown(Interaction.InputButton.Select))
             {
                 yield return checklistOne.MoveToDestination();
                 stageBox[Stage.ShowChecklistOne].status = true;
                 yield return Environment.Instance.HideMoteAndStopShowAfterRoutine();
                 print("END ShowChecklistOne");
                 break;
             }
             else
                 yield return null;
         }
         ManageSwitch();
     }
 
     private IEnumerator TeleportToPositionOne()
     {
         print("START TeleportToPisitionOne");
         Highlight.Instance.list.Clear();
         yield return Environment.Instance.ShowFootPrint(Environment.Instance.footPrintLocations[1]);
         StartCoroutine(Environment.Instance.ShowMoteAfter(5, Environment.Instance.moteLocations[1])); // showing mote after 5 seconds if user didn't interact
 
         while (true)
         {
             if (Interaction.Instance.GetDown(Interaction.InputButton.Select))
             {
                 yield return player.TeleportTo(1);
                 stageBox[Stage.TeleportToPositionOne].status = true;
                 // hidiing Environment objects:
                 Environment.Instance.HideFootPrint();
                 yield return Environment.Instance.HideMoteAndStopShowAfterRoutine();
                 print("END TeleportToPositionOne");
                 break;
             }
             else
                 yield return null;
         }
         ManageSwitch();
     }
 
     private IEnumerator MoveCradle()
     {
         print("START MoveCradle");
         machine.cradleHologram.SetActive(true); // showing hologram
         Highlight.Instance.Unhighlight();
         Highlight.Instance.list.Add(machine.cradle.gameObject);         // highlighting mainConsole's buttons & the cradle:
         foreach (Button button in machine.mainConsole.buttonsArray)
             Highlight.Instance.list.Add(button.gameObject);
         Highlight.Instance.HighlightObjects();
 
         while (true)
         {
             machine.mainConsole.ShowElementOnButton(machine.mainConsole.cradleRightButton, 0);  // showing text
             Interaction.Instance.EnableMainConsole(true); // Enabling interaction for MainConsole
             if (machine.cradle.isInRightDestination) // success...
             {
                 machine.cradleHologram.SetActive(false);
                 machine.mainConsole.RemoveElementAndMarker();
                 Highlight.Instance.Unhighlight();
                 checklistOne.CheckElement(0);
                 stageBox[Stage.MoveCradle].status = true;
                 print("END MoveCradle");
                 break;
             }
             else
                 yield return null;
         }
         ManageSwitch();
     }
 
     private IEnumerator OpenArms()
     {
         print(" START OpenArms");
         
         while (true)
         {
             if (!CheckMoveCradle()) 
             // the problem is when CheckMoveCradle() returns false...
 
             /* CheckMoveCradle will turn stageBox[Stage.MoveCradle].status to 
              * false and return false. 
              * That breaks the while loop and call the ManageSwitch() which in
              * turn will stop the current running coroutine and switch
              * the execution to MoveCradle coroutine. HERE'S MY PROBLEM!!! 
              * (note: by this time, MoveCradle() coroutine is being executed
              *  for the second time, not first!).
              * When StartCoroutine(MoveCradle()) is called from inside 
              * ManageSwitch(), it doesn't start a new instance of the coroutine,
              * or start executing it from beginning (as I understand it should do!!!), 
              * instead it just enter the coroutne at its last line, do nothing but
              *  return to the 
              * caller method (ManageSwitch()) even though there's no Yield the the end.
              * My Question is why doesn't it start executing MoveCradle() 
              * coroutine from beginning?!
 
              */
                 break;
             
             if (machine.armRig.armsDistance >= machine.armRig.warningDistance) // success...
             {
                 machine.armRig.leftArmHologram.SetActive(false); // hiding holograms
                 machine.armRig.rightArmHologram.SetActive(false);
                 machine.mainConsole.RemoveElementAndMarker();
                 Highlight.Instance.Unhighlight();
                 checklistOne.CheckElement(1);
                 stageBox[Stage.OpenArms].status = true;
                 print("END OpenArms");
                 break;
             }
             else
                 yield return null;
         }
         ManageSwitch();
     }
 
 
     /************************************************************************
      *                                                                      *
      *                             Check methods                            *
      *                                                                      *
      ************************************************************************/
 
     private bool CheckMoveCradle()
     {
         if (machine.cradle.isInRightDestination)
         {
             stageBox[Stage.MoveCradle].status = true;
             return true;
         }
         else
         {
             stageBox[Stage.MoveCradle].status = false;
             checklistOne.UncheckElement(0);
             return false;
         }
     }
 }
 



Comment
Add comment · Show 2
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 KoenigX3 · Jan 05, 2017 at 06:36 PM 0
Share

The code executes as it is written. The Start() function calls the first coroutine, which stops executing after the 5th time, and calls the second coroutine. The second coroutine executes 3 times, then it stops executing, and calls the first coroutine - which is an infinite loop.

I don't see any problems with this code, unless you wanted to do something else. Are you trying to pause the first coroutine, and continue it after the second coroutine is finished? Or the only problem is that the first coroutine gets called again, and because of that there is an infinite loop?

avatar image backer_s KoenigX3 · Jan 10, 2017 at 03:10 PM 0
Share

Thanks for your answer! the problem is actually quite different. I realized that the example I posted doesn't reflect the actual problem I'm facing, so I posted the actual code I'm working on..

1 Reply

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

Answer by Bunny83 · Jan 06, 2017 at 12:39 AM

Coroutines are not threads. Coroutines can only be interrupted (which includes "stopping") at a yield statement.

So when a coroutine tries to "stop" itself, it will be stopped at the next yield statement because that's the point where you actually yield the control back to the coroutine scheduler.

Also you need to be careful. When you start a coroutine, the StartCoroutine call will immediately execute the started coroutine up to the first yield before it actually returns. So a construct like this will cause a stackoverflow / crash:

 IEnumerator R1()
 {
     StartCoroutine(R2());
     yield return null;
 }
 
 IEnumerator R2()
 {
     StartCoroutine(R1());
     yield return null;
 }


However the following would work as StartCoroutine will return and finish the calling coroutine:

 IEnumerator R1()
 {
     yield return null;
     StartCoroutine(R2());
 }
 
 IEnumerator R2()
 {
     yield return null;
     StartCoroutine(R1());
 }

Though starting and stopping coroutines quickly is not a good idea as each new coroutine will create garbage. Coroutines are not "methods" but auto-generated classes and when you "start" one you actually create an instance of that class.

If you have trouble understanding how coroutines work, i suggest reading this blog article. Unfortunately the blog doesn't exist anymore so i linked a cached version.

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 backer_s · Jan 10, 2017 at 02:58 PM 0
Share

I would like to thank you for your clear and detailed answer! Actually I had to post the actual code from beginning because it's hard to explain the problem on an example code.

I have updated the question and posted the actual code I'm working on. I have descried the problem I'm facing in detail as a comment in the right place in the code.

Your help is really appreciated!

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

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

Coroutine Won't Stop Using IEnumerator 1 Answer

Multiple coroutine exicution order 1 Answer

Coroutine only fires once instead of looping until stopped. 2 Answers

StopAllCoroutines not working 0 Answers

Had difficulties implementing intro to Coroutines from unitypatterns.com. Help? 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