Im looking for the following behavior… I can’t seem to find a way to do this. Is it possible?

 void Start() 
 {
     StartCoroutine(Coroutine1()); 
 }
 
 IEnumerator Coroutine1() {
     // Do something...
 
     // I want this Coroutine to break here if Coroutine2 breaks
     yield return StartCoroutine(Coroutine2()); 
 
     // Do something else... (shouldn't be called if Coroutine2 breaks) 
 }

 IEnumerator Coroutine2()
 {
         if (something) {
         yield break; //or something else here, this doesn't do what I need
     }
     else {
         yield return null;
     }
 }

Any thoughts?

Thanks

*** Edit ***

I Realize it is possible to use an anonymous lambda to pass an argument to Coroutine2() and have it “return” a boolean for example, and then just check that after Coroutine2 resolves and break in Coroutine1 if needed, but that is very hackey to me.

I want when Coroutine2 breaks, to FORCE Coroutine1 to break and not finish execution

*** Edit 2 ***

I also read that throwing an Exception in the child coroutine would cause the parent coroutine to stop, but that didn’t work for me, I believe that is because the coroutines are not in a class that inherits from MonoBehavior perhaps? or that was a bug that was fixed in newer Unity versions. maybe someone can confirm this, but throwing an exception in child coroutines did not cause the parent coroutine to stop.

ALSO in my specific situation it is also likely that the nested coroutine that needs to break up the chain may be 3 levels deep, and will need to break its parent coroutine and the coroutine above that

No, this is illogical.

There is no such thing as a “nested” co-routine. That implies a single thread of control.

By definition a co-routine is a separate thread of control. The launch point is just where the operating system gets called to start the thread. You cannot “return” to the launch point when done.

EDIT 2:

So the following is basically another way of having the return bool type functionality, the only real advantage is that you only have to change code in the calling IEnumerator rather than in the child IEnumerator which is more convenient for some situations.

So the first code inherits from MonoBehaviour and you would use it as your inherit in all codes where you want this new IEnumerator functionality (you could set it up to just be a static class instead if you preferred). The second code is an example that inherits from it, maybe it is useful to you!

Code one to inherit from in order to wrap your Coroutines:

public class RoutineBehaviour : MonoBehaviour{
	public Coroutine<T> StartCoroutine<T>(IEnumerator coroutine){
		Coroutine<T> coroutineObj = new Coroutine<T>();
		coroutineObj.coroutine = base.StartCoroutine(coroutineObj.InternalRoutine(coroutine));
		return coroutineObj;
	}

	public class Coroutine<T>{
		private T returnVal;
		public Coroutine coroutine;
		public T Value{
			get { return returnVal; }
		}

		public IEnumerator InternalRoutine(IEnumerator coroutine){
			while (true){
				object yielded = coroutine.Current;
				if (yielded != null && yielded.GetType() == typeof(T)){
					returnVal = (T)yielded;
					yield break;
				}else{
					yield return coroutine.Current;
				}
				bool b = coroutine.MoveNext();
				if(b == false){
					yield break;
				}
			}
		}
	}
}

Code two, examples of how you can use the return values from the wrapper:

public class CoroutineTest : RoutineBehaviour {
	void Start() {
		StartCoroutine(Coroutine1()); 
	}

	IEnumerator Coroutine1(){
		Debug.Log("Doing something in coroutine 1");
		//Do something
		
		Coroutine<bool> co2 = StartCoroutine<bool>(Coroutine2());
		yield return co2.coroutine;	
		if(co2.Value){
			Debug.Log("Coroutine2 broke us!");
			yield break;
		}
		Debug.Log("Coroutine 2 has broken without breaking us!");
		//do something else
		
		Coroutine<int> co3 = StartCoroutine<int>(Coroutine3());
		yield return co3.coroutine;	
		if(co3.Value > 3){
			Debug.Log("Coroutine3 broke us!");
			yield break;
		}
		
		Debug.Log("Coroutine 3 has broken without breaking us!");
		//do something else
	}

	IEnumerator Coroutine2(){
		if(true){
			for(int i = 0; i < 10; i++){
				Debug.Log("coroutine 2 stuff " + i);
				yield return null;
			}
			yield return false; //doesn't break parent
		}
	}
	IEnumerator Coroutine3(){
		if(true){
			for(int i = 0; i < 10; i++){
				Debug.Log("coroutine 3 stuff " + i);
				yield return null;
			}
			yield return 4; //does break parent
		}
	}
}

Maybe that is a more usable system for you!

Also on my travels I found this forum post and although I haven’t tested it yet, it looks like it might have some benefits to you.

Scribe


EDIT: perhaps you prefer doing it this way -

public int frameCount = 0;

IEnumerator co1;
void Start() {
	co1 = Coroutine1();
	StartCoroutine(co1); 
}

void Update(){
	frameCount ++;
}

IEnumerator Coroutine1() {
	Debug.Log("Doing something in coroutine 1");
	//Do something
	
	IEnumerator co2 = Coroutine2();
	yield return StartCoroutine(co2);
	
	while((co2.Current as bool?) != true){
		Debug.Log("waiting on coroutine 2 to force advance");
		yield return null;
	}
	
	Debug.Log("Coroutine 2 has broken! We can do something else!");
	//Do something else
}

IEnumerator Coroutine2(){
	co1.MoveNext();
	yield return null;
	if(true){
		for(int i = 0; i < 10; i++){
			Debug.Log("coroutine 2 stuff " + frameCount.ToString());
			co1.MoveNext();
			yield return null;
		}
		yield return true;
		co1.MoveNext();
		return true;
		Debug.Log("test");
	}
}

The co1.MoveNext(); command moves Coroutine1 forward to its next yield statement, I’ve actually got an exam tomorrow so this is probably the last you’ll here from me until tomorrow afternoon (and possibly forever depending how it goes ^^) But going that route might be better, it’s still a little hacky with the while argument (co2.Current as bool?) != true but at least it is Coroutine2 that is controlling when to advance!

Scribe


You can do this, coroutines are by default in the same single thread, I believe they simply save their own state at the end of each frame (they definitely give the impression of being in a different thread however), you can do:

public int frameCount = 0;
void Start() {
	StartCoroutine(Coroutine1()); 
}

void Update(){
	frameCount ++;
}

void OnGUI(){
	GUILayout.Label(frameCount.ToString());
}

IEnumerator Coroutine1() {
	Debug.Log("Doing something in coroutine 1 " + frameCount.ToString());
	//Do something
	
	yield return StartCoroutine(Coroutine2());
	
	Debug.Log("Coroutine 2 has broken! We can do something else! " +frameCount.ToString());
	//Do something else
	
	Debug.Log("End Coroutine 1 " +frameCount.ToString());
}

IEnumerator Coroutine2(){
	if(true){
		Debug.Log("Doing something in coroutine 2 " +frameCount.ToString());
		
		for(int i = 0; i < 100; i++){
			yield return null;
		}
		
		Debug.Log("coroutine 2 should break now " +frameCount.ToString());
		return true; //Stop Coroutine2
	}else{
		yield return null;
	}
}

I think the important bit to you is that you can break an Ienumerator with return true; (or return false; I don’t think it makes a difference, it just seems to want a boolean value returned!)

Hope that is useful, you can do it a second way using a value that you pass to Coroutine2 if you want to continue doing something in Coroutine1 whilst you wait for Coroutine2 to end.

Scribe

Try to pass a value to the second coroutine. As you cannot pass a value type and modify it in a coroutine, I would recommend to pass a basic class:

class Data{
    public bool hasBroken = false;
} 

void Start(){
   StartCoroutine(First());
}

IEnumerator First()
{
     Data data = new Data();
     yield return StartCoroutine(Second(data));
     if(data.hasBroken == true){}
}

IEnumerator Second(Data data){
   while(true){
       if(condition){
             data.hasBroken = true;
             yield break;
       }
   }
}

Well you can do this.

Edit: Now with a callback to cancel or continue the routine, thanks Bunny83 for point the my mistake.

private IEnumerator DoSomething()
        {
			var callback = false;
			yield return StartCoroutine(ProcessSomething(value =>
			{
				callback = value;
			}
			));
			
			if(callback == false)
				//cancel routine
			else
				//continue something
        }
    
        private static IEnumerator ProcessSomething(System.Action<bool> callback)
        {
            // some stuff
            
            if(UnityEngine.Random.Range(1,10)>1)
			{
				callback(false);
				goto end;
			}
                
            //if the random number is 1 goto end and skip the others things
            //else process other things below
    
            var lemons = 5;
            
            for (var i = 0; i < lemons; i++)
            {
                lemons++;
            }//this thing no make any sense. I know.
            
            //do more stuff 
            callback(true);
            end:
            yield return null;
        }