Skip to content

Instantly share code, notes, and snippets.

@oliverbooth
Last active January 3, 2024 23:24
Show Gist options
  • Save oliverbooth/b9ef25fa23d1d1e68f912a9a00f12fb7 to your computer and use it in GitHub Desktop.
Save oliverbooth/b9ef25fa23d1d1e68f912a9a00f12fb7 to your computer and use it in GitHub Desktop.
A barebones recreation of Unity's coroutine system, complete with an example behaviour.
using System.Collections;
public abstract class Behaviour
{
private readonly List<Stack<IEnumerator>> _activeCoroutines = new();
public virtual void Start()
{
}
public virtual void Update()
{
}
protected void StartCoroutine(IEnumerator coroutine)
{
_activeCoroutines.Add(new Stack<IEnumerator>(new[] {coroutine}));
}
internal void UpdateCoroutines()
{
for (int index = 0; index < _activeCoroutines.Count; index++)
{
Stack<IEnumerator> instructions = _activeCoroutines[index];
if (instructions.Count == 0)
{
_activeCoroutines.RemoveAt(index);
index--; // avoid skipping the next element
continue;
}
IEnumerator instruction = instructions.Peek();
if (!instruction.MoveNext())
{
instructions.Pop();
continue;
}
if (instruction.Current is IEnumerator next && instruction != next)
instructions.Push(next);
}
}
}
using System.Collections;
public class MySimpleBehaviour : Behaviour
{
public override void Update()
{
Console.Title = $"Running at {1 / Time.DeltaTime:F0} fps";
}
public override void Start()
{
StartCoroutine(Foo());
StartCoroutine(Bar());
}
private IEnumerator Foo()
{
yield return Foo2();
Console.WriteLine("Foo finished!");
}
private IEnumerator Foo2()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
yield return new WaitForSeconds(1);
}
Console.WriteLine("Foo2 finished!");
}
private IEnumerator Bar()
{
yield return new WaitForSeconds(1);
Console.WriteLine("Bar finished!");
}
}
internal static class Program
{
private static readonly List<Behaviour> BehaviourList = new();
private static void Main()
{
BehaviourList.Add(new MySimpleBehaviour());
foreach (Behaviour behaviour in BehaviourList)
{
behaviour.Start();
}
long lastFrameTime = DateTime.Now.Ticks;
while (true)
{
// game loop
long frameTime = DateTime.Now.Ticks;
long deltaTime = frameTime - lastFrameTime;
lastFrameTime = frameTime;
Time.DeltaTime = (float) TimeSpan.FromTicks(deltaTime).TotalSeconds;
foreach (Behaviour behaviour in BehaviourList)
{
behaviour.Update();
behaviour.UpdateCoroutines();
}
Thread.Sleep(10);
}
}
}
public static class Time
{
public static float DeltaTime { get; internal set; }
}
using System.Collections;
internal class WaitForSeconds : IEnumerator
{
private readonly DateTime _endTime;
public WaitForSeconds(float seconds)
{
_endTime = DateTime.Now + TimeSpan.FromSeconds(seconds);
}
public object Current => null;
public bool MoveNext() => DateTime.Now < _endTime;
public void Reset() { } // not important
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment