Controlling time in Unity

Controlling sequential time with suspenders

Activities in Unity are written in C#, allowing them to tie into C#'s powerful enumerator system. This also underlies coroutines in Unity, but activities are vastly more powerful in that they are composable (meaning that a parent activity can control multiple child or service activities) and deeply integrated with other parts of KuteEngine.

All activities define a

protected override IEnumerator MainProcess() { ... }

method which allows them use one of several types of suspenders and thereby control sequential time. The main ones are:

// Do stuff, then
yield return SuspendForDuration(durationInSeconds);

// ...
yield return SuspendUntil(predicate, minDuration, max...);

// ...
yield return SuspendWhile(predicate, minDuration, max...);

// ...
yield return SuspendWorker(worker, minDuration, max...);

// More stuff ...

For overloaded methods, see the API reference. Suspenders also provide built-in support for two additional interfaces: ITerminatable (which permits child/service activities to collaborate with their direct parents over their termination) and IGuard (which are stateful predicates).

Controlling responsive time with monitors

KuteEngine was designed from the ground up as a near real time OS that supports interruptions within a single frame. For activities, this means that they may face termination on a per-frame basis. To stay in control, they can make use of the monitor design pattern, which allows them to pull responsive control out of the sequential flow of the activity. Here's a quick example:

private IEnumerator SomeActivityMonitor(IActivity someActivity)
{
    // wait for an event which requires changing control flow
    yield return new SuspendUntil(somePredicate);
    
    // decide which sibling activity to play after someActivity
    _nextState = State.NextActivity;
    
    // by exiting, someActivity gets automatically terminated
}

Monitors are always paired with a child or service activity. Their key feature is to run in parallel with it and surveil it via predicates. If something happens that requires an immediate response, the monitor can change the control flow. It can also use the activity's public interface in order to force it to adapt in some relevant way. This means that the activity for the most part doesn't need to worry about responsiveness. It can focus on sequential time while the monitor handles responsive time.

Last updated