Skip to content

Instantly share code, notes, and snippets.

@margaretdax
Last active March 24, 2021 11:52
Show Gist options
  • Save margaretdax/7a12a01eacf3739b7b72b635ba80cc5b to your computer and use it in GitHub Desktop.
Save margaretdax/7a12a01eacf3739b7b72b635ba80cc5b to your computer and use it in GitHub Desktop.
Tools I used in the development of OX OX OH for fully pausable/resumable "Coroutines" that can be run via Unity Coroutines but is not dependent on Unity at all. The most important thing here is the Run function, which takes a Stack of IEnumerator. The first IEnumerator in the stack passed to run should be whatever you'd normally pass to StartCor…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PausableBehaviour : MonoBehaviour
{
private Stack<IEnumerator> stack = new Stack<IEnumerator>();
private Coroutine stackRoutine;
private void StartStack()
{
if (stack.Count == 0 || stackRoutine != null) return;
stackRoutine = StartCoroutine(RoutineUtils.Run(stack, StopStack));
}
private void StopStack()
{
if (stackRoutine != null)
{
StopCoroutine(stackRoutine);
}
stackRoutine = null;
}
protected void PushTask(IEnumerator task)
{
stack.Push(task);
StartStack();
}
protected virtual void OnEnable()
{
StartStack();
}
protected virtual void OnDisable()
{
StopStack();
}
}
using System;
using System.Collections.Generic;
public static class RoutineUtils
{
public static IEnumerator Run(Stack<IEnumerator> stack)
{
while(stack.Count > 0)
{
bool cont = true;
while (cont && stack.Count > 0)
{
IEnumerator top = stack.Peek();
if (top.MoveNext())
{
if (top.Current is IEnumerator spawned)
{
if(stack.Count > 0)
stack.Push(spawned);
}
else
{
cont = false;
}
}
else
{
if(stack.Count > 0)
stack.Pop();
}
}
if(stack.Count > 0)
yield return null;
}
}
public static IEnumerator Join(List<IEnumerator> iterators)
{
List<Stack<IEnumerator>> stacks = new List<Stack<IEnumerator>>(iterators.Count);
foreach (IEnumerator it in iterators)
{
Stack<IEnumerator> stack = new Stack<IEnumerator>();
stack.Push(it);
stacks.Add(stack);
}
while (stacks.Count > 0)
{
for (int i = stacks.Count - 1; i >= 0; i--)
{
Stack<IEnumerator> stack = stacks[i];
IEnumerator it = stack.Peek();
if (it.MoveNext())
{
if (it.Current is IEnumerator sub)
{
stack.Push(sub);
}
else if (it.Current is AsyncOperation async)
{
stack.Push(WaitAsync(async));
}
}
else
{
stack.Pop();
}
if (stack.Count <= 0)
{
stacks.RemoveAt(i);
}
}
yield return null;
}
iterators.Clear();
}
public static IEnumerator Join(List<IEnumerator> its, Func<bool> keepAlive)
{
IEnumerator joinIterator = Join(its);
while (joinIterator.MoveNext() && (keepAlive == null || keepAlive.Invoke()))
yield return null;
}
public static IEnumerator WaitForSeconds(float seconds)
{
float timeAcc = Time.deltaTime;
while (timeAcc < seconds)
{
yield return null;
timeAcc += Time.deltaTime;
}
}
public static IEnumerator WaitAsync(AsyncOperation asyncOperation)
{
while (!asyncOperation.isDone)
yield return null;
}
public static IEnumerator WaitForFrame(int count = 1)
{
for (int i = 0; i < count; i++)
{
yield return null;
}
}
public static IEnumerator Chain(IEnumerator one, IEnumerator two)
{
yield return one;
yield return two;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment