CoroutineHandler - markvaaz/ScarletCore GitHub Wiki
CoroutineHandler
is a static system for scheduling, executing, and controlling Unity coroutines with advanced management features. It supports single, repeated, delayed, frame-based, and random interval executions, with full control over pausing, resuming, cancellation, execution limits, and statistics. Ideal for complex asynchronous flows, custom yields, and integration with Unity's coroutine system.
using ScarletCore.Systems;
// Start a coroutine that runs every 2 seconds, 5 times
var id = CoroutineHandler.StartRepeating(() => Log.Info("Running!"), 2f, "MyCoroutine", 5);
// Pause, resume, or stop the coroutine
CoroutineHandler.PauseCoroutine(id);
CoroutineHandler.ResumeCoroutine(id);
CoroutineHandler.StopCoroutine(id);
- Start coroutines with time, frame, or random intervals
- Support for cancellation, pausing, and resuming coroutines
- Control of maximum executions and execution count
- Completion callbacks and custom names for debugging
- Automatic and manual cleanup of completed coroutines
- Query statistics and active coroutine names
- Support for coroutines with cancellation callback (Action)
Some scheduling methods accept an Action<Action>
delegate (with a cancel callback). This allows your coroutine to receive a callback that, when invoked, cancels the coroutine immediately.
This is useful for:
- Stopping a repeating or long-running coroutine from inside itself
- Cancelling based on custom logic or error
- Early exit on condition
- The coroutine action receives a callback parameter (commonly named
cancel
orcancelAction
). - If you call this callback, the coroutine will be marked for cancellation and will not run again.
CoroutineHandler.StartRepeating((cancel) => {
Log.Info($"Tick: {Time.time}");
if (Time.time > 10f) cancel(); // Stop after 10 seconds
}, 1f);
You can use ActionWithCancel in all repeating and random interval methods:
StartRepeating(Action<Action> actionWithCancel, float delay, string name = null, int maxExecutions = -1)
StartFrameRepeating(Action<Action> actionWithCancel, int frameInterval, string name = null, int maxExecutions = -1)
StartRandomInterval(Action<Action> actionWithCancel, float minDelay, float maxDelay, string name = null, int maxExecutions = -1)
Tip: If you don't need cancellation, use the simpler Action
overloads.
Executes an action after a delay.
var id = CoroutineHandler.StartGeneric(() => Log.Info("Delayed!"), 2f);
Parameters:
-
action
- Action to execute -
delay
- Delay in seconds -
name
- Optional name
Returns: CoroutineId
for control
Executes repeatedly at time intervals (seconds).
var id = CoroutineHandler.StartRepeating(() => Log.Info("Repeating!"), 1f, "Repeat", 5);
Or with cancellation support:
var id = CoroutineHandler.StartRepeating(cancel => {
if (shouldStop) cancel();
else Log.Info("Still running");
}, 1f);
Parameters:
-
action
- Action to execute (can beAction
orAction<Action>
) -
delay
- Interval in seconds -
name
- Optional name -
maxExecutions
- Maximum executions (-1 for infinite)
Returns: CoroutineId
for control
Executes repeatedly at frame intervals.
var id = CoroutineHandler.StartFrameRepeating(() => Log.Info("Every 10 frames!"), 10);
Or with cancellation support:
var id = CoroutineHandler.StartFrameRepeating(cancel => {
if (shouldStop) cancel();
}, 10);
Parameters:
-
action
- Action to execute (can beAction
orAction<Action>
) -
frameInterval
- Interval in frames -
name
- Optional name -
maxExecutions
- Maximum executions (-1 for infinite)
Returns: CoroutineId
for control
Executes repeatedly at random intervals in seconds.
var id = CoroutineHandler.StartRandomInterval(() => Log.Info("Random interval!"), 1f, 5f);
Or with cancellation support:
var id = CoroutineHandler.StartRandomInterval(cancel => {
if (shouldStop) cancel();
}, 1f, 5f);
Parameters:
-
action
- Action to execute (can beAction
orAction<Action>
) -
minDelay
- Minimum interval -
maxDelay
- Maximum interval -
name
- Optional name -
maxExecutions
- Maximum executions (-1 for infinite)
Returns: CoroutineId
for control
Executes an action on the next frame.
var id = CoroutineHandler.NextFrame(() => Log.Info("Next frame!"));
Parameters:
-
action
- Action to execute -
name
- Optional name
Returns: CoroutineId
for control
Stops and removes a coroutine.
CoroutineHandler.StopCoroutine(id);
Parameters:
-
id
- CoroutineId
Returns: True if found and stopped
Pauses or resumes a coroutine.
CoroutineHandler.PauseCoroutine(id);
CoroutineHandler.ResumeCoroutine(id);
Parameters:
-
id
- CoroutineId
Pauses or resumes all active coroutines.
CoroutineHandler.PauseAllCoroutines();
CoroutineHandler.ResumeAllCoroutines();
Toggles the pause state of a coroutine.
CoroutineHandler.TogglePauseCoroutine(id);
Returns: True if paused, false if resumed or not found
Stops all managed coroutines.
CoroutineHandler.StopAllCoroutines();
Checks if a coroutine is running or paused.
CoroutineHandler.IsCoroutineRunning(id);
CoroutineHandler.IsCoroutinePaused(id);
Query executions performed, limit, and remaining executions for a coroutine.
var execs = CoroutineHandler.GetExecutionCount(id);
var max = CoroutineHandler.GetMaxExecutions(id);
var left = CoroutineHandler.GetRemainingExecutions(id);
List names of active coroutines.
var names = CoroutineHandler.GetActiveCoroutineNames();
Returns aggregate statistics (active, inactive, infinite, limited, total executions, auto-cleanup).
var stats = CoroutineHandler.GetCoroutineStatistics();
Returns how long a coroutine has been paused.
var duration = CoroutineHandler.GetPauseDuration(id);
Number of active coroutines.
var count = CoroutineHandler.ActiveCoroutineCount;
Removes finished or invalid coroutines, invoking completion callbacks.
CoroutineHandler.CleanupCompletedCoroutines();
Enables/disables periodic automatic cleanup.
CoroutineHandler.EnableAutoCleanup(30f); // every 30 seconds
CoroutineHandler.DisableAutoCleanup();
Forces cleanup of coroutines by criteria (inactive, completed, all).
CoroutineHandler.ForceCleanup(onlyInactive: true);
// Executes an action every second, 5 times
var id = CoroutineHandler.StartRepeating(() => Log.Info("Tick!"), 1f, "TickCoroutine", 5);
CoroutineHandler.StartRepeating(cancel => {
if (SomeCondition()) cancel();
else Log.Info("Still running");
}, 1f);
CoroutineHandler.PauseCoroutine(id);
CoroutineHandler.ResumeCoroutine(id);
CoroutineHandler.StopCoroutine(id);
- Coroutines are identified by a unique, thread-safe
CoroutineId
-
Do NOT call Unity's
StartCoroutine
directly for managed coroutines – always useCoroutineHandler
methods for tracking and control - Coroutines can be paused and resumed at yield points
- Completion callbacks (
OnComplete
) are called on both natural completion and cancellation - Use
EnableAutoCleanup
in long-running systems to avoid memory leaks - The system is thread-safe for control operations, but actions executed in coroutines should be thread-safe if accessing shared resources
While CoroutineHandler
is ideal for complex asynchronous flows, custom yields, and integration with Unity's coroutine system, there are scenarios where ActionScheduler
is a better fit:
-
Simple timed, repeated, or delayed actions: Use
ActionScheduler
for most simple automation, timers, or event sequences. -
Performance-critical bulk scheduling:
ActionScheduler
is optimized for lightweight, high-frequency actions. -
No need for custom yields or Unity yield instructions: If you don't need to yield for Unity objects/events or use
WaitForSeconds
, preferActionScheduler
.
Tip: Use
CoroutineHandler
for advanced coroutine control, custom yields, or when you need to interact with Unity's coroutine/yield system. UseActionScheduler
for most simple, repeated, or delayed actions.