Skip to content

Scriptable Sequence

Generic system for playing an ordered list of async steps set up as assets. Steps share a context with a typed blackboard, and can branch, run sub-sequences, jump back to an earlier step and undo their visuals on cancel.

Concepts

Sequence and steps

  • Sequence is a ScriptableObject holding an ordered list of SequenceStep assets.
  • SequenceStep is the base of a step asset. Override PlayAsync to do the work. The step completes when the returned task completes. Step assets are shared between runs, so keep run state in the context, not in fields.
  • ISequenceStep is the same contract for steps built in code that cannot be assets (see RunSubSequenceStep).

Context and blackboard

  • SequenceContext is passed to every step of a run. It gives the EntityManager, the EntityQueryCache and a SequenceBlackboard. Inherit from it to add game specific data.
  • SequenceBlackboard is a typed key-value store for passing data between steps. Keys are BlackboardKey<T> assets, so a value is found by asset reference, not by string.

Playing

  • SequenceRunner.PlayAsync plays the steps one by one with a given context and cancellation token. It does not own the context and does not dispose anything.
  • SequencePlayer owns a single run. Play cancels the running sequence, if any, and starts the new one. It takes ownership of the context and disposes the steps and the context when the run ends, in any way. IsPlaying tells whether a run is still going, including one that is still unwinding after a cancel.

Revert

A step can jump back to an earlier step of the same list. Override RevertTargetStep and WaitForRevertConditionAsync. While the step runs, the runner races PlayAsync against the condition. When the condition wins, PlayAsync is cancelled, OnRevert is called and the runner continues from the target step. Override OnRevert to undo what the step put on screen.

Cancel

SequencePlayer.Cancel(), and Play() when it replaces a running sequence, call OnCancel of every step the cancelled run already started, in reverse start order, before they return. This also covers steps that are already done, for example a highlight left for a later step that will never run. Override OnCancel to undo such visuals. It must work when the step is not running and when its visuals were already removed.

SequencePlayer.Dispose() cancels without calling OnCancel, because the owner may already be going away.

Built-in steps

Step                     Description
──────────────────────── ─────────────────────────────────────────────────────────────────────
DelayStep                Waits a fixed number of seconds.
WaitUntilStep            Waits until a SequenceCondition is true, checked every frame.
ConditionalSequenceStep  Plays one of two sequences depending on a SequenceCondition.
RunSequenceStep          Plays another Sequence with the same context.
RunSubSequenceStep       Plays a list of steps with its own context. Built in code, not an asset.

SequenceCondition is the base of a condition asset used by the branching and waiting steps.

Usage

SequencePlayer player = new(destroyCancellationToken);

SequenceContext context = new(queryCache);
player.Play(sequence, context);

// Later, when the flow must stop early
player.Cancel();