Last Update: 2023-07-06
Action Handlers
Action handlers are a key component of the stategraph system that allows entities to respond to gameplay actions initiated by players or AI. They provide a way to define how an entity should respond when someone attempts to perform an action on it or when it needs to perform an action itself.
Creating Action Handlers
Action handlers are created using the ActionHandler
constructor:
ActionHandler(ACTIONS.EAT, function(inst, action)
if action.target and action.target:HasTag("food") then
inst.sg:GoToState("eat", action.target)
return true
end
return false
end)
The function returns true
if the action is handled successfully, or false
if it should fall back to default handling.
Action Handler Structure
The basic structure of an action handler includes:
- The action type (from
ACTIONS
table) - A handler function that receives:
inst
: The entity performing the actionaction
: The action being performed
Common Action Types
Here are some common action types defined in ACTIONS
:
ACTIONS.ATTACK
: Attack a targetACTIONS.EAT
: Eat foodACTIONS.PICKUP
: Pick up an itemACTIONS.CHOP
: Chop a treeACTIONS.MINE
: Mine a rockACTIONS.DIG
: Dig up an objectACTIONS.HARVEST
: Harvest a resourceACTIONS.WALKTO
: Walk to a location
Example: Creating Action Handlers
local actionhandlers = {
ActionHandler(ACTIONS.EAT, function(inst, action)
inst.sg:GoToState("eat", action.target)
return true
end),
ActionHandler(ACTIONS.PICKUP, function(inst, action)
inst.sg:GoToState("pickup")
return true
end),
ActionHandler(ACTIONS.ATTACK, function(inst, action)
if not inst.components.health:IsDead() then
inst.sg:GoToState("attack", action.target)
return true
end
return false
end),
}
Adding Action Handlers to a Stategraph
Action handlers are passed as the fifth parameter when creating a StateGraph:
return StateGraph("myentity", states, events, "idle", actionhandlers)
Destination State Logic
Action handlers often need to transition the entity to a state that will perform the action:
ActionHandler(ACTIONS.CHOP, function(inst, action)
if not inst.sg:HasStateTag("busy") then
inst.sg:GoToState("chop", action.target)
return true
end
return false
end)
Action Data
The action
parameter provides information about the action being performed:
action.target
: The target entity of the actionaction.doer
: The entity performing the actionaction.pos
: The position where the action is being performedaction.distance
: The distance at which the action can be performed
Using Destination State
You can pass data to the destination state to use in that state's logic:
ActionHandler(ACTIONS.ATTACK, function(inst, action)
inst.sg:GoToState("attack", {
target = action.target,
weapon = inst.components.combat:GetWeapon()
})
return true
end)
Then, in the destination state:
State{
name = "attack",
onenter = function(inst, data)
inst.sg.statemem.target = data.target
inst.sg.statemem.weapon = data.weapon
inst.AnimState:PlayAnimation("attack")
end,
timeline = {
TimeEvent(10*FRAMES, function(inst)
inst.components.combat:DoAttack(inst.sg.statemem.target, inst.sg.statemem.weapon)
end),
},
}
Conditionally Handling Actions
Action handlers can conditionally choose whether to handle an action:
ActionHandler(ACTIONS.PICKUP, function(inst, action)
-- Only handle the action if the entity isn't busy
if not inst.sg:HasStateTag("busy") then
-- Only pick up food items
if action.target and action.target:HasTag("food") then
inst.sg:GoToState("pickup", action.target)
return true
end
end
return false
end)
Interrupting Current State
Action handlers can choose to interrupt the current state based on conditions:
ActionHandler(ACTIONS.ATTACK, function(inst, action)
-- Allow attacking from idle or if currently doing something interruptible
if inst.sg:HasStateTag("idle") or inst.sg:HasStateTag("caninterrupt") then
inst.sg:GoToState("attack")
return true
end
return false
end)