ListenerAction Script Protocol
Overview
ListenerAction scripts run custom code when a State Machine listener event fires. Unlike Listeners (which are function signatures for addListener()), ListenerAction is a script type that you attach to state machine listener events.
When to use ListenerAction scripts:
- Custom side-effects when a state machine listener triggers
- Logging, analytics, or audio playback on listener events
- Complex logic that needs the pointer event data from the trigger
Type Definition
export type ListenerAction<T> = {
init: ((self: T, context: Context) -> boolean)?,
perform: (self: T, pointerEvent: PointerEvent) -> (),
} & T
Protocol Methods
| Function | Signature | Required | Description |
|---|---|---|---|
init | (self: T, context: Context): boolean | No | One-time initialization |
perform | (self: T, pointerEvent: PointerEvent): () | Yes | Runs when the listener fires |
perform(self, pointerEvent) — REQUIRED
Called when the state machine listener event fires. Receives the PointerEvent that triggered the listener, providing access to position and pointer ID.
function perform(self: MyAction, pointerEvent: PointerEvent)
print("Listener triggered at:", pointerEvent.position.x, pointerEvent.position.y)
end
init(self, context) — Optional
Called once when the action is created. Use for setup and accessing the ViewModel.
function init(self: MyAction, context: Context): boolean
local vm = context:viewModel()
-- Setup logic
return true
end
Template
export type MyAction = {
clickCount: number,
}
function perform(self: MyAction, pointerEvent: PointerEvent)
self.clickCount += 1
print("Click #" .. tostring(self.clickCount)
.. " at (" .. tostring(pointerEvent.position.x)
.. ", " .. tostring(pointerEvent.position.y) .. ")")
end
return function(): ListenerAction<MyAction>
return {
clickCount = 0,
perform = perform,
}
end
How to Apply
- Create a ListenerAction script in the Assets panel
- In the State Machine editor, select a Listener
- Add the script as an action on the listener
- The
performfunction will run each time the listener triggers
Key Differences from Node Scripts
| Feature | Node Script | ListenerAction |
|---|---|---|
| Lifecycle | init, advance, update, draw | init, perform |
| Rendering | Has draw() and Renderer access | No rendering |
| When it runs | Every frame (advance/draw) | Only when listener fires |
| Pointer data | Via pointerDown/pointerMove handlers | Via perform parameter |
Practice Exercise
Exercise 1: Click Counter Action ⭐
Premise
ListenerAction scripts are event-driven. They run only when the listener fires, making them ideal for analytics, counters, and side-effects.
By the end of this exercise, you will increment a counter in perform() and print an ANSWER: line after 3 listener events.
Starter Code
export type ClickCounterAction = {
clicks: number,
}
function perform(self: ClickCounterAction, pointerEvent: PointerEvent)
-- TODO 1: Increment self.clicks
-- TODO 2: Print click position
-- print("click at", pointerEvent.position.x, pointerEvent.position.y)
-- TODO 3: When clicks reaches 3, print "ANSWER: clicks=3"
end
return function(): ListenerAction<ClickCounterAction>
return {
perform = perform,
clicks = 0,
}
end
Assignment
- Attach the script as a listener action in a state machine Listener
- Trigger the listener 3 times
- Copy the
ANSWER:line from Console
Verify Your Answer
Knowledge Check
See Also: Listeners, Script Types Overview, PointerEvent
Next Steps
- Continue to TransitionCondition Protocol
- Need a refresher? Review Quick Reference