A worked example, rendered from real sample data. Sign in to run the tool on your own input.
initial: Idle
Idle -> Walking : move [hasInput]
Walking -> Running : sprint
Running -> Walking : walk
Walking -> Idle : stop
Idle -> Jumping : jump
Jumping -> Idle : land
Any -> Dead : dieexport type State = "Idle" | "Walking" | "Running" | "Jumping" | "Dead";
export type Trigger = "move" | "sprint" | "walk" | "stop" | "jump" | "land" | "die";
export type Guard = "hasInput";
export interface Transition { from: State | "Any"; to: State; trigger: Trigger; guard?: Guard }
export const TRANSITIONS: Transition[] = [
{ from: "Idle", to: "Walking", trigger: "move", guard: "hasInput" },
{ from: "Walking", to: "Running", trigger: "sprint" },
{ from: "Running", to: "Walking", trigger: "walk" },
{ from: "Walking", to: "Idle", trigger: "stop" },
{ from: "Idle", to: "Jumping", trigger: "jump" },
{ from: "Jumping", to: "Idle", trigger: "land" },
{ from: "Any", to: "Dead", trigger: "die" },
];
export const INITIAL_STATE: State = "Idle";
export const guards: Record<Guard, () => boolean> = {
hasInput: () => true,
};
export interface StateHooks {
onEnter?: Partial<Record<State, () => void>>;
onExit?: Partial<Record<State, () => void>>;
onUpdate?: Partial<Record<State, (deltaSeconds: number) => void>>;
}
export class StateMachine {
state: State = INITIAL_STATE;
constructor(private hooks: StateHooks = {}) {}
can(trigger: Trigger): boolean {
return this.match(trigger) !== undefined;
}
send(trigger: Trigger): boolean {
const next = this.match(trigger);
if (!next) return false;
this.hooks.onExit?.[this.state]?.();
this.state = next.to;
this.hooks.onEnter?.[this.state]?.();
return true;
}
update(deltaSeconds: number): void {
this.hooks.onUpdate?.[this.state]?.(deltaSeconds);
}
private match(trigger: Tr
…
Generate finite state machine code from state/transition definitions. Part of the DevTools Surf developer suite. Browse more tools in the Game Dev collection.