Start Page » Game Development with the Drag[en]gine » State Machines
State machines define game logic using a set of states with transitions leading from one state to the other. Transitions are triggered by sending events to the state machine. A state machine is defined by the state it is located in right now. In contrary to behavior trees stats machines only run when an event is sent. This makes state machines more efficient than behavior trees if events are sent at low intervals.
States and transitions can contain actions which modify game state. Actions are typically provided by behaviors to control the behavior or behaviors linked to them. Actions are supposed to not fail and throw exceptions only if something is really wrong. Instead they should provide conditions to check if actions could be properly applied or not. If the state machine can not find an action it is treated as if it matches an empty action. It is thus allowed to define actions that do not exist. This can be used to run actions on behaviors which might not be present in an element class. To find problems with missing actions use the debug feature in ECBehaviorStateMachine.
Conditions can be paramtrized by adding one or more parameters to the rule. The conditions define themselves which parameters they understand and how they react to them. The name of parameters is free but it is recommended to use a naming scheme like this: <source>.<parameter>
. This groups parameters and reduces the chance of name conflicts. This is especially important since parameters are also reused for action rules. And while actions already define the source
part rather well for conditions this is unknown.
States can have enter actions and exit actions. Enter actions run after activating the state. Exit actions run before switching to another state. Enter and exit actions both can have conditions which determine if the action is run or not. Enter actions can have a state change assigned. If an enter action with a state change is run the state changes immediately to the specified state and all enter actions afterwards are ignored. This can be used to automatically transition into another state for example if a pre-condition is not fulfilled or an earlier action failed to run properly. In particular no action can be assigned in which case the enter action only serves the purpose to transition into another state if its conditions fail. In addition states can be assigned an auto-transition state. If all enter actions are processed and the state has an auto-transition state assigned the auto-transition state is immediately activated. This allows to create pass-through states which only run a couple of enter actions then transition into the final state.
Upon receiving an event the state machine checks transitions defined in the current state from the first defined to the last defined. The first transition matching the event with all of its conditions evaluating to true is used. All matching transitions afterwards are ignored.If no transition matches the event is discared. It is thus fully legit to send an event to a state machine for states not supporting this particular event. Transitions can have actions assigned. They behave similar to enter actions of states. In particular they can also contain a state change which is useful for situations where actions are unable to properly to transition into an error type state. Transitions typically have a next state assigned but this is optional. If no next state is set the transition only runs actions and stays in the current state. If all actions finished running and a next state is set then the state changes to the next state. If a next state is set the transition first switches the state machine to the null state to run exit actions. Then the transition actions are run. Afterward the state is changed.
A typical problem for state machines is the transition-in-transition problem. In general state machines do not allow transitions to be triggered while in a transition since this causes state inconsistency. The state machine in the Drag[en]gine game engine is designed to be able to cope with transitions in transitions. If an event is received while a transition is in progress it is delayed until after the transition finished. This avoids state inconsistencies and since events are allowed to not trigger a transition the worst that can happen is that an event is discarded.
A particular feature of the Drag[en]gine state machines is importing. State machines can be imported into state machines. This will import all states replacing existing states if present. States can be imported into the states or transitions. If imported into states the actions and transitions are appended to the actions and transitions stored in the state as well as the next state changed if defined in the imported state. The already present actions and transitions apply first. Hence the order of import matters. If imported into a transition the enter actions are imported as transition actions. This allows to compose state machines using reusable parts of other state machines. This makes state machines easier to read, less error prone and reusable.
The state machine file format is recognized by the LoadStateMachine script class. The file is an XML file with a simple structure to define a state machine using XML.
Tag | Description | Occurance | Default |
---|---|---|---|
initialState | Initial state of the state machine. Enter actions are run | 1 | - |
state | Define state. Replaces existing state if present | 0..N | - |
import | Import states from a state machine file replacing existing states if present. Path can be absolute or relative to the directory this state machine has been loaded from. Relative path are not supported on in-script created state machines | 0..N | - |
Defines a state. Replaces existing state with the same identifier if present.
Attribute | Description | Occurance | Default |
---|---|---|---|
id | Identifier of state. | Required | - |
Tag | Description | Occurance | Default |
---|---|---|---|
enterAction | Action to run upon entering state | 0..N | - |
exitAction | Action to run upon exiting state | 0..N | - |
transition | Define transition | 0..N | - |
nextState | Identifier of state to switch to after all enter actions finished | 0..1 | - |
import | Import actions, transitions and next state (if set) from existing state with identifier | 0..N | - |
Defines an action. Can be an enter or exit action for a state or an action for a transition.
Attribute | Description | Occurance | Default |
---|---|---|---|
name | Name of action. | Optional | - |
Tag | Description | Occurance | Default |
---|---|---|---|
parameter | Add parameter. Parameter value is text content of node which can be empty. Attributes:
| 0..N | - |
condition | Add condition. Condition name is text content of node | 0..N | - |
conditionMode | How conditions are evaluated. Valid values:
| 0..1 | allTrue |
state | Identifier of state to switch to after action runs. Not allowed for exit actions | 0..1 | - |
Defines a transition. Transitions are matched by event name and conditions being fulfilled.
Attribute | Description | Occurance | Default |
---|---|---|---|
event | Event name. | Required | - |
state | State to transition to after all actions finished | Optional | - |
Tag | Description | Occurance | Default |
---|---|---|---|
action | Action to run | 0..1 | - |
parameter | Add parameter. Parameter value is text content of node which can be empty. Attributes:
| 0..N | - |
condition | Add condition. Condition name is text content of node | 0..N | - |
conditionMode | How conditions are evaluated. Valid values:
| 0..1 | allTrue |
import | Import enter actions from existing state with identifier | 0..N | - |
Example from the ExampleApp. A simple state machine toggling red, green and blue color upon receiving events from the player. Uses a custom SMAction implementation named “changeColor” to manipulate the color of a dynamic skin renderable.
This uses the basic state machine system from the game engine with a custom .
<?xml version='1.0' encoding='ISO-8859-1'?> <stateMachine> <!-- This example state machine supports three events "red", "green" and "blue". Each time the events are received the respective color component is toggled on and off. Each state denotes one color combination and the allowed transitions between them. The states are named "R G B" where RGB is "on" or "off". The initial state is "on on on" hence white colored. Transitions can have actions and conditions like this: <transition event='do it' state='next state'> <condition name='only if true'/> <action name='some action'/> <action name='another action'/> </transition> Nested conditions are supported using: <conditionMode>anyTrue</conditionMode> <condition>condition1</condition> <condition>condition2</condition> Where these modes are supported: - allTrue: no condition returns false - anyTrue: at least one condition returns true - anyFalse: at least one condition returns false - allFalse: no condition returns true If complex conditions are required it is best to model them in the game scripts as a separate named condition. This increases the flexibility and avoids complicated XML for non-trivial situations --> <initialState>on on on</initialState> <state id='off off off'> <enterAction name='changeColor'> <parameter name='color'>0 0 0</parameter> </enterAction> <transition event='red' state='on off off'/> <transition event='green' state='off on off'/> <transition event='blue' state='off off on'/> </state> <state id='off off on'> <enterAction name='changeColor'> <parameter name='color'>0 0 1</parameter> </enterAction> <transition event='red' state='on off on'/> <transition event='green' state='off on on'/> <transition event='blue' state='off off off'/> </state> <state id='off on off'> <enterAction name='changeColor'> <parameter name='color'>0 1 0</parameter> </enterAction> <transition event='red' state='on on off'/> <transition event='green' state='off off off'/> <transition event='blue' state='off on on'/> </state> <state id='off on on'> <enterAction name='changeColor'> <parameter name='color'>0 1 1</parameter> </enterAction> <transition event='red' state='on on on'/> <transition event='green' state='off off on'/> <transition event='blue' state='off on off'/> </state> <state id='on off off'> <enterAction name='changeColor'> <parameter name='color'>1 0 0</parameter> </enterAction> <transition event='red' state='off off off'/> <transition event='green' state='on on off'/> <transition event='blue' state='on off on'/> </state> <state id='on off on'> <enterAction name='changeColor'> <parameter name='color'>1 0 1</parameter> </enterAction> <transition event='red' state='off off on'/> <transition event='green' state='on on on'/> <transition event='blue' state='on off off'/> </state> <state id='on on off'> <enterAction name='changeColor'> <parameter name='color'>1 1 0</parameter> </enterAction> <transition event='red' state='off on off'/> <transition event='green' state='on off off'/> <transition event='blue' state='on on on'/> </state> <state id='on on on'> <enterAction name='changeColor'> <parameter name='color'>1 1 1</parameter> </enterAction> <transition event='red' state='off on on'/> <transition event='green' state='on off on'/> <transition event='blue' state='on on off'/> </state> </stateMachine>
State machines can be used for actor actions using BAAStateMachine. The Drag[en]gine provides some ready to extend actor action state machines. You can examine the here: Actor action state machines. See in particular firstPerson.desm and vehicle.desm for common game use and firstPersonVR.desm and vrhand.desm for VR use.