BetterCoroutines¶
Coroutines is an awesome hack, but unfortunately they’re not that cheap.BetterCoroutines is a very similar but much more performant alternative to Unity’s coroutines. It runs faster and reduces the amount of garbage generated.Furthermore you have more control over which update loop they run in and their lifetime is not dependent on gameobjects.
That said, they still aren’t super cheap and should be used sparingly (if at all) if you’re shooting for high performance. Their performance is similar to that ofMore Effective Coroutines.
Usage¶
Defining your coroutine¶
Defining your coroutine method is exactly the same as with Unity’s coroutines:
IEnumeratorMyRoutine(){Debug.Log("Let's wait a frame!");yieldreturnnull;Debug.Log("That was awesome!");}
Starting a coroutine¶
Instead of usingMonoBehaviour.StartCoroutine() you should useBetterCoroutines.Start().
BetterCoroutines.Start(MyRoutine());
This’ll runMyRoutine in the regular update loop.
If you instead want it to run in LateUpdate or FixedUpdate you can do the following:
BetterCoroutines.Start(MyRoutine(),UpdateLoop.LateUpdate);// orBetterCoroutines.Start(MyRoutine(),UpdateLoop.FixedUpdate);
If you want your coroutines to stop automatically when a gameobject or component is destroyed/disabled, you can do so with an overload:
BetterCoroutines.Start(MyRoutine(),myGameObject);// orBetterCoroutines.Start(MyRoutine(),myComponent);
Stopping a coroutine¶
The start method actually returns the id of the started coroutine, which you can use to stop it prematurely if needed.
intmyCoroutineId=BetterCoroutines.Start(MyRoutine());// laterboolwasStopped=BetterCoroutines.Stop(myCoroutineId);
wasStopped will now be true if the coroutine was found and stopped, otherwise it will be false.
Stopping all coroutines¶
If you suddenly have the urge to stop all coroutines you can do so easily:
// stops all coroutines regardless of which update loop they're part ofBetterCoroutines.StopAll();// stops all coroutines in a specific update loopBetterCoroutines.StopAll(UpdateLoop.FixedUpdate);
Checking whether a specific coroutine is running¶
You can check if a coroutine with a specific ID is currently running.
boolisRunning=BetterCoroutines.IsRunning(myCoroutineId);
Pausing a coroutine¶
BetterCoroutines supports pausing a coroutine as well.
BetterCoroutines.Pause(myCoroutineId);BetterCoroutines.Unpause(myCoroutineId);// orBetterCoroutines.SetPaused(myCoroutineId,true);BetterCoroutines.SetPaused(myCoroutineId,false);
You can can check whether a coroutine is currently paused withIsPaused(id).
boolisPaused=BetterCoroutines.IsPaused(myCoroutineId);
Yield Operations¶
Wait a frame¶
Just as with Unity’s coroutines you can wait a single frame by yieldingnull.
If this is not verbose enough for you, you can instead use the constant BetterCoroutines.WaitForOneFrame.
IEnumeratorWaitAFrameRoutine(){Debug.Log("First frame");yieldreturnnull;Debug.Log("Second frame");yieldreturnBetterCoroutines.WaitForOneFrame;Debug.Log("Three frame");}
Subcoroutines¶
You can yield a coroutine to suspend the current one until the yielded coroutine is done.
IEnumeratorMyRoutine(){yieldreturnMySubroutine();// oryieldreturnBetterCoroutines.Start(MySubroutine());}IEnumeratorMySubroutine(){yieldreturnnull;}
WaitForSeconds¶
You can suspend a coroutine for a certain time either in scaled or unscaled time.
IEnumeratorWaitForSecondsRoutine(){// waits 1 second in scaled timeyieldreturnBetterCoroutines.WaitForSeconds(1);// waits 1 second in unscaled timeyieldreturnBetterCoroutines.WaitForSeconds(1,false);}
WaitForSecondsRealtime¶
You can also suspend a coroutine for a specific time in realtime.
IEnumeratorWaitForSecondsRealtimeRoutine(){yieldreturnBetterCoroutines.WaitForSecondsRealtime(1);}
WaitWhile¶
You can also suspend a coroutine until a delegate returns false.The delegate is invoked each frame.
IEnumeratorWaitWhileRoutine(){// waits until space is released (assuming it's pressed right now)yieldreturnBetterCoroutines.WaitWhile(()=>Input.GetKey(KeyCode.Space));}
WaitForEndOfFrame¶
BetterCoroutines also has support for Unity’s special WaitForEndOfFrame instruction.
It’ll suspend the coroutine until right before the current frame is displayed.
While you could create a new instance every time, there’s no reason to punish the GC. Just use BetterCoroutines.WaitForEndOfFrame instead.
IEnumeratorEndOfFrameRoutine(){yieldreturnBetterCoroutines.WaitForEndOfFrame;// take screenshot or whatever}
WaitUntil¶
Similar toWaitWhile but instead it waits until the delegate returns true.The delegate is invoked each frame.
IEnumeratorWaitUntilRoutine(){// waits until Space is pressed.yieldreturnBetterCoroutines.WaitUntil(()=>Input.GetKeyDown(KeyCode.Space));}
WaitForWWW¶
Yielding a WWW object will suspend the coroutine until the download is done.
IEnumeratorWaitForWWWRoutine(){WWWWwww=newWWW("https://gitlab.com/archoninteractive/SwissArmyLib/raw/master/logo.png");yieldreturnwww;// oryieldreturnBetterCoroutines.WaitForWWW(www);// www.texture is now downloaded}
WaitForAsyncOperation¶
Yielding an AsyncOperation will suspend the coroutine until that AsyncOperation is done.
IEnumeratorWaitForAsyncOperationRoutine(){AsyncOperationoperation=SceneManager.LoadSceneAsync(0);yieldreturnoperation;// oryieldreturnBetterCoroutines.WaitForAsyncOperation(operation);// scene is now loaded}
Todo
Write some examples for BetterCoroutines