- Home /
Coroutine with reference not stopping - Missed the out keyword
Using Unity 2019.1.9f1
I just fell into this problem with a simple Coroutine manager I wrote, the problem was strangling me so i decided to write an example to be sure the problem was not my fault. Or else I made a wrong assumption on how the Coroutine system is meant to work.
The problem is:
I start a coroutine and save it reference
I stop the coroutine and start a new one using the same reference by changing it's target IEnumerator
!!! The coroutine actually won't stop, the new one starts (on the same reference?)
Here is the code, it's simple, a phone is ringing, the user by pressing D (running on script 2) invokes an unity event, the telephone (SHOULD) stop ringing and the user should answer.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DEBUGCoroutines : MonoBehaviour
{
//DIFFERENT STATES
public enum DebugState { Ringing, Pickup, Stop }
public DebugState state = DebugState.Ringing;
Coroutine stateRoutine = null;
void Start()
{
//START EXAMPLE BY RINGING
UpdateState(state, true);
}
//STATE UPDATER, ON CALL CHANGES STATE
void UpdateState(DebugState s, bool force = false)
{
if (s != state || force)
{
state = s;
CustomStopAllCoroutines();
switch (state)
{
case DebugState.Ringing:
CustomStartCoroutine(stateRoutine, Ring());
break;
case DebugState.Pickup:
CustomStartCoroutine(stateRoutine, Pickup());
break;
case DebugState.Stop:
CustomStartCoroutine(stateRoutine, Stop());
break;
default:
break;
}
}
}
//STATE EVENTS
//
IEnumerator Pickup()
{
Debug.Log("HELLO!?");
yield return new WaitForSeconds(5f);
Debug.Log("Ok, Good bye");
UpdateState(DebugState.Stop);
}
IEnumerator Ring()
{
while (state == DebugState.Ringing)
{
Debug.Log("ring");
yield return new WaitForSeconds(2f);
}
Debug.Log("ERROR"); //THIS SHOULDN'T PLAY!
}
IEnumerator Stop()
{
yield return new WaitForSeconds(10);
UpdateState(DebugState.Ringing);
}
//METHOD CALLED BY THE EVENT
public void GetCall()
{
UpdateState(DebugState.Pickup);
}
//COROUTINE MANAGERS
//
void CustomStopAllCoroutines()
{
QuitRoutine(stateRoutine);
}
void CustomStartCoroutine(Coroutine cr, IEnumerator routine)
{
if (cr == null) cr = StartCoroutine(routine);
else
{
StopCoroutine(cr);
cr = null;
cr = StartCoroutine(routine);
}
}
void QuitRoutine(Coroutine cr)
{
if (cr != null) StopCoroutine(cr);
cr = null;
}
}
And here the simple event caller:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class DEBUGCaller : MonoBehaviour
{
public UnityEvent debugEvent;
void Update()
{
if(Input.GetKeyDown(KeyCode.D)) debugEvent.Invoke();
}
}
I am not using StopAllCoroutines() because (not in this simple example) I am stopping only isolated routines and have others that meanwhile must run in background.
Using StopAllCoroutines() indeed works, I also tried to change while (state == DebugState.Ringing) into a while(true) and the error is still here - so it has not to do with the Order of Execution I guess.
Other updates, I noticed I was mixing IEnumerators and Coroutine, I changed everything to IEnumerator (I am not allowed to pass as method variable an IEnumerator to a Coroutine). The behaviour of this script didn't change. I am still stuck behind the same issue.
Answer by Pivetta · Jul 10, 2019 at 07:03 PM
Found the solution and it was my mistake.
I was not really changing my Coroutine or IEnumerator variable (had to change to IEnumerator cause I could not define the Coroutine member from a Method Variable - I bet the ref keyword would do)
All I had to do was using the out keyword to save my IEnumerator outside the method, now everything is working smooth
The changed parts of the code:
//stateRoutine is now an IEnumerator
IEnumerator stateRoutine = null;
//In the switch now I had to use out
CustomStartCoroutine(out stateRoutine, Ring());
//This is now the fixed method to start coroutines
void CustomStartCoroutine(out IEnumerator cr, IEnumerator routine)
{
cr = routine;
StartCoroutine(cr);
}
Your answer
Follow this Question
Related Questions
Execution order when Start is declared with IEnumerator return (as a Coroutine) 1 Answer
Is any coroutine called before LateUpdate? 1 Answer
Call function after other objects have run their Start() function 2 Answers
Issue With Simultaneous ReadPixels Calls 0 Answers
How to Substitute Coroutine in non-MonoBehaviour Class? 1 Answer