On this page
- Scripting Reference
- Core API
- Core Types
Statement(owner)StatementState(owner, name)StatementStateTemplate(name)eStatementEventseStatementUpdateModeeStatementResetModeeStatementErrorBehavioreStatementLensModeeStatementLensOverlayeStatementHeatMetriceStatementDebugEdgeKindeStatementDebugEdgeStyleSTATEMENT_DEBUGSTATEMENT_TIME_GLOBAL_SCALE
- Core Statement Methods
AddState(state)AddStateTemplate(template, [config], [name], [clone])SetInitialState(name)SetResetMode(mode)SetInheritPause(enabled)SetInheritTimeScale(enabled)GetState([name])GetStateName()IsInState(name_or_state)GetChildMachine()GetChildState()IsInPath(path)IsIn(name_or_state)GetCurrentStateName()EnsureState(name, [data], [force])ChangeState(name, [data], [force])UpdateDelta([dt])Update()Draw()GetStateTime()SetStateTime(time)ClearStates()
- Core StatementState Methods
- Core Types
- Advanced API
- Pausing
- Update Modes and Time Scaling
- Queueing
- History & Introspection
- State Stack (Push / Pop)
- Submachines (StatementState)
- State Change Hook
- Low-Level Event Running
- Exit Control & Declarative Transitions (StatementState)
- Per-State Timers (Advanced)
- State Templates (Advanced)
SetConfigClone(enabled)AddStateEvent(event, fn)AddEnter(fn)AddUpdate(fn)AddExit(fn)AddDraw(fn)AddTransition(target_name, condition, [data], [force])ClearTransitions()DebugLinkTo(target_name)DebugPayload(payload)DebugBreakOnEnter([break_on_enter])DebugTag(tag)Build(owner, [config], [name], [clone])
- Cleanup & Global Helpers
- Debug API (Machine & State)
- Machine debug controls
ClearDebugTransitionHistory()DebugJumpToState(name, force)DebugPause()DebugResume()DebugSetErrorBehavior(behavior)DebugSetLogErrorsToFile(log_to_file)DebugStep()DebugTag(tag)GetDebugGraph()GetDebugName()GetDebugStateStats()GetDebugTag()GetDebugTransitionHistory()IsDebugEnabled()SetDebugEnabled(enabled)SetDebugName(name)
- State-level debug helpers
- Global debug helpers
- Machine debug controls
- Visual Debugger & Debug UI
- Core API
Scripting Reference
This page documents the public API of the state machine system.
It’s split into:
- Core API - recommended reading for everyone.
- Advanced API - optional tools for more complex behaviours.
Core API
Core Types
Statement(owner)
Create a state machine bound to the given owner instance or struct.
state_machine = new Statement(self);
owner:Id.InstanceorStruct- Returns:
Struct.Statement
StatementState(owner, name)
Create a new state bound to the given owner.
idle = new StatementState(self, "Idle");
owner:Id.InstanceorStructname:String- Returns:
Struct.StatementState
If owner is neither an existing instance nor a struct, the constructor logs a severe debug message and returns undefined.
StatementStateTemplate(name)
Create a reusable template for building StatementState instances.
var idle_template = new StatementStateTemplate("Idle");
name:String- Returns:
Struct.StatementStateTemplate
Templates store handlers, transitions, and debug metadata that can be applied to multiple states. Build states with template.Build(owner, [config], [name], [clone]) or Statement.AddStateTemplate(...).
eStatementEvents
Event slots used by states.
Values include:
eStatementEvents.ENTEReStatementEvents.EXITeStatementEvents.STEPeStatementEvents.DRAWeStatementEvents.NUM- sentinel for internal sizing.
eStatementUpdateMode
Controls how UpdateDelta processes accumulated time.
Values include:
eStatementUpdateMode.ACCUMULATEDeStatementUpdateMode.PER_FRAME
eStatementResetMode
Controls how a submachine is reset or paused when its host state exits or enters.
Values include:
eStatementResetMode.RESET_ON_EXITeStatementResetMode.REMEMBEReStatementResetMode.RESET_ON_ENTER
eStatementErrorBehavior
Controls how caught errors are handled in debug mode.
Values include:
eStatementErrorBehavior.PAUSEeStatementErrorBehavior.RETHROW
eStatementLensMode
Lens layout modes.
Values include:
eStatementLensMode.FULLeStatementLensMode.EGOeStatementLensMode.RADIALeStatementLensMode.CLOUD
eStatementLensOverlay
Lens overlay modes.
Values include:
eStatementLensOverlay.NONEeStatementLensOverlay.HEATMAP
eStatementHeatMetric
Heatmap metrics used by the Lens overlay.
Values include:
eStatementHeatMetric.TIMEeStatementHeatMetric.VISITS
eStatementDebugEdgeKind
Edge types used in debug graphs.
Values include:
eStatementDebugEdgeKind.DECLARATIVEeStatementDebugEdgeKind.OBSERVEDeStatementDebugEdgeKind.MANUAL
eStatementDebugEdgeStyle
Edge style categories used by the Lens renderer.
Values include:
eStatementDebugEdgeStyle.STRUCTURALeStatementDebugEdgeStyle.LAST_TRANSITIONeStatementDebugEdgeStyle.QUEUEDeStatementDebugEdgeStyle.HISTORY
STATEMENT_DEBUG
Global toggle for Statement debug features.
Set to 0 to compile without debug tracking.
STATEMENT_TIME_GLOBAL_SCALE
Global time scale applied to all Statement machines. This is used by StatementSetGlobalTimeScale.
Core Statement Methods
AddState(state)
Register a StatementState on this machine.
state_machine.AddState(idle);
state:Struct.StatementState- Returns:
Struct.Statement
The first state added becomes the default initial state. If auto_enter_first_state is true (default) and there is no active state yet, the machine enters it immediately and runs its Enter handler if defined. Set auto_enter_first_state to false if you want to delay entry until you call ChangeState or SetInitialState.
If a state with the same name already exists, it is replaced (with a warning).
Requires a state struct built from StatementState.
AddStateTemplate(template, [config], [name], [clone])
Build a state from a StatementStateTemplate and add it to this machine.
state_machine.AddStateTemplate(idle_template);
state_machine.AddStateTemplate(idle_template, { speed: 2 }, "IdleFast");
template:Struct.StatementStateTemplateconfig(optional):Any- config payload for the built state.name(optional):String- override the template’s state name.clone(optional):Bool- override the template’s config cloning.- Returns:
Struct.Statement
Uses this machine’s owner when building the state. Logs a severe debug message if the template is invalid.
SetInitialState(name)
Set which state name should be treated as the initial state when the machine starts.
state_machine.SetInitialState("Idle");
name:String- Returns:
Struct.Statement
If you do not call this, the first state added becomes the default initial state. If the named state does not exist yet, it will be used when it is added.
SetResetMode(mode)
Set how this machine behaves when it is hosted as a submachine and the parent state exits or enters.
state_machine.SetResetMode(eStatementResetMode.RESET_ON_EXIT);
mode:Constant.eStatementResetMode- Returns:
Struct.Statement
Modes:
RESET_ON_EXIT: stop the submachine when the host exits.REMEMBER: pause the submachine when the host exits and resume on enter.RESET_ON_ENTER: stop the submachine and restart fresh when the host enters.
Default is RESET_ON_EXIT.
SetInheritPause(enabled)
Control whether a submachine inherits pause state from its parent machine.
state_machine.SetInheritPause(true);
enabled:Bool- Returns:
Struct.Statement
Default is true.
SetInheritTimeScale(enabled)
Control whether a submachine inherits time scaling from its parent machine.
state_machine.SetInheritTimeScale(false);
enabled:Bool- Returns:
Struct.Statement
Default is false.
GetState([name])
Get a state by name, or the current state if no name is provided.
var _current = state_machine.GetState();
var _idle = state_machine.GetState("Idle");
name(optional):String- Returns:
Struct.StatementStateorUndefinedif not found / no current state.
Logs a warning if a named lookup fails.
GetStateName()
Get the name of the current state.
var _name = state_machine.GetStateName();
- Returns:
StringorUndefined.
IsInState(name_or_state)
Check whether the current state matches the supplied name or state struct.
if (state_machine.IsInState("Hurt")) {
// Already in the Hurt state.
}
if (state_machine.IsInState(my_attack_state)) {
// Using a direct state reference.
}
name_or_state:StringorStruct.StatementState- Returns:
Bool
Accepts either a state name or a StatementState struct. If called with an unsupported type or when there is no active state, it returns false (and logs a warning for unsupported types). If you pass a struct, it must be built from StatementState.
GetChildMachine()
Return the active submachine hosted by the current state, if any.
var _child = state_machine.GetChildMachine();
- Returns:
Struct.StatementorUndefined.
GetChildState()
Return the active state of the current state’s submachine, if any.
var _child_state = state_machine.GetChildState();
- Returns:
Struct.StatementStateorUndefined.
IsInPath(path)
Check whether the machine is in a nested state path such as Idle/Move/Run.
if (state_machine.IsInPath("Combat/Attack")) {
// Host in Combat and submachine in Attack
}
path:String- Returns:
Bool
The path is split on / and compared against the current state and any nested submachines in order.
IsIn(name_or_state)
Alias for IsInState.
if (state_machine.IsIn("Hurt")) {
// same as IsInState
}
name_or_state:StringorStruct.StatementState- Returns:
Bool
GetCurrentStateName()
Alias for GetStateName.
var _name = state_machine.GetCurrentStateName();
- Returns:
StringorUndefined.
EnsureState(name, [data], [force])
Ensure that the current state matches the supplied name. If it is already active, no transition occurs.
// Make sure we are in Idle; only changes if needed.
state_machine.EnsureState("Idle");
// Ensure Hurt with a payload.
state_machine.EnsureState("Hurt", { damage: _damage });
name:Stringdata(optional):Any- payload attached to the transition if a change is required.force(optional):Bool- Returns:
Struct.StatementStateorUndefinedif the target does not exist.
Internally this is equivalent to checking the current state’s name and only calling ChangeState when different, which avoids redundant transitions and Exit/Enter calls.
ChangeState(name, [data], [force])
Immediately change to another state, optionally with a transition payload.
state_machine.ChangeState("Attack");
state_machine.ChangeState("Hitstun", { damage: 5 }, true); // payload + force
name:Stringdata(optional):Any- payload retrievable viaGetLastTransitionData().force(optional):Bool- Returns:
Struct.StatementStateorUndefinedif target doesn’t exist.
Behaviour:
- If target does not exist: logs a severe debug message and returns
undefined. - If target is already active: does nothing and returns current state.
- If current state has
can_exit == falseandforce == false: refuses to change and returns current state. - If the current state hosts a submachine with an exit gate (see
LockExitUntilSubInandLockExitWhileSubNot) andforce == false, the change is blocked. - A manual
ChangeStateclears any queued transition before switching. - Otherwise:
- Runs old state
Exit(if present). - Updates history (
previous_state,previous_states). - Switches
stateto the new state. - Resets
state_ageto 0. - Runs optional state-change hook (see
SetStateChangeBehaviour). - Runs new state
Enter(if present).
- Runs old state
If an Exit handler changes state itself, the outer ChangeState respects that redirect and returns immediately.
UpdateDelta([dt])
Drive the state machine using a delta value. The delta is scaled by the machine time scale and the global time scale.
// Step Event with a real delta source
state_machine.UpdateDelta(delta_time / 1000000);
dt(optional):Real- unscaled delta to apply. Defaults to 1.- Returns: whatever the state’s Update handler returns, or
Undefinedif no Step ran or there is no active state.
When update mode is eStatementUpdateMode.ACCUMULATED, the machine runs Step once per whole accumulated tick and advances state age by fractional time. When update mode is eStatementUpdateMode.PER_FRAME, the machine runs Step once per call. Use SetUpdateMode to control this.
Update()
Drive the state machine for one Step.
// Step Event
state_machine.Update();
This is a legacy convenience wrapper for UpdateDelta(1).
Draw()
Optional helper to run the current state’s Draw handler.
// Draw Event
state_machine.Draw();
- Returns: whatever the state’s Draw handler returns, or
Undefinedif not implemented.
Use only if you want per-state drawing.
GetStateTime()
Get the scaled time since the current state was entered. This value is advanced by UpdateDelta and respects time scaling.
if (state_machine.GetStateTime() > game_get_speed(gamespeed_fps) * 0.5) {
// half a second at 60 FPS
}
- Returns:
Real
Automatically reset on each state change.
SetStateTime(time)
Manually set the current state’s age in scaled time units.
state_machine.SetStateTime(0);
time:Real- Returns:
Struct.Statement
ClearStates()
Clear all states and reset the machine.
state_machine.ClearStates();
Clears:
states,states_arraystate,previous_state,previous_statesstate_stack- any queued state
state_ageinitial_state_namelast_transition_data
Returns the machine for chaining.
Core StatementState Methods
AddEnter(fn)
Bind an Enter handler that runs once when the state becomes active.
idle.AddEnter(function() {
sprite_index = spr_player_idle;
});
fn:Function- automaticallymethod(owner, fn)bound. In other words, the scope of the function runs from whoever has been supplied as the owner of the state (most often the instance running the state machine itself). This behaviour extends through to all thefnarguments in the other threeAdd*()methods below.- Returns:
Struct.StatementState
AddUpdate(fn)
Bind an Update handler that runs every Step while the state is active.
idle.AddUpdate(function() {
// Idle behaviour
});
fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.StatementState
AddExit(fn)
Bind an Exit handler that runs once when the state stops being active.
idle.AddExit(function() {
EchoDebugInfo("Leaving Idle");
});
fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.StatementState
AddDraw(fn)
Bind a Draw handler that runs each Draw while the state is active if you call Statement.Draw().
idle.AddDraw(function() {
draw_self();
});
fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.StatementState
SetConfig(config, [clone])
Assign configuration data to this state, optionally cloning the input.
state.SetConfig({ speed: 2 });
state.SetConfig(config, false); // keep reference (no clone)
config:Anyclone(optional):Bool- override this state’s config clone setting.- Returns:
Struct.StatementState
By default, state config is cloned when assigned. Use StatementStateTemplate.SetConfigClone to change the default for template-built states.
GetConfig()
Get the current config data for this state.
var _cfg = state.GetConfig();
- Returns:
AnyorUndefined
Advanced API
The following features are optional. You can ignore them unless your project specifically benefits from them.
Pausing
SetPaused(paused)
Pause or resume the state machine. When paused, Update() skips queue processing, STEP handlers, declarative transitions, and state age increments. Manual ChangeState calls still work.
state_machine.SetPaused(true); // freeze
state_machine.SetPaused(false); // resume
paused:Bool- Returns:
Struct.Statement
IsPaused()
Check whether the machine is currently paused.
if (state_machine.IsPaused()) { /* skip logic */ }
- Returns:
Bool
Update Modes and Time Scaling
SetUpdateMode(mode)
Set how UpdateDelta processes the machine.
state_machine.SetUpdateMode(eStatementUpdateMode.ACCUMULATED);
mode:Constant.eStatementUpdateMode- Returns:
Struct.Statement
Modes:
ACCUMULATED: accumulate time and run Step once per whole tick.PER_FRAME: run Step once per call toUpdateDelta.
GetUpdateMode()
Get the current update mode for this machine.
var _mode = state_machine.GetUpdateMode();
- Returns:
Constant.eStatementUpdateMode
StatementSetDefaultUpdateMode(mode)
Set the global default update mode used by newly created machines.
StatementSetDefaultUpdateMode(eStatementUpdateMode.PER_FRAME);
mode:Constant.eStatementUpdateMode- Returns:
Undefined
StatementGetDefaultUpdateMode()
Get the global default update mode that future machines will use.
var _default_mode = StatementGetDefaultUpdateMode();
- Returns:
Constant.eStatementUpdateMode
SetTimeScale(scale)
Set per-machine time scale. This multiplies the delta used by UpdateDelta.
state_machine.SetTimeScale(0.5);
scale:Real- Returns:
Struct.Statement
GetTimeScale()
Get per-machine time scale.
var _scale = state_machine.GetTimeScale();
- Returns:
Real
If no global scale is set, this returns 1.
StatementSetGlobalTimeScale(scale)
Set the global time scale for all Statement machines. This multiplies each machine’s time scale.
StatementSetGlobalTimeScale(1);
scale:Real- Returns:
Undefined
You can also set STATEMENT_TIME_GLOBAL_SCALE directly.
GetGlobalTimeScale()
Get the global time scale applied to all machines.
var _global = state_machine.GetGlobalTimeScale();
- Returns:
Real
Queueing
SetQueueAutoProcessing(enabled)
Control whether queued transitions are automatically processed inside Update().
state_machine.SetQueueAutoProcessing(true);
enabled:Bool- Returns:
Struct.Statement
Default: true.
QueueState(name, [data], [force])
Queue a state change to be processed later.
state_machine.QueueState("Attack");
name:Stringdata(optional):Any- payload retrievable viaGetLastTransitionData()if the transition succeeds.force(optional):Bool- Returns:
Struct.Statement
Logs a warning and does not queue anything if the state name does not exist.
ProcessQueuedState()
Process any pending queued state change immediately.
state_machine.ProcessQueuedState();
- Returns:
Struct.StatementStateorUndefined
If there is no queued state, this returns the current state. If the current state cannot exit (and force was not set when queuing), the queued transition remains pending and the current state is returned. Otherwise the queue entry is cleared before calling ChangeState().
HasQueuedState()
Check if a queued state is pending.
if (state_machine.HasQueuedState()) { /* ... */ }
- Returns:
Bool
GetQueuedStateName()
Get the name of the queued state, if any.
var _next = state_machine.GetQueuedStateName();
- Returns:
StringorUndefined
GetQueuedStateData()
Get the payload attached to a queued state, if any.
var _payload = state_machine.GetQueuedStateData();
- Returns:
AnyorUndefined
ClearQueuedState()
Cancel any queued state without processing it.
state_machine.ClearQueuedState();
- Returns:
Struct.Statement
History & Introspection
SetHistoryLimit(limit)
Set how many previous states to keep in history.
state_machine.SetHistoryLimit(32);
limit:Real- Returns:
Struct.Statement
limit <= 0 means unlimited history.
GetHistoryCount()
Get how many entries are currently stored in the previous state history.
var _count = state_machine.GetHistoryCount();
- Returns:
Real
GetHistoryAt(index)
Get a previous state by history index.
var _st = state_machine.GetHistoryAt(0);
index:Real- Returns:
Struct.StatementStateorUndefinedif the index is invalid.
Index 0 is the oldest entry. The most recent entry is at GetHistoryCount() - 1.
ClearHistory()
Clear the previous state history without affecting the current state.
state_machine.ClearHistory();
- Returns:
Struct.Statement
PreviousState([data], [force])
Convenience helper to change back to the most recent previous state.
state_machine.PreviousState();
data(optional):Any- payload attached to this transition.force(optional):Bool- Returns:
Struct.StatementStateorUndefined.
This is roughly equivalent to:
state_machine.ChangeState(state_machine.GetPreviousStateName(), data, force);
but is safer and handles edge cases for you.
GetPreviousStateName()
Get the name of the most recent previous state in history.
var _prev = state_machine.GetPreviousStateName();
- Returns:
StringorUndefined.
WasPreviouslyInState(name, [depth])
Check whether the state at the given history depth matches the supplied name.
// Was the last state "Attack"?
if (state_machine.WasPreviouslyInState("Attack")) {
// ...
}
// Was the state three transitions ago "Patrol"?
if (state_machine.WasPreviouslyInState("Patrol", 3)) {
// ...
}
name:Stringdepth(optional):Real- 1 checks the most recent previous state, 2 checks the one before that, etc. Defaults to 1.- Returns:
Bool
Returns false if there is not enough history, or if the entry at that depth is not a valid StatementState.
GetLastTransitionData()
Get the payload attached to the most recent successful state transition, if any.
var _data = state_machine.GetLastTransitionData();
if (is_struct(_data)) {
EchoDebugInfo("Last transition damage: " + string(_data.damage));
}
- Returns:
AnyorUndefined.
This works for direct ChangeState, queued transitions, stack pushes/pops, and other transitions that go through the machine.
PrintStateNames()
Print all state names registered on this machine (via the debug system).
state_machine.PrintStateNames();
- Returns:
Struct.Statement
DebugDescribe()
Print a one-line debug description of this state machine, including owner, current state, previous state, age, queued state, state stack depth, and history count.
state_machine.DebugDescribe();
- Returns:
Undefined
Useful for quick logging of state machine status without having to inspect multiple values manually.
PrintStateHistory([limit])
Print the previous state history for this machine, from most recent backwards.
// Dump entire history
state_machine.PrintStateHistory();
// Or only the last 5 entries
state_machine.PrintStateHistory(5);
limit(optional):Real- maximum number of history entries to print. Use 0 or a negative value to print the full history.- Returns:
Struct.Statement
By default the method prints a short summary (similar to DebugDescribe()) and then each history entry with its index.
State Stack (Push / Pop)
PushState(name, [data], [force])
Push current state onto a stack and change to name.
state_machine.PushState("Pause");
name:Stringdata(optional):Any- payload attached to the transition.force(optional):Bool- Returns:
Struct.StatementStateorUndefined.
If the transition is blocked (for example can_exit == false and not forced), the current state is not pushed.
PopState([data], [force])
Pop the last pushed state from the stack and change back to it.
state_machine.PopState();
data(optional):Any- payload for this transition.force(optional):Bool- Returns:
Struct.StatementStateorUndefined.
Returns the current state if the stack is empty or if the target state no longer exists.
GetStateStackDepth()
Number of entries currently on the state stack.
var _depth = state_machine.GetStateStackDepth();
- Returns:
Real
PeekStateStack()
Peek at the most recently pushed state without popping it.
var _top = state_machine.PeekStateStack();
- Returns:
Struct.StatementStateorUndefined.
ClearStateStack()
Clear all entries from the state stack without changing the current state.
state_machine.ClearStateStack();
- Returns:
Struct.Statement
Submachines (StatementState)
Statement supports nested state machines. A state can host a submachine and optionally control when the host can exit.
CreateSubMachine([name])
Create and attach a submachine to this state (making it a host state).
var _sub = state.CreateSubMachine("CombatSub");
name(optional):String- friendly name for debug tools. Defaults to the host state name.- Returns:
Struct.Statement
If a submachine already exists, this returns the existing submachine.
HasSubMachine()
Check whether this state currently hosts a submachine.
if (state.HasSubMachine()) {
// has a child machine
}
- Returns:
Bool
GetSubMachine()
Get the hosted submachine, if any.
var _sub = state.GetSubMachine();
- Returns:
Struct.StatementorUndefined
OnSubmachineEnter(fn)
Set a callback that runs when this host state enters and its submachine is started or resumed.
state.OnSubmachineEnter(method(self, function(_sub) {
EchoDebugInfo("Submachine started");
}));
fn:Function- called asfn(submachine). This is not auto-bound, so usemethod(owner, fn)if you need scope binding.- Returns:
Struct.StatementState
OnSubmachineExit(fn)
Set a callback that runs when this host state exits and its submachine is suspended or stopped.
state.OnSubmachineExit(method(self, function(_sub) {
EchoDebugInfo("Submachine stopped");
}));
fn:Function- called asfn(submachine). This is not auto-bound, so usemethod(owner, fn)if you need scope binding.- Returns:
Struct.StatementState
LockExitUntilSubIn(state_name)
Prevent this host state from exiting (unless forced) until the submachine is in the given state.
state.LockExitUntilSubIn("Ready");
state_name:String- Returns:
Struct.StatementState
LockExitWhileSubNot(fn)
Prevent this host state from exiting (unless forced) while a predicate returns false for the submachine.
state.LockExitWhileSubNot(function(_sub) {
return _sub.IsInState("Ready");
});
fn:Function- called asfn(submachine)and should returnBool.- Returns:
Struct.StatementState
Exit locks are respected by ChangeState, QueueState, PushState, and PopState unless force is true.
State Change Hook
SetStateChangeBehaviour(fn)
Register a callback to be run whenever the machine changes state.
state_machine.SetStateChangeBehaviour(method(self, function() {
EchoDebugInfo("Now in state: " + string(state_machine.GetStateName()));
}));
fn:Function- called asfn(previous_state, transition_data); both may beundefined. This function is not auto-bound, so usemethod(owner, fn)if you need scope binding.- Returns:
Undefined
Called after the old state’s Exit, after state is updated, and before new state Enter.
AddAnyExitHook(fn)
Register a hook that runs whenever any state exits.
state_machine.AddAnyExitHook(function(_from, _to, _data, _force, _meta) {
// ...
});
fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.Statement
Hook signature: fn(from_state, to_state, data, force, meta).
meta is a struct { via_queue, via_push, via_pop, via_debug }.
Runs after the old state’s Exit and before the machine switches to the new state.
AddAnyEnterHook(fn)
Register a hook that runs whenever any state enters.
state_machine.AddAnyEnterHook(function(_to, _from, _data, _force, _meta) {
// ...
});
fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.Statement
Hook signature: fn(to_state, from_state, data, force, meta).
meta is a struct { via_queue, via_push, via_pop, via_debug }.
Runs after the machine switches to the new state and before the new state’s Enter handler.
AddAnyTransitionHook(fn)
Register a hook that runs whenever a transition completes.
state_machine.AddAnyTransitionHook(function(_from, _to, _data, _force, _meta) {
// ...
});
fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.Statement
Hook signature: fn(from_state, to_state, data, force, meta).
meta is a struct { via_queue, via_push, via_pop, via_debug }.
Runs after the machine switches to the new state and before the new state’s Enter handler.
ClearAnyExitHooks()
Clear all any-exit hooks on this machine.
state_machine.ClearAnyExitHooks();
- Returns:
Struct.Statement
ClearAnyEnterHooks()
Clear all any-enter hooks on this machine.
state_machine.ClearAnyEnterHooks();
- Returns:
Struct.Statement
ClearAnyTransitionHooks()
Clear all any-transition hooks on this machine.
state_machine.ClearAnyTransitionHooks();
- Returns:
Struct.Statement
Low-Level Event Running
Behind the scenes, each Statement state uses an array indexed with enums to decide what handler to run. For instance, Update(), runs the handler stored in the array position indexed by eStatementEvents.STEP. In most circumstances, you don’t need to worry about this stuff, simply use Update() / Draw() and it will be handled automatically.
However, if you’re confident editing Statement itself, you can extend eStatementEvents with your own custom event types. The enum is defined in scr_statement_macro.
eStatementEventsis an enum defined inside the Statement framework (inscr_statement_macro) that maps the built-in handler types:
eStatementEvents.ENTEReStatementEvents.DRAWeStatementEvents.STEPeStatementEvents.EXITeStatementEvents.NUM- a sentinel used internally as a “one past the end” value when looping over event types. It is not a real event and should not be passed toRunState.
Always insert new entries before
NUM;NUMis used as an “end of enum” marker when initialising internal arrays (such as thestate_eventarray), so adding entries afterNUMwill break that initialisation. After editing the enum, you can then use the following methods to add or run custom state handlers, or check whether they exist.
AddStateEvent(event, fn)
StatementState method. Bind a handler to a specific eStatementEvents index. This is your “custom” handler entry point.
Create Event
// Assuming you have added ANIMATION_END to the enum list (before NUM)
idle.AddStateEvent(eStatementEvents.ANIMATION_END, function() {
// custom logic dealing with the end of animations in the idle state
});
event:Real- one of theeStatementEventsvalues (ENTER,EXIT,STEP,DRAWor any customeStatementEventsvalue you’ve defined).fn:Function- automaticallymethod(owner, fn)bound.- Returns:
Struct.StatementState
HasStateEvent(event)
StatementState method. Check whether this state has a handler for a given eStatementEvents index.
if (!idle.HasStateEvent(eStatementEvents.ANIMATION_END)) {
// maybe attach one
}
event:Real- one of theeStatementEventsvalues (including custom entries you add).- Returns:
Bool
RunState(event)
Statement method. Run a specific eStatementEvents index on the current state. This is scoped to the state machine itself, unlike the other two which are scoped to the state, to keep parity with the other handlers, like state_machine.Update(), etc.
Animation End Event
var _state = state_machine.GetState();
if (!is_undefined(_state) && _state.HasStateEvent(eStatementEvents.ANIMATION_END)) {
state_machine.RunState(eStatementEvents.ANIMATION_END);
}
event:Real(usually one of theeStatementEventsvalues)- Returns: Any or
Undefinedif:- There is no active state, or
- The chosen event is not implemented on the current state.
Exit Control & Declarative Transitions (StatementState)
SetCanExit(can_exit) / LockExit() / UnlockExit()
Control whether a state can be exited without forcing.
state.LockExit(); // block transitions unless force == true
state.SetCanExit(true); // equivalent to UnlockExit()
can_exit:Bool- Returns:
Struct.StatementState
When can_exit == false, ChangeState/queued transitions will only leave this state if force == true.
AddTransition(target_name, condition, [data], [force])
Add a declarative transition that will be evaluated each Update() while the state is active. When the condition returns true, the machine changes to target_name.
idle.AddTransition("Run", function() {
return abs(hsp) > 0.1;
});
target_name:Stringcondition:Function- automatically bound to the owner viamethod(owner, fn).data(optional):Any- payload attached to the transition if it fires.force(optional):Bool- ignorecan_exitwhen firing.- Returns:
Struct.StatementState
Transitions are checked in the order they were added; the first condition returning true will fire. When a transition fires, its data payload is passed into ChangeState.
ClearTransitions()
Remove all declarative transitions from this state.
state.ClearTransitions();
- Returns:
Struct.StatementState
EvaluateTransitions()
Evaluate this state’s declarative transitions and return the first matching record.
var _tr = state.EvaluateTransitions();
- Returns:
Struct{ target_name, condition, force, data }orUndefined.
Normally you do not call this directly; the machine calls EvaluateTransitions() after each Update() and then applies the transition via ChangeState. Use it manually only for custom control.
EvaluateTransitions() (machine)
Force evaluation of declarative transitions on the current state and apply the first passing transition.
state_machine.EvaluateTransitions(); // after custom update loop
- Returns:
Struct.StatementStateorUndefinedif no transition fired or no active state.
This is normally called automatically at the end of Update(). Use it manually if you disable auto-processing or run custom update ordering.
This is not the same as
state.EvaluateTransitions(), as this method actually changes state if a transition fires. This version attached to the state machine is the one you most likely want to use.
Per-State Timers (Advanced)
Per-state timers live on individual StatementState instances and are considered advanced. In almost all cases (99% of use cases) you can ignore them and just use the machine-level state time via GetStateTime() / SetStateTime().
Per-state timers are backed by GameMaker time sources and tick independently of Update():
- Once a state becomes active and its timer is started, that timer advances every frame until you change out of that state or explicitly stop/pause/reset the timer.
- Because they use time sources internally, they can continue advancing even if the instance is deactivated or you temporarily stop calling
Update().
By contrast, GetStateTime() / SetStateTime() live on the Statement itself:
- Represent “how long the current state has been active (scaled time units)”.
- Reset automatically on state change.
- Only increment when you call
Update()on the machine.
If you’re unsure which to use, start with GetStateTime() and ignore per-state timers; they exist mainly for very specialised cases where you need a timer tightly bound to a specific state’s lifetime.
TimerStart()
Create and start a per-state timer (if not already created), resetting it to 0.
state.TimerStart();
- Returns:
Struct.StatementState
Requires this state to be added to a Statement machine.
TimerSet(time)
Set the per-state timer value.
state.TimerSet(30);
time:Real- Returns:
Struct.StatementState
TimerGet()
Get the current per-state timer value.
var _t = state.TimerGet();
- Returns:
Real
TimerPause()
Pause the per-state timer.
state.TimerPause();
- Returns:
Struct.StatementState
TimerRestart()
Restart the per-state timer if it exists.
state.TimerRestart();
- Returns:
Struct.StatementState
TimerKill()
Kill (destroy) the per-state timer.
state.TimerKill();
- Returns:
Struct.StatementState
State Templates (Advanced)
State templates let you define reusable state logic (events, transitions, debug metadata) and then build multiple StatementState instances from that template.
SetConfigClone(enabled)
Control whether config is deep-cloned when building states from this template.
template.SetConfigClone(true);
enabled:Bool- Returns:
Struct.StatementStateTemplate
Default is true.
AddStateEvent(event, fn)
Bind a handler to a template event slot.
template.AddStateEvent(eStatementEvents.ENTER, function() {
// ...
});
event:Real- one of theeStatementEventsvalues (including custom entries you add).fn:Function- Returns:
Struct.StatementStateTemplate
Handlers are stored unbound; when you call Build, they are attached to the new state and bound to the owner.
AddEnter(fn)
Bind an Enter handler to this template.
template.AddEnter(function() {
// ...
});
fn:Function- Returns:
Struct.StatementStateTemplate
AddUpdate(fn)
Bind an Update/Step handler to this template.
template.AddUpdate(function() {
// ...
});
fn:Function- Returns:
Struct.StatementStateTemplate
AddExit(fn)
Bind an Exit handler to this template.
template.AddExit(function() {
// ...
});
fn:Function- Returns:
Struct.StatementStateTemplate
AddDraw(fn)
Bind a Draw handler to this template.
template.AddDraw(function() {
// ...
});
fn:Function- Returns:
Struct.StatementStateTemplate
AddTransition(target_name, condition, [data], [force])
Add a declarative transition to this template.
template.AddTransition("Run", function() {
return abs(hsp) > 0.1;
});
target_name:Stringcondition:Function- stored unbound and later bound to the owner when built.data(optional):Anyforce(optional):Bool- Returns:
Struct.StatementStateTemplate
ClearTransitions()
Clear all declarative transitions defined on this template.
template.ClearTransitions();
- Returns:
Struct.StatementStateTemplate
DebugLinkTo(target_name)
Declare a debug-only link from this template to another state for the visualiser.
template.DebugLinkTo("Attack");
target_name:String- Returns:
Struct.StatementStateTemplate
DebugPayload(payload)
Set a default payload used when jumping to this state via debug tools.
template.DebugPayload({ damage: 10 });
payload:Any- Returns:
Struct.StatementStateTemplate
DebugBreakOnEnter([break_on_enter])
Enable or disable “break on enter” for this template in debug builds.
template.DebugBreakOnEnter();
break_on_enter(optional):Bool- Defaults to true.- Returns:
Struct.StatementStateTemplate
DebugTag(tag)
Assign a tag (or comma-separated tags) for grouping/filtering in debug UIs.
template.DebugTag("Combat");
tag:String- Returns:
Struct.StatementStateTemplate
Build(owner, [config], [name], [clone])
Build a new StatementState instance from this template.
var _state = template.Build(self, { speed: 2 }, "IdleFast");
owner:Id.InstanceorStructconfig(optional):Anyname(optional):String- override the template’s state name.clone(optional):Bool- override the template’s config cloning.- Returns:
Struct.StatementStateorUndefined
When built, all template handlers/transitions are applied to the state and bound to the owner. Use Statement.AddStateTemplate(...) to build-and-add in one step.
Cleanup & Global Helpers
RemoveState(name)
Remove a state by name from this machine.
state_machine.RemoveState("Debug");
name:String- Returns:
Struct.Statement
Destroy()
Helper to clean up state-specific timers for all states registered on this machine (current and history).
state_machine.Destroy();
Call this if you are discarding a machine and want to ensure no associated timers continue ticking.
StatementStateKillTimers()
Global helper: destroy all state timers registered in global.__statement_timers and clear the array.
StatementStateKillTimers();
Use this if you want a global “nuke all state timers” reset, e.g. when restarting a run or changing rooms.
Debug API (Machine & State)
The following helpers are mainly intended for debugging and tooling. They are safe to use in shipping builds, but you will typically guard them behind #if STATEMENT_DEBUG checks.
Machine debug controls
ClearDebugTransitionHistory()
Clear any recorded transition history entries.
state_machine.ClearDebugTransitionHistory();
- Returns:
Struct.Statement
DebugJumpToState(name, force)
Jump to a state from debug tooling, using that state’s debug payload if set.
state_machine.DebugJumpToState(name, force);
name:Stringforce(optional):Bool- Returns:
Struct.StatementState,Undefined
DebugPause()
Pause this machine for debug purposes.
state_machine.DebugPause();
- Returns:
Struct.Statement
DebugResume()
Resume this machine from a debug pause.
state_machine.DebugResume();
- Returns:
Struct.Statement
DebugSetErrorBehavior(behavior)
Set how the machine reacts to caught errors: PAUSE (default) or RETHROW.
state_machine.DebugSetErrorBehavior(behavior);
behavior:Constant.eStatementErrorBehavior- Returns:
Struct.Statement
DebugSetLogErrorsToFile(log_to_file)
Control whether caught errors append to debug_statement_errors.log before optional rethrow.
state_machine.DebugSetLogErrorsToFile(log_to_file);
log_to_file:Bool- Returns:
Struct.Statement
DebugStep()
Run exactly one Update tick while paused, then re-pause.
state_machine.DebugStep();
- Returns:
Any,Undefined
DebugTag(tag)
Assign a tag (or comma-separated tags) for grouping/filtering in debug UIs.
state_machine.DebugTag(tag);
tag:String- Returns:
Struct.Statement
GetDebugGraph()
Get a snapshot of this machine’s debug graph: states + edges.
state_machine.GetDebugGraph();
- Returns:
Struct,Undefined- A struct { states, edges } or undefined if debug disabled.
GetDebugName()
Get the friendly debug name, or a fallback based on the owner.
state_machine.GetDebugName();
- Returns:
String,Undefined
GetDebugStateStats()
Get the per-state debug stats map.
state_machine.GetDebugStateStats();
- Returns:
Struct,Undefined
GetDebugTag()
Get the debug tag string, if set.
state_machine.GetDebugTag();
- Returns:
String,Undefined
GetDebugTransitionHistory()
Get the recent transition history records.
state_machine.GetDebugTransitionHistory();
- Returns:
Array,Undefined
IsDebugEnabled()
Returns whether debug tracking is enabled for this machine.
state_machine.IsDebugEnabled();
- Returns:
Bool
SetDebugEnabled(enabled)
Enable or disable debug tracking for this machine.
state_machine.SetDebugEnabled(true);
enabled:Bool- Returns:
Struct.Statement
Default is true when STATEMENT_DEBUG is enabled.
SetDebugName(name)
Assign a friendly name for this machine in debug UIs.
state_machine.SetDebugName(name);
name:String- Returns:
Struct.Statement
State-level debug helpers
DebugBreakOnEnter(break_on_enter)
Enable or disable “break on enter” for this state in debug builds.
state.DebugBreakOnEnter(break_on_enter);
break_on_enter(optional):Bool- Defaults to true.- Returns:
Struct.StatementState
DebugLinkTo(target_name)
Declare a debug-only link from this state to another state for the visualiser.
state.DebugLinkTo(target_name);
target_name:String- Returns:
Struct.StatementState
DebugPayload(payload)
Set a default payload used when jumping to this state via debug tools.
state.DebugPayload(payload);
payload:Any- Returns:
Struct.StatementState
DebugTag(tag)
Assign a tag (or comma-separated tags) for grouping/filtering in debug UIs.
state.DebugTag(tag);
tag:String- Returns:
Struct.StatementState
Global debug helpers
StatementDebugPruneRegistry([prune_destroyed_owners])
Remove dead entries from the global Statement debug registry.
var _removed = StatementDebugPruneRegistry();
prune_destroyed_owners(optional):Bool- when true, also removes machines whose owner instances are destroyed.- Returns:
Real- number of entries removed.
Returns 0 if STATEMENT_DEBUG is false.
Visual Debugger & Debug UI
Statement ships with an in-game visual debugger known as Lens. You do not need to use it directly to benefit from Statement, but it is available if you want.
Lens entry points
StatementLens()
Debug visualiser for Statement machines (drawn in GUI space).
var statement_lens = new StatementLens();
- Returns:
Struct.StatementLens
StatementLensGet()
Get the global Statement Lens instance when STATEMENT_DEBUG is enabled.
var _lens = StatementLensGet();
- Returns:
Struct.StatementLensorUndefined
StatementLensInit()
Ensure the Lens globals exist and refresh the active machine list.
StatementLensInit();
- Returns:
Undefined
StatementLensUpdate()
Update hook for the Statement Lens (call from a Step event when STATEMENT_DEBUG is enabled).
StatementLensUpdate();
- Returns:
Undefined
StatementLensInputPressed(action_id)
Return true if a Statement Lens action is pressed in the active input context.
if (StatementLensInputPressed(STATEMENT_LENS_ACTION_NEXT_MACHINE)) {
// next machine
}
action_id:String- Returns:
Bool
Action ids are defined as STATEMENT_LENS_ACTION_* macros in scr_statement_macro. Returns false if no active input root is available. Default bindings are provided by STATEMENT_LENS_BIND_* macros and use the matching input binding structs they define.
StatementLensDraw()
Draw hook for the Statement Lens (call from a Draw GUI event when STATEMENT_DEBUG is enabled).
StatementLensDraw();
- Returns:
Undefined
StatementLensOpen(ui_root)
Open or create the Statement Lens window inside the debug UI root.
var _ui_root = global.__statement_lens_root;
StatementLensOpen(_ui_root);
ui_root:Struct- your debug UI root struct.- Returns:
StructorUndefined
Requires a compatible UI root struct from your debug UI host. Returns Undefined if STATEMENT_DEBUG is false or ui_root is invalid.
Lens instance helpers
IsVisible()
Whether the lens is visible.
statement_lens.IsVisible();
- Returns:
Bool
SetVisible(visible)
Set visibility of the lens.
statement_lens.SetVisible(visible);
visible:Bool- true to show the lens, false to hide it.- Returns:
Struct.StatementLens