Coroutines are a great idea and super useful, but they’re kind of unwieldy to use in C# and sometimes they just don’t plain work. Or I don’t know how to use them properly. All I know is that they’re more complicated than they need to be, and I remember having problems using them from an Update method.
So I made my own version of Coroutines inspired by the XNA WaitUntil stuff I posted about a long time ago. Here it is!
using System; using UnityEngine; using Debug = UnityEngine.Debug; using Object = UnityEngine.Object; class ConditionalBehaviour : MonoBehaviour { public float SinceAlive; public Action Action; public Condition Condition; void Update() { SinceAlive += Time.deltaTime; if (Condition(SinceAlive)) { if (Action != null) Action(); Destroy(gameObject); Action = null; Condition = null; } } } public delegate bool Condition(float elapsedSeconds); public static class Wait { public static void Until(Condition condition, Action action) { var go = new GameObject("Waiter"); var w = go.AddComponent<ConditionalBehaviour>(); w.Condition = condition; w.Action = action; } public static void Until(Condition condition) { var go = new GameObject("Waiter"); var w = go.AddComponent<ConditionalBehaviour>(); w.Condition = condition; } }
Here’s an example of use, straight out of the Volkenessen code (with special guest appearance from my ported easing functions) :
var initialOffset = new Vector3(hitDirection.x * -1, 0, 0); var origin = armToUse.transform.localPosition; armToUse.renderer.enabled = true; Wait.Until(elapsed => { var step = Easing.EaseOut(1 - Mathf.Clamp01(elapsed / Cooldown), EasingType.Cubic); armToUse.transform.localPosition = origin + initialOffset * step; return step == 0; }, () => { armToUse.renderer.enabled = false; });
What’s going on here :
- You call
Wait.Until
as a static method and pass it one or two methods (be it lambdas or method references) : The first one is the Condition which gets evaluated every Update until it returns true, and the second gets evaluated when the condition is true (it’s a shorthand, basically) - The Wait static class instantiates a “Waiter” game object and hooks a custom script component to it that does the updating and checking stuff
- The condition gets passed the number of seconds elapsed since the component was created, so you don’t have to keep track of it separately.
I use it for waiting for amounts of time (Wait.Until(elapsed => elapsed > 2, () => { /* Something */ })
), interpolate values and do smooth transitions (like the code example above, I animate the player’s arm with it), etc.
I’ll probably keep updating my component as I need more things out of it, but up to now it’s served me well. Hope it helps you too!