diff --git a/src/Co.cs b/src/Co.cs
index 9909111..d888ce5 100644
--- a/src/Co.cs
+++ b/src/Co.cs
@@ -25,8 +25,12 @@ private static Coroutine[] GetCoroutines(IEnumerator[] enumerators)
return coroutines;
}
+
public static float DeltaTime => CoroutineManager.Instance.DeltaTime;
public static double DeltaTimeDouble => CoroutineManager.Instance.DeltaTimeDouble;
+
+ public static float PhysicsDeltaTime => CoroutineManager.Instance.PhysicsDeltaTime;
+ public static double PhysicsDeltaTimeDouble => CoroutineManager.Instance.PhysicsDeltaTimeDouble;
public static void Run(CoroutineBase coroutine)
diff --git a/src/CoProcessMode.cs b/src/CoProcessMode.cs
new file mode 100644
index 0000000..fb01b90
--- /dev/null
+++ b/src/CoProcessMode.cs
@@ -0,0 +1,21 @@
+namespace HCoroutines;
+
+///
+/// The ProcessMode determines when the Update() method of a coroutine is called.
+///
+public enum CoProcessMode {
+ ///
+ /// The ProcessMode is inherited from the parent coroutine. If there is no parent, then the Normal mode is used.
+ ///
+ Inherit,
+
+ ///
+ /// The Update() method is called during each process frame (like the _Process() method).
+ ///
+ Normal,
+
+ ///
+ /// The Update() method is called during each physics frame (like the _PhysicsProcess() method).
+ ///
+ Physics
+}
\ No newline at end of file
diff --git a/src/CoroutineBase.cs b/src/CoroutineBase.cs
index e99f724..07c136b 100644
--- a/src/CoroutineBase.cs
+++ b/src/CoroutineBase.cs
@@ -20,6 +20,9 @@ public class CoroutineBase
public bool IsAlive = true;
public bool IsPlaying = false;
+ // TODO: Add way to set this property.
+ public CoProcessMode ProcessMode { get; private set; }
+
public void StartCoroutine(CoroutineBase coroutine)
{
coroutine.Manager = Manager;
@@ -34,7 +37,10 @@ public void StartCoroutine(CoroutineBase coroutine)
///
public virtual void OnEnter()
{
- ResumeUpdates();
+ if (this.ProcessMode == CoProcessMode.Inherit)
+ {
+ this.ProcessMode = Parent?.ProcessMode ?? CoProcessMode.Normal;
+ }
}
///
diff --git a/src/CoroutineManager.cs b/src/CoroutineManager.cs
index f656a19..e915f0c 100644
--- a/src/CoroutineManager.cs
+++ b/src/CoroutineManager.cs
@@ -1,20 +1,22 @@
using Godot;
using System;
-using System.Collections.Generic;
+using HCoroutines.Util;
namespace HCoroutines;
public partial class CoroutineManager : Node
{
public static CoroutineManager Instance { get; private set; }
+
public float DeltaTime { get; private set; }
public double DeltaTimeDouble { get; private set; }
+
+ public float PhysicsDeltaTime { get; private set; }
+ public double PhysicsDeltaTimeDouble { get; private set; }
- private bool isIteratingActiveCoroutines = false;
- private HashSet activeCoroutines = new();
- private HashSet coroutinesToDeactivate = new();
- private HashSet coroutinesToActivate = new();
-
+ private DeferredHashSet activeProcessCoroutines = new();
+ private DeferredHashSet activePhysicsProcessCoroutines = new();
+
public void StartCoroutine(CoroutineBase coroutine)
{
coroutine.Manager = this;
@@ -23,27 +25,31 @@ public void StartCoroutine(CoroutineBase coroutine)
public void ActivateCoroutine(CoroutineBase coroutine)
{
- if (isIteratingActiveCoroutines)
- {
- coroutinesToActivate.Add(coroutine);
- coroutinesToDeactivate.Remove(coroutine);
- }
- else
+ switch (coroutine.ProcessMode)
{
- activeCoroutines.Add(coroutine);
+ case CoProcessMode.Normal:
+ case CoProcessMode.Inherit:
+ activeProcessCoroutines.Add(coroutine);
+ break;
+
+ case CoProcessMode.Physics:
+ activePhysicsProcessCoroutines.Add(coroutine);
+ break;
}
}
public void DeactivateCoroutine(CoroutineBase coroutine)
{
- if (isIteratingActiveCoroutines)
- {
- coroutinesToDeactivate.Add(coroutine);
- coroutinesToActivate.Remove(coroutine);
- }
- else
+ switch (coroutine.ProcessMode)
{
- activeCoroutines.Remove(coroutine);
+ case CoProcessMode.Normal:
+ case CoProcessMode.Inherit:
+ activeProcessCoroutines.Remove(coroutine);
+ break;
+
+ case CoProcessMode.Physics:
+ activePhysicsProcessCoroutines.Remove(coroutine);
+ break;
}
}
@@ -57,9 +63,22 @@ public override void _Process(double delta)
DeltaTime = (float)delta;
DeltaTimeDouble = delta;
- isIteratingActiveCoroutines = true;
+ UpdateCoroutines(activeProcessCoroutines);
+ }
+
+ public override void _PhysicsProcess(double delta)
+ {
+ PhysicsDeltaTime = (float)delta;
+ PhysicsDeltaTimeDouble = delta;
+
+ UpdateCoroutines(activePhysicsProcessCoroutines);
+ }
+
+ private void UpdateCoroutines(DeferredHashSet coroutines)
+ {
+ coroutines.Lock();
- foreach (CoroutineBase coroutine in activeCoroutines)
+ foreach (CoroutineBase coroutine in coroutines.Items)
{
if (coroutine.IsAlive && coroutine.IsPlaying)
{
@@ -74,18 +93,6 @@ public override void _Process(double delta)
}
}
- isIteratingActiveCoroutines = false;
-
- foreach (CoroutineBase coroutine in coroutinesToActivate)
- {
- activeCoroutines.Add(coroutine);
- }
- coroutinesToActivate.Clear();
-
- foreach (CoroutineBase coroutine in coroutinesToDeactivate)
- {
- activeCoroutines.Remove(coroutine);
- }
- coroutinesToDeactivate.Clear();
+ coroutines.Unlock();
}
}
\ No newline at end of file
diff --git a/src/Util/DeferredHashSet.cs b/src/Util/DeferredHashSet.cs
new file mode 100644
index 0000000..20fd20d
--- /dev/null
+++ b/src/Util/DeferredHashSet.cs
@@ -0,0 +1,67 @@
+using System.Collections.Generic;
+
+namespace HCoroutines.Util;
+
+///
+/// HashSet implementation that defers Add() and Remove() calls during iteration.
+///
+public class DeferredHashSet
+{
+ public HashSet Items = new();
+
+ private bool isIterating = false;
+ private HashSet itemsToAdd = new();
+ private HashSet itemsToRemove = new();
+
+ public void Add(T item)
+ {
+ if (isIterating)
+ {
+ itemsToAdd.Add(item);
+ itemsToRemove.Remove(item);
+ }
+ else
+ {
+ Items.Add(item);
+ }
+ }
+
+ public void Remove(T item)
+ {
+ if (isIterating)
+ {
+ itemsToRemove.Add(item);
+ itemsToAdd.Remove(item);
+ }
+ else
+ {
+ Items.Remove(item);
+ }
+ }
+
+ public void Lock()
+ {
+ isIterating = true;
+ }
+
+ public void Unlock()
+ {
+ isIterating = false;
+ ExecutePendingAddRemoves();
+ }
+
+ private void ExecutePendingAddRemoves()
+ {
+ foreach (T item in itemsToAdd)
+ {
+ Items.Add(item);
+ }
+ itemsToAdd.Clear();
+
+ foreach (T item in itemsToRemove)
+ {
+ Items.Remove(item);
+ }
+ itemsToRemove.Clear();
+ }
+}
\ No newline at end of file