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