Documentation
Sub Routines
Small, chainable background tasks for Unity. Each one is a condition and an action, checked once a frame.
- Version 1.1.0
- Unity 2021.3 LTS and newer, including Unity 6
Sub Routines gives you small background tasks in Unity without writing a coroutine for every little thing. Each sub routine is just a condition and an action. Every frame the condition is checked, and while it's true the action runs. When it turns false, an optional callback runs and the sub routine tidies itself away.
On top of that you get a handful of ready-made helpers (Wait, RunFor, When, Repeat and friends) and a way to chain them so they run one after another.
The source is fully commented, so if something here isn't clear, the scripts are a good second place to look. Or just email us.
1. Getting started
Import the package, then add the namespace at the top of your script:
using MugHeadStudios;
That's it. There's nothing to add to your scene. The first time you create a sub routine, a small helper object is made for you.
SubRoutines.Chain(
SubRoutines.RunFor(1f, t => transform.localScale = Vector3.one * t),
SubRoutines.Wait(0.5f, () => Debug.Log("Half a second later")),
SubRoutines.Do(() => Debug.Log("Done"))
);
There's a demo scene in Tests/Runtime/SubRoutinesDemo.unity if you'd like to see it running. It uses the built-in UI (uGUI) package.
If your own scripts live in an assembly definition, add a reference to MugHeadStudios.SubRoutines. Scripts in the default Assembly-CSharp don't need anything.
2. The SubRoutines methods
SubRoutines is a static class with everything you need to start sub routines. Every method returns the SubRoutine it created, so you can keep hold of it, pause it or remove it later.
Always(Action action)
Runs an action every frame, until you remove it.
SubRoutines.Always(() => {
// Runs every frame
});
Wait(float time, Action action)
Waits for a number of seconds, then runs the action once.
SubRoutines.Wait(1f, () => {
// Runs after one second
});
RunFor(float time, Action<float> action, Action callback = null)
Runs the action every frame for a number of seconds. It's passed t, the progress from 0 to 1. The callback runs at the end.
SubRoutines.RunFor(2f, t => {
// t goes from 0 to 1 over two seconds
}, () => {
// Runs once the time is up
});
When(Func<bool> condition, Action action)
Waits until the condition is true, then runs the action once.
SubRoutines.When(() => player.isGrounded, () => {
// Runs once the player lands
});
While(Func<bool> condition, Action action, Action callback = null)
The one all the others are built on. Runs the action every frame while the condition is true. Once it's false, the callback runs and the sub routine is removed.
SubRoutines.While(() => health < maxHealth, () => {
health += regenPerSecond * Time.deltaTime;
}, () => {
// Runs once fully healed
});
RunNextFrame(Action action)
Waits one frame, then runs the action.
SubRoutines.RunNextFrame(() => {
// Runs on the next frame
});
RunAfterXFrames(int numFrames, Action action)
Waits a number of frames, then runs the action.
SubRoutines.RunAfterXFrames(60, () => {
// Runs after 60 frames
});
RunForXFrames(int numFrames, Action<int> action, Action callback)
Runs the action every frame for a number of frames. It's passed f, the number of frames so far. The callback runs on the last frame.
SubRoutines.RunForXFrames(60, f => {
// Runs every frame for 60 frames
}, () => {
// Runs when all 60 frames are done
});
Do(Action action)
Runs the action straight away. On its own that's no different from calling the code yourself, but it's handy inside a chain.
SubRoutines.Do(() => {
// Runs immediately
});
Repeat(int repeat, float interval, Action<int> action, Action callback = null)
Runs the action a number of times, with a gap of interval seconds between each. It's passed r, the current repeat. Use -1 to repeat forever. The callback runs after the last one.
SubRoutines.Repeat(10, 0.3f, r => {
// Runs 10 times, 0.3 seconds apart
}, () => {
// Runs after the last repeat
});
Chain(params SubRoutine[] subRoutines)
Runs sub routines one after another, waiting for each to finish before starting the next. See section 5.
SubRoutines.Chain(
SubRoutines.Do(() => { /* Straight away */ }),
SubRoutines.Wait(1f, () => { /* 1 second later */ }),
SubRoutines.Wait(1f, () => { /* 2 seconds later */ })
);
GetInstance()
Returns the SubRoutinesGameObject that runs everything.
SubRoutines.GetInstance();
RemoveSubRoutine(SubRoutine subRoutine)
Stops and removes one sub routine.
var spin = SubRoutines.Always(() => transform.Rotate(0, 90 * Time.deltaTime, 0));
// Later
SubRoutines.RemoveSubRoutine(spin);
RemoveAllSubRoutines()
Stops and removes every running sub routine.
SubRoutines.RemoveAllSubRoutines();
3. The SubRoutine class
This is the sub routine object itself. You'll normally get these from the SubRoutines methods above rather than making them yourself, but you can if you want something custom.
Properties
| Property | What it does |
|---|---|
Func<bool> condition |
Checked every frame. |
Action action |
Runs every frame while the condition is true. |
Action callback |
Runs once when the condition becomes false. |
bool paused |
While true, nothing is checked or run. Read only. |
SubRoutine chainedRoutine |
The next sub routine in a chain. It's un-paused when this one finishes. Read only. |
Methods
Constructor. Sets the condition, action and callback, and starts running straight away.
public SubRoutine(Func<bool> _condition, Action _action, Action _callback = null)
Pause. Pauses or resumes the sub routine. Sub routines in a chain are paused for you until it's their turn, but you can override that.
public SubRoutine Pause(bool pause)
ChainedRoutine. Sets the sub routine that should run after this one. The one you pass in is paused until this one finishes.
public SubRoutine ChainedRoutine(SubRoutine subRoutine)
Run. Called for you once a frame. You shouldn't need to call it yourself. It returns false once the sub routine has finished, so it can be removed.
4. How it runs each frame
The first sub routine you create adds a hidden helper object called "SubRoutines" to the active scene. It holds the list of running sub routines and runs each one in Unity's normal Update. That means Time.deltaTime and other time values are always correct inside your actions and callbacks.
The helper lives in the MugHeadStudios.Internal namespace. You shouldn't need to touch it, apart from the one tip in section 6.
5. Chains
A chain runs sub routines in order, waiting for each one to finish before moving on. There are two ways to make one.
With SubRoutines.Chain (the easy way):
SubRoutines.Chain(
SubRoutines.Wait(1f, () => Debug.Log("One")),
SubRoutines.Wait(1f, () => Debug.Log("Two")),
SubRoutines.Wait(1f, () => Debug.Log("Three"))
);
With ChainedRoutine:
SubRoutines.Wait(1f, () => Debug.Log("One"))
.ChainedRoutine(SubRoutines.Wait(1f, () => Debug.Log("Two")));
Chains can be nested. Each nested chain runs alongside the others by default.
6. Notes and limits
- Sub routines only run in play mode. Creating one outside play mode logs a warning.
- They use
Time.deltaTime, so they respectTime.timeScale. - The helper object (and every running sub routine) is removed when its scene unloads. To keep them running across scene loads, call this once:
DontDestroyOnLoad(SubRoutines.GetInstance().gameObject); - If a sub routine throws an error, for example because it touches an object that's been destroyed, the error is logged and just that one is removed. The rest keep running.
- Works with Enter Play Mode Options when domain reload is turned off.
- Supports Unity 2021.3 LTS and newer, including Unity 6.
7. Contact
Found a bug, or something in here doesn't make sense? Email us at [email protected]. We read everything and we're happy to help.