Last active
January 3, 2024 23:24
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class Time | |
{ | |
public static float DeltaTime { get; internal set; } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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