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