Search Unity

Coroutines: Starting, Stopping, Interrupting, IsRunning ...

Discussion in 'Scripting' started by aflesher, Mar 1, 2018.

  1. aflesher

    aflesher

    Joined:
    Dec 12, 2013
    Posts:
    28
    I've been writing lots of coroutines lately. A common functionality is that I need stop an existing coroutine before starting it (if it's already running). Another common functionality is that I need to be able to see if a given coroutine is running. Typically this is how I accomplish this:

    Code (CSharp):
    1. Coroutine myCoroutine;
    2.  
    3. void Begin() {
    4.   if (myCoroutine != null) {
    5.     StopCoroutine(myCoroutine);
    6.   }
    7.  
    8.   myCoroutine = StartCoroutine(MyCoroutine());
    9. }
    10.  
    11. void End() {
    12.   if (myCoroutine != null) {
    13.     StopCoroutine(myCoroutine);
    14.     myCoroutine = null;
    15.   }
    16. }
    17.  
    18. bool IsRunning() {
    19.   return myCoroutine != null;
    20. }
    21.  
    22. IEnumerator MyCoroutine() {
    23.   yield return new WaitForSeconds(1);
    24.   // .. do something
    25.   myCoroutine = null;
    26. }
    For a class that has a few different coroutines this starts to get a little ugly. Is there a better way to do this? I guess I write a custom class for this.
     
  2. jschieck

    jschieck

    Joined:
    Nov 10, 2010
    Posts:
    429
    What I like to do is have a manager that handles the actual coroutines. It allows you to actually start, stop, and keep track of things that are running... for example:

    Code (CSharp):
    1. public class CoroutineManager : MonoBehaviour
    2. {
    3.     private static CoroutineManager Instance
    4.     {
    5.         get
    6.         {
    7.             if (mInstance == null)
    8.             {
    9.                 mInstance = new GameObject("CoroutineManager").AddComponent<CoroutineManager>();
    10.                 GameObject.DontDestroyOnLoad(mInstance.gameObject);
    11.             }
    12.             return mInstance;
    13.         }
    14.     }
    15.     private static CoroutineManager mInstance;
    16.     private static Dictionary<string, Coroutine> runningRoutines = new Dictionary<string, Coroutine>();
    17.     private static IEnumerator InternalRoutine(string key, IEnumerator routine)
    18.     {
    19.         yield return routine;
    20.         runningRoutines.Remove(key);
    21.     }
    22.  
    23.     public static void Start(string key, IEnumerator routine)
    24.     {
    25.         Stop(key);
    26.         var internalRoutine = Instance.StartCoroutine(InternalRoutine(key, routine));
    27.         runningRoutines.Add(key, internalRoutine);
    28.     }
    29.     public static bool IsRunning(string key)
    30.     {
    31.         return runningRoutines.ContainsKey(key);
    32.     }
    33.     public static bool Stop(string key)
    34.     {
    35.         Coroutine routine;
    36.         if (runningRoutines.TryGetValue(key, out routine))
    37.         {
    38.             Instance.StopCoroutine(routine);
    39.             runningRoutines.Remove(key);
    40.             return true;
    41.         }
    42.         return false;
    43.     }
    44. }
    Then you can use it like this

    Code (CSharp):
    1. public class ExampleScript : MonoBehaviour
    2. {
    3.     private const string KEY = "TEST";
    4.  
    5.     private void Start()
    6.     {
    7.         CoroutineManager.Start(KEY, TestRoutine());
    8.     }
    9.     private void Update()
    10.     {
    11.         if (Input.GetKeyDown(KeyCode.Space))
    12.         {
    13.             if (!CoroutineManager.IsRunning(KEY))
    14.             {
    15.                 Debug.LogFormat("Routine {0} is not running... Starting it", KEY);
    16.                 CoroutineManager.Start(KEY, TestRoutine());
    17.             }
    18.         }
    19.         if (Input.GetKeyDown(KeyCode.Escape))
    20.         {
    21.             if (CoroutineManager.Stop(KEY))
    22.             {
    23.                 Debug.LogFormat("Stopped Routine {0}", KEY);
    24.             }
    25.         }
    26.     }
    27.     private IEnumerator TestRoutine()
    28.     {
    29.         Debug.Log("Hello");
    30.         yield return new WaitForSeconds(5);
    31.         Debug.Log("World");
    32.     }
    33. }
     
    aflesher likes this.