Hello all,
Today, at Unity Answers, Fattie posted a question about detecting if coroutine is still running.
I don’t know of any method of detecting this, and I don’t think any simple method exists, apart from setting some variables at coroutine end. Anyway, this triggered my curiosity, so I entered research mode. As a result of my quick R&D, I created StartCoroutineEx extension method, CoroutineController class and CoroutineState enumeration. Please see the code below, but firstly some info.
- To use extended version, instead of calling:
StartCoroutine(SomeCoroutine());
you have to use:
CoroutineController controller;
this.StartCoroutineEx(SomeCoroutine(), out controller); // please note that 'this' keyword is required (at least in C#)
-
Using CoroutineController returned as output parameter, you can check current state of coroutine, as well as control it a bit (stop, pause, resume).
-
You can yield it as a standard coroutine as well:
yield return this.StartCoroutineEx(SomeCoroutine(), out controller);
A word of explanation is required here. When I started, I planned StartCoroutineEx to return instance of CoroutineEx, where CoroutineEx would be a class derived from YieldInstruction (I was not able to derive from Coroutine, as it is sealed). Everything was working great, except of yielding. After a few tries, I decided it’s a dead end, as this is probably controlled within Unity engine, so returning anything but Coroutine will not be delayed. I went with out parameter then, but if anyone has a different suggestion, please share it.
-
I used C#, because it’s my almost native language
But if you put my scripts in any of early compilation folder (e.g. Assets\Plugins), then you can use them in UnityScript as well.
-
This is an alpha version, so if you see an error, let me know. Please let me know as well, what do you think of this idea. Is it good? Or maybe stupid? Or maybe not really stupid, but you would never use it?
Code:
public enum CoroutineState
{
Ready,
Running,
Paused,
Finished
}
using System.Collections;
public class CoroutineController
{
private IEnumerator _routine;
public CoroutineState state;
public CoroutineController(IEnumerator routine)
{
_routine = routine;
state = CoroutineState.Ready;
}
public IEnumerator Start()
{
if (state != CoroutineState.Ready)
{
throw new System.InvalidOperationException("Unable to start coroutine in state: " + state);
}
state = CoroutineState.Running;
while (_routine.MoveNext())
{
yield return _routine.Current;
while (state == CoroutineState.Paused)
{
yield return null;
}
if (state == CoroutineState.Finished)
{
yield break;
}
}
state = CoroutineState.Finished;
}
public void Stop()
{
if (state != CoroutineState.Running state != CoroutineState.Paused)
{
throw new System.InvalidOperationException("Unable to stop coroutine in state: " + state);
}
state = CoroutineState.Finished;
}
public void Pause()
{
if (state != CoroutineState.Running)
{
throw new System.InvalidOperationException("Unable to pause coroutine in state: " + state);
}
state = CoroutineState.Paused;
}
public void Resume()
{
if (state != CoroutineState.Paused)
{
throw new System.InvalidOperationException("Unable to resume coroutine in state: " + state);
}
state = CoroutineState.Running;
}
}
using UnityEngine;
using System.Collections;
public static class CoroutineExtensions
{
public static Coroutine StartCoroutineEx(this MonoBehaviour monoBehaviour, IEnumerator routine, out CoroutineController coroutineController)
{
if (routine == null)
{
throw new System.ArgumentNullException("routine");
}
coroutineController = new CoroutineController(routine);
return monoBehaviour.StartCoroutine(coroutineController.Start());
}
}