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.Untilas 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!
