lunoland

Unity Coroutine Pattern

Aug 14th, 2018
241
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // There are a couple different ways to use coroutines in Unity, though some are worse
  2. // than others. Here is the pattern that I've been using which I find to be pretty clean
  3. // and flexible.
  4.  
  5. // First, we'll always use an IEnumerator variable to be able to refer to individual
  6. // instances of a coroutine. Often times it makes sense to pack these variables into some
  7. // collection if you'll need multiple instances at once, or to make them a member of a
  8. // class/struct.
  9. IEnumerator thingyCoroutine;
  10.  
  11.  
  12. // Next we can define our coroutine behavior. The trick here is that we'll set
  13. // thingyCoroutine to null whenever the coroutine exits normally. This way, we can keep
  14. // track of the status of the coroutine without additional flags.
  15. IEnumerator Thingy() {
  16.     while (doStuff) {
  17.         yield return null;
  18.        
  19.         if (badThing) {
  20.             // The main thing you'll have to remember with this pattern: whenever you end
  21.             // the coroutine, you need to make sure to set thingyCoroutine to null.
  22.             thingyCoroutine = null;
  23.             yield break;
  24.         }
  25.     }
  26.    
  27.     thingyCoroutine = null; // Again, we must set this to null when exiting the coroutine.
  28. }
  29.  
  30.  
  31. // Now we can create a public interface that handles starting/stopping the coroutine
  32. // gracefully.
  33.  
  34. public void StartThingy() {
  35.  
  36.     // We can see if the coroutine is already running first. Common things to do here are
  37.     // to return or to stop the coroutine and possibly do some clean up before restarting.
  38.     if (thingyCoroutine != null) { return; }
  39.    
  40.     thingyCoroutine = Thingy();
  41.     StartCoroutine(thingyCoroutine);
  42. }
  43.  
  44. public void StopThingy() {
  45.     if (thingyCoroutine == null) { return; }
  46.     StopCoroutine(thingyCoroutine);
  47.     thingyCoroutine = null;
  48.    
  49.     // Anything else you need to do to exit gracefully can go here, e.g. resetting the
  50.     // things the coroutine may have changed.
  51. }
  52.  
  53. public void RestartThingy() {
  54.     StopThingy();
  55.     StartThingy();
  56. }
  57.  
  58.  
  59. // When a MonoBehaviour is disabled, all coroutines running on it are stopped at their
  60. // next yield instruction. If you don't want this, you can start the coroutines on some
  61. // behaviour that you know won't be disabled. Perhaps you have some singleton, e.g.
  62. // Game.instance.StartCoroutine(thingyCoroutine).
  63.  
  64. // Otherwise, since we know thingyCoroutine will only be null when we stopped it
  65. // ourselves, we can restart any coroutines that didn't finish in OnEnable.
  66. void OnEnable() {
  67.     if (thingyCoroutine != null)
  68.         StartCoroutine(thingyCoroutine); // Pick up where we left off
  69. }
  70.  
  71. void OnDisable() {
  72.     if (gameObject.activeInHierarchy) {
  73.         // Bonus gotcha: OnDisable is also called when an object is being destroyed,
  74.         // except in this case the gameObject will be active when it's being destroyed and
  75.         // inactive when it's being disabled as normal. You may need to handle things
  76.         // differently in this situation, and this is the only way to check for it AFAIK.
  77.     }
  78.    
  79.     // Sometimes you may want to exit gracefully instead of picking up where we left off
  80.     // when the behaviour is re-enabled.
  81.     if (badThing)
  82.         StopThingy();
  83. }
  84.  
  85.  
  86. // Having this IEnumerator variable makes it easy for us to inquire about the state of the
  87. // coroutine. Sometimes it's helpful to have these sorts of fields if other parts of the
  88. // game need to know about the routine, e.g. if another coroutine kicks off this routine
  89. // and needs to wait until it's finished.
  90. public bool ThingyIsRunning { get { return thingyCoroutine != null && gameObject.activeInHierarchy; } }
  91. public bool ThingyIsPaused  { get { return thingyCoroutine != null && !gameObject.activeInHierarchy; } }
  92. public bool ThingyStarted   { get { return thingyCoroutine != null; } }
  93. public bool ThingyStopped   { get { return thingyCoroutine == null; } }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×