Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Start Coroutine after Stopping it ...

Discussion in 'Scripting' started by AhmadIssawi, Jun 23, 2018.

  1. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    Hi every body...
    i want to start a Coroutine after i stopped it ... but it does Not start ...
    in fact, i want to do :

    Start Coroutine-1

    // if user push aButton-2
    {
    Stop Coroutine-1
    Start Coroutine-2
    }

    // if user push aButton-1
    {
    Stop Coroutine-2
    Start Coroutine-1
    }

    But, when i stop a Coroutine, i can Not start it after that ...

    Thank you for any help ...
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,292
    You need to store reference to the coroutine when you're trying to stop/start it.
    Code (CSharp):
    1. private Coroutine _coroutineOne;
    2. private Coroutine _coroutineTwo;
    3.  
    4. public void ButtonPressPushAB2(){
    5.     if (_coroutineOne != null) {
    6.         StopCoroutine(_coroutineOne);
    7.         _coroutineOne = null;
    8.     }
    9.  
    10.     _coroutineTwo = StartCoroutine(CoroutineTwo());
    11. }
    12.  
    13. private void ButtonPressAB1(){
    14.     if (_coroutineTwo != null) {
    15.         StopCoroutine(_coroutineTwo);
    16.         _coroutineTwo = null;
    17.     }
    18.  
    19.     _coroutineOne = StartCoroutine(CoroutineOne());
    20. }
    21.  
    22. private IEnumerator CoroutineOne(){
    23.    yield return null;
    24. }
    25.  
    26. private IEnumerator CoroutineTwo(){
    27.    yield return null;
    28. }
    Note that stop means stop. Not paused.
     
    Ryiah, Doug_B and AhmadIssawi like this.
  3. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    First : thank you for your Detailed Answer...
    Next : i followed your clear instructions, but unfortunately : i got the same problem ... each time i stop a coroutine, i can no longer start it later ...
    Here what i wrote :

    private Coroutine CoroutinePedalDown, CoroutinePedalUp;
    private IEnumerator PedalDownJob, PedalUpJob;


    // in the convenient place...
    if(CoroutinePedalUp != null) { print("1");
    StopCoroutine(CoroutinePedalUp);
    CoroutinePedalUp = null;
    }
    CoroutinePedalDown = StartCoroutine(PedalDownJob);

    // in the convenient place...
    if(CoroutinePedalDown != null) { print("2");
    StopCoroutine(CoroutinePedalDown);
    CoroutinePedalDown = null;
    }
    CoroutinePedalUp = StartCoroutine(PedalUpJob);


    public IEnumerator PedalDownJob(Args...) { print("PedalDownJob is Called");
    // other code...
    }
    public IEnumerator PedalUpJob(Args...) { print("PedalUpJob is Called");
    // other code...
    }
    When i run the code and start doing the actions (button-1 then Button-2 etc...) , the console write :



    PedalDownJob is Called
    2
    PedalUpJob
    1

    and he stops writing any more .... then, he can not call any job...

    thanks again...
     
  4. santiagolopezpereyra

    santiagolopezpereyra

    Joined:
    Feb 21, 2018
    Posts:
    91
    You could use getters and setters.

    Code (CSharp):
    1.     private bool routineStopped;
    2.  
    3.     private bool RoutineStopped {
    4.         get{
    5.             return routineStopped;
    6.         }set{
    7.             routineStopped = value;
    8.             if (value){
    9.                 StopCoroutine("MyCoroutine");
    10.                 StartCoroutine("MyCoroutine");
    11.             }
    12.         }
    13.     }
    14.  
    15.     private IEnumerator MyCoroutine () {
    16.         dostuff;
    17.         something;
    18.         RoutineStopped = true;
    19.     }
    This way, when you set RoutineStopped to true, it will call StopCoroutine() and then StartCoroutine().
     
    AhmadIssawi and TaleOf4Gamers like this.
  5. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    i know of course .... stop = stop .... but the problem that the code understands : stop = Kill !!! :(
     
  6. santiagolopezpereyra

    santiagolopezpereyra

    Joined:
    Feb 21, 2018
    Posts:
    91
    I have tested the getters and setters solution and it works. Have you tried it?
     
    AhmadIssawi likes this.
  7. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    I dont think that the problem is inside the works of coroutines rather in the code that is inside those functions. Where is the return inside your functions? Should not there be one?
     
    AhmadIssawi likes this.
  8. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    i Hope that you find the error in this ...
     

    Attached Files:

  9. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Thats not the full code is it?
     
    AhmadIssawi likes this.
  10. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48

    Dear santiagolopezpereyra Thank you first for your help ...
    Unfortunately i did not try, for 2 reasons :
    1- i did not understand the code completely (i am familiar with the type of VergilUa code more than the getters and setters)
    2- i saw that you put the stop at the end of the auction code .. in fact the problem is that :
    When user pushes Button-1 the IEnumenator-1 must start working, and when the user pushes Button-2 (Maybe DURING working and before ending) IEnumenator-1 must Stop and IEnumenator-2 must Start, and again if the user pushes Button-1 again (Maybe DURING working and before ending) IEnumenator-2 must Stop and IEnumenator-1 must Start, and so ....

    thank you again...
     
  11. santiagolopezpereyra

    santiagolopezpereyra

    Joined:
    Feb 21, 2018
    Posts:
    91
    Here's your solution:

    Code (CSharp):
    1. private bool firstRoutineRunning, secondRoutineRunning;
    2.     private bool FirstRoutineRunning {
    3.         get{
    4.             return firstRoutineRunning;
    5.         }set{
    6.             firstRoutineRunning = value;
    7.             if (value){
    8.                 StopCoroutine("SecondRoutine");
    9.                 StartCoroutine("FirstRoutine");
    10.             }
    11.         }
    12.     }
    13.  
    14.      private bool SecondRoutineRunning {
    15.         get{
    16.             return secondRoutineRunning;
    17.         }set{
    18.             secondRoutineRunning = value;
    19.             if (value){
    20.                 StopCoroutine("FirstRoutine");
    21.                 StartCoroutine("SecondRoutine");
    22.             }
    23.         }
    24.     }
    25.  
    26.     void Update () {
    27.         if (user press button 1){ // Here put Input.GetKeyDown or whatever you want.
    28.             FirstRoutineRunning = true;
    29.             SecondRoutineRunning = false;
    30.  
    31.         }
    32.         if (user press button 2){
    33.             SecondRoutineRunning = true;
    34.             FirstRoutineRunning = false;
    35.         }
    36.     }
    If the player presses button 1 (whatever that is in your game), the first routine will run and the second routine will stop. If the player press button 2, the first routine stops and the second starts.

    If you are not familiar with getters and setters you should, because you can see how simple they make things.
     
    AhmadIssawi likes this.
  12. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    Still wondering why making it so static, while something like this could work.
    Code (CSharp):
    1. private Coroutine currentCoroutine;
    2.  
    3.     public void ChangeCoroutine(IEnumerator coroutine)
    4.     {
    5.         if (currentCoroutine != null)
    6.         {
    7.             StopCoroutine(currentCoroutine);
    8.         }
    9.  
    10.         currentCoroutine = StartCoroutine(coroutine);
    11.     }
    And then change it like
    Code (CSharp):
    1. ChangeCoroutine(YourCoroutine());
     
    AhmadIssawi likes this.
  13. santiagolopezpereyra

    santiagolopezpereyra

    Joined:
    Feb 21, 2018
    Posts:
    91
    That's actually perfect. I was thinking of booleans so one could have a better register of which coroutine was running (the first or the second), but that can be done also the way you did. I'd only suggest to change a little bit the structure

    Code (CSharp):
    1.     private Coroutine currentCoroutine;
    2.    
    3.         public void ChangeCoroutine(IEnumerator coroutine)
    4.         {
    5.             if (currentCoroutine != null && currentCoroutine != coroutine) // A second condition to prevent stoping and starting the same coroutine by mistake; this is just being extra careful.
    6.             {
    7.                 StopCoroutine(currentCoroutine);
    8.                 currentCoroutine = StartCoroutine(coroutine);
    9.             }
    10.         }
    11.  
    I didn't like to have
    currentCoroutine = StartCoroutine(coroutine);
    outside of the if statement because the method is suppose to change a coroutine, which gives by granted that another one's running. If that last line is outside of the if statement, a coroutine would start even when there was no change to be done. But, since this is just following the concept of the method's name, "ChangeCoroutine", and not the particular necessities of the code, if you find that starting the coroutine even when not changing it suits your code, go for it!
     
    AhmadIssawi likes this.
  14. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    AhmadIssawi likes this.
  15. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    Dear friends ....Your codes above are absolutely Correct, Logic, Nice and Clear ...
    and since i still have problem ... i followed My code word by word ... and Finally : the Problem is Not in the code of coroutines .. but in the code that is inside the following IEnumerator :


    Code (CSharp):
    1.     public IEnumerator sYMove(GameObject GO1, float Steps,float Speed, int Goal)    {  
    2.  
    3.         int Crnt=(int)GO1.transform.position.y;
    4.         float Ft;
    5.         int Tm = 0;
    6.                                                                            
    7.         while(true)    {    Ft=Crnt + (Goal-Crnt)*Mathf.Sin(Steps*Tm*Mathf.PI/200);
    8.                         GO1.transform.position = new Vector3(GO1.transform.position.x, Ft, GO1.transform.position.z);
    9.                         Tm +=1;
    10.                         if(Steps*Tm>=100)    {    GO1.transform.position = new Vector3(GO1.transform.position.x, Goal, GO1.transform.position.z);
    11.                                                 yield break;
    12.                                             }
    13.                         yield return new WaitForSeconds(Speed);
    14.                     }
    15.                                                                                     }
    each time i change this function .... the code works well ... :(
     

    Attached Files:

  16. WheresMommy

    WheresMommy

    Joined:
    Oct 4, 2012
    Posts:
    890
    What is the error you get? What is the behavior you expect and what else is happening?
     
    AhmadIssawi likes this.
  17. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    Dear ... the Problem i got is the Subject of this thread : the fact i CAN NOT RESTART the function and use it again after being Stopping it ....

    Again, in details :
    when i use the following function :

    Code (CSharp):
    1.     IEnumerator MyTryCrt()    {    while(true)    {    print("MyTryCrt");
    2.                                                         yield return new WaitForSeconds(1);
    3.                                                      }
    4.                                }
    i have no Problem .... and i can stop its coroutine and RESTART it many times, (according to user actions) ...
    But when i use the initial function : i can :
    1) start it
    2) stop it
    3) Here i can NO Longer start it again after stopping it ...
     
  18. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    So i think YOU ARE RIGHT HERE !!

    and then the Problem is inside the following function :
     

    Attached Files:

  19. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
  20. AhmadIssawi

    AhmadIssawi

    Joined:
    Jun 4, 2016
    Posts:
    48
    Dears, ... after a deep revision of Coroutine and Yield concepts ... i GET the error finally ....
    the Problem is SIMPLY in one word that :
    Whenever Coroutine reaches the "yield break" statement .... it can No Longer be Used ....
    "yield break" takes the meaning of "KILL Coroutine"...
    So, let's Close this thread .. and Go to another more specific ...
    Thank you again for All ...
     
  21. hearstzhang

    hearstzhang

    Joined:
    Apr 1, 2019
    Posts:
    17
    You saved my ass, thank you so much!
     
  22. Follet

    Follet

    Joined:
    May 18, 2018
    Posts:
    38
    I know this is two years old, but as I was having this issue and not finding a solution I guessed I could give the solution after I found it. After stopping a corroutine, if you want to start it again, you have to set it again:
    Code (CSharp):
    1.     IEnumerator MyCoroutine;
    2.  
    3.     void Start()
    4.     {
    5.         MyCoroutine = this.WaitABit();
    6.     }
    7.  
    8.     IEnumerator WaitABit()
    9.     {
    10.         //set parameters and do stuff
    11.         yield return new WaitForSeconds(1);
    12.         //do more stuff
    13.     }
    14.  
    15.     void ActivateAndDeactivateCoroutine()
    16.     {
    17.         if (Input.GetKey(KeyCode.A)) //Whatever your conditions are to start
    18.         {
    19.             StartCoroutine(MyCoroutine);
    20.         }
    21.         if (Input.GetKey(KeyCode.B))//Whatever your conditions are to stop
    22.         {
    23.             StopCoroutine(MyCoroutine);
    24.             MyCoroutine = WaitABit(); //This is the important part to be able to restart the coroutine after it stops
    25.         }
    26.     }
    Now the coroutine will stop and start as many times as you want and have only one instance of it running and stopping it at any time.
     
  23. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
    While we're necroing old threads, remember that coroutines are NOT always an appropriate solution: know when to use them and when NOT to use them!

    If your application requires starting AND stopping coroutines, then coroutines are likely NOT the right approach.

    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
     
    Follet likes this.
  24. Follet

    Follet

    Joined:
    May 18, 2018
    Posts:
    38
    Thanks for the heads up! I will definetly use this since it seems I'm using coroutines when I should not
     
    Kurt-Dekker likes this.