Source: Decorator.cs - Last Updated: 2019.7.30
This section introduces decorators; builtin decorators are documented here; read Custom Decorators if you wish to implement your own.
A decorator modulates the behavior of a target task. Common decorators are implemented via the status
class: unary operations let you invert (!), condone (~), promote (+, ++) and demote (-, --) statuses; if this is not enough, use Status.Map()
.
Beyond, the API provides a set of powerful, easy to use constructs properly known as 'decorators'. Mostly, these decorators follow a common syntax:
Decorator( Params ) ? [ StatusExp ]
Under the hood, most decorators are stateful conditionals:
- Decorators require storage - be it a cooldown or latch, data is stored to keep track of the current state; for this reason, syntax does vares depending on whether you inline decorators (and let the API manage storage on your behalf) or manually declare the decorator.
- Depending on how
Decorator( Params )
evaluates,[ StatusExp ]
may be evaluated, or skip.
Since decorators are stateful, on occasion their state must reset. While you may explicitly Reset()
a stateful decorator, several features help you manage the decorator life cycle.
- Inline decorators automatically reset when the associate
Task
/UTask
is reset. - Decorators enclosed within a
with(arg)[ exp ]
orroe[ exp ]
block reset when an argument changes state (with
) or the enclosed expression returnsdone
orfail
(reset-on-exit /roe
); read more about reset management here.
Auto-reset features (RoE, RoR) are detailed here
Within a Task/UTask
, you may use decorators inline. Let's apply a 0.1 seconds cooldown to a Fire()
action:
status s = Cooldown(0.1f)?[ Fire() ];
In the above example Task (or UTask) manage the underlying data (the timestamp) on your behalf. This is convenient, but comes with small memory/performance overheads. You also cannot reset the decorator on its own (but you can reset all decorators associated with a task Via its Reset()
method).
Without a task context (or if you do not wish to use the inline syntax), declare the decorator before use:
// Field declaration
public Cooldown overheat = 0.1f;
// Anywhere in your code
status s = overheat.pass?[ Fire() ]; // (1)
// or...
status s = overheat[0.2f]?[ Fire() ]; // (2)
In the above example, (1) depicts the parameterless syntax; (2) depicts the parameterized syntax; decorators implementing the OptionalArguments
interface support the parameterless syntax.
Making the decorator public allows customization Via the Unity inspector. You then manage the decorator's life cycle:
-
Manually, by invoking
overheat.Reset()
ornull
-ing the decorator. -
If you are using
Task
orUTask
, you can still register the decorator:
class Gunner
{
public Cooldown overheat = 0.1f;
protected void Start() => Register(overheat);
}
- Implicitly, by letting the decorator 'expire' when the owning object is destroyed.