Skip to content

Instantly share code, notes, and snippets.

@ntratcliff
Last active June 28, 2022 15:20
Show Gist options
  • Save ntratcliff/77646569ffd44a2b215e7eafed1ea772 to your computer and use it in GitHub Desktop.
Save ntratcliff/77646569ffd44a2b215e7eafed1ea772 to your computer and use it in GitHub Desktop.
Handy Unity coroutine utilities.
using System;
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using UnityEngine;
namespace AeLa.Utilities
{
public static class CoroutineUtils
{
public static IEnumerator DoNextFrame(Action action)
{
yield return null;
action.Invoke();
}
/// <summary>
/// Invokes an action after a delay
/// </summary>
public static IEnumerator DoDelayed(Action action, float delay)
{
yield return new WaitForSeconds(delay);
action.Invoke();
}
/// <summary>
/// Executes a coroutine after a delay
/// </summary>
public static IEnumerator DoDelayed(IEnumerator routine, float delay)
{
yield return new WaitForSeconds(delay);
yield return routine;
}
/// <summary>
/// Calls the provided callback after the routine is finished
/// </summary>
public static IEnumerator DoAfter(Coroutine routine, Action action)
{
yield return routine;
action.Invoke();
}
public static IEnumerator DoAfter(IEnumerator routine, Action action)
{
yield return routine;
action.Invoke();
}
public static IEnumerator DoAfter(YieldInstruction yieldInstruction, Action action)
{
yield return yieldInstruction;
action.Invoke();
}
/// <summary>
/// Waits until the provided action is invoked
/// </summary>
public static IEnumerator WaitUntil(Action action)
{
var called = false;
void Wait() => called = true;
action += Wait;
while (!called) yield return null;
action -= Wait;
}
/// <summary>
/// Waits until the provided action returns true
/// </summary>
public static IEnumerator WaitUntil(Func<bool> predicate)
{
yield return new WaitUntil(predicate);
}
/// <summary>
/// Starts a coroutine either with the provided manager or as a globally managed routine
/// </summary>
public static Coroutine StartCoroutine(IEnumerator routine, MonoBehaviour manager)
{
return manager
? manager.StartCoroutine(routine)
: Global.StartCoroutine(routine);
}
[SuppressMessage("ReSharper", "MemberHidesStaticFromOuterClass")]
public static class Global
{
public static Coroutine StartCoroutine(IEnumerator routine)
{
return GlobalCoroutineRunner.Instance.StartCoroutine(routine);
}
public static void StopCoroutine(Coroutine coroutine)
{
GlobalCoroutineRunner.Instance.StopCoroutine(coroutine);
}
/// <summary>
/// <inheritdoc cref="CoroutineUtils.DoAfter(Coroutine, Action)"/>
/// </summary>
public static void DoAfter(Coroutine routine, Action action) =>
StartCoroutine(CoroutineUtils.DoAfter(routine, action));
/// <summary>
/// <inheritdoc cref="CoroutineUtils.DoAfter(IEnumerator, Action)"/>
/// </summary>
public static void DoAfter(IEnumerator routine, Action action) =>
StartCoroutine(CoroutineUtils.DoAfter(routine, action));
public static void DoAfter(YieldInstruction yieldInstruction, Action action) =>
StartCoroutine(CoroutineUtils.DoAfter(yieldInstruction, action));
public static void DoAfter(Func<bool> predicate, Action action) => DoAfter(WaitUntil(predicate), action);
public static void DoDelayed(Action action, float delay) =>
StartCoroutine(CoroutineUtils.DoDelayed(action, delay));
public static void DoNextFrame(Action action) => DoDelayed(action, 0);
public static void DoNextFixedUpdate(Action action) => DoAfter(new WaitForFixedUpdate(), action);
}
}
}
using UnityEngine;
namespace AeLa.Utilities
{
public class GlobalCoroutineRunner : MonoBehaviour
{
private static GlobalCoroutineRunner instance;
public static GlobalCoroutineRunner Instance
{
get
{
if (!instance)
{
var go = new GameObject
{
name = "[ Global Coroutines ]",
hideFlags = HideFlags.HideAndDontSave
};
instance = go.AddComponent<GlobalCoroutineRunner>();
}
return instance;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment