Advertisement
lunoland

Unity Coroutine Pattern

Aug 14th, 2018
419
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 3.69 KB | None | 0 0
  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; } }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement