User Tools

Site Tools


dragengine:modules:dragonscript:behavior_statemachine

ECBehaviorStateMachine

Example usage of State machine Behavior. See StateMachineExampleClass.ds and colorizer.desm

Behavior element behavior adding StateMachine support.

Loads state machine from file (*.desm) and creates a SMContext. Other behaviors can add actions and conditions to this state machine allowing to compose state machine actions and conditions easily.

You can assign actions and conditions without using other behaviors by using one or more factories. The factories are added to the behavior. Upon creating the behavior instances the factories are asked to create and assign SMAction and SMCondition.

This behavior can be used in different ways depending on the needs.

Single State Machine Usage

This is the most simple solution where only one state machine is used. For many situations this is enough and is the most simple solution to use. Add one ECBehaviorStateMachine with no ID to the element and as many other behaviors adding actions and conditions as required. Set the stateMachine.path property to define the state machine to load. Then use behavior listeners to run events on the state machine at the appropriate time.

See Element Class Example for example code.

Multiple State Machine Usage

You can add multiple instances of ECBehaviorStateMachine to the element to load and use multiple state machines. This can be for using multiple state machines together to model complex logic. In this situation behaviors assigining actions and conditions do add them to all instances of ECBehaviorStateMachine. This is usually not a problem since the state machines are written to use only the actions and conditions making sense to be used.

See Element Class Example for example code.

Instance Counts

This behavior can be used multiple times on an element to add multiple custom colors to mainpulate. Use the behavior identifier to tell them apart.

Element Class Properties

Element class properties have the prefix stateMachine. or stateMachine({id}). if id is not empty.

path

Set path to state machine file to load.

  • Full name: stateMachine.path or stateMachine({id}).path
  • Type: string
  • Default Value: empty string
  • Expected File Type: *.desm
  • Example (*.deeclass)
    <string name='stateMachine.path'>actor.desm</string>

debug

Debug mode prefix. If not empty string enables debug mode with prefix to locate log messages easily.

  • Full name: stateMachine.debug or stateMachine({id}).debug
  • Type: string
  • Default Value: empty string
  • Example (*.deeclass)
    <string name='stateMachine.debug'>Debug-Actor-SM</string>

Events

This behavior has no events.

Behavior Tree Actions

This behavior adds these behavior tree actions if behavior tree is present. If behavior has non-empty identifier replace stateMachine with stateMachine(id).

stateMachine.set

Set one or more state machine parameters.

ParameterValueDescription
reset Set state machine root state as current state
statestringSet state machine state to state with identifier matching string value

This is an example of using this action:

<action name='stateMachine.set'>
  <parameter name='state'>open</parameter>
</action>

stateMachine.event

Run event on state machine. Action returns BTResult.success no matter if current state understands event or not unless required parameter is present.

ParameterValueDescription
idstringIdentifier of event to run
required If present action fails if current state does not understand event

This is an example of using this action:

<action name='stateMachine.event'>
  <parameter name='id'>open door</parameter>
</action>

stateMachine.check

Check one or more state machine parameters. Action succeeds if all parameter value matches their respective state machine parameter otherwise action fails. This action is typically used as first action in a sequence to run the sequence only if a state machine parameter matches (or not).

ParameterValueDescription
statestringCurrent state identifier matches string value
state.notstringCurrent state identifier does not match string value
state.startsstringCurrent state identifier starts with string value
state.starts.notstringCurrent state identifier does not start with string value
state.endsstringCurrent state identifier ends with string value
state.ends.notstringCurrent state identifier does not end with string value
state.containsstringCurrent state identifier contains string value
state.contains.notstringCurrent state identifier does not contain string value
wait If present action returns BTResult.running instead of BTResult.failed to wait until the checks are all fulfilled

This is an example of using this action:

<sequence>
  <action name='stateMachine.check'>
    <parameter name='state'>open</parameter>
  </action>
  <!-- actions here run only if state machine is in the "open" state -->
</sequence>

Behavior Tree Conditions

This behavior adds these behavior tree conditions if behavior tree is present. If behavior has non-empty identifier replace stateMachine with stateMachine(id).

stateMachine.check

Check one or more state machine parameters. Conditions returns true if all parameter value match their respective state machine parameter. This condition is typically used to run an action or sequence of actions as long as state machine conditions are true.

ParameterValueDescription
stateMachine.statestringCurrent state identifier matches string value
stateMachine.state.notstringCurrent state identifier does not match string value
stateMachine.state.startsstringCurrent state identifier starts with string value
stateMachine.state.starts.notstringCurrent state identifier does not start with string value
stateMachine.state.endsstringCurrent state identifier ends with string value
stateMachine.state.ends.notstringCurrent state identifier does not end with string value
stateMachine.state.containsstringCurrent state identifier contains string value
stateMachine.state.contains.notstringCurrent state identifier does not contain string value

This is an example of using this condition:

<action name='myAction' id='doing something'>
  <parameter name='stateMachine.state'>open</parameter>
  <condition>stateMachine.check</condition>
</action>

Required Behaviors

This behavior requires no other behaviors.

Optional Behaviors

Persistency

This behavior does support element class to be persistable (setPersistable). Saves state machine content (SMContext).

API Documentation

ECBehaviorStateMachine.

Since DragonScript Module Version 1.3

Use Cases

  • Create element logic without writing state machine using scripts.
  • Reuse element logic across different elements.
  • Split element logic into smaller logic units using multiple state machines (potentially reused).

Element Class Example

Example of the Single State Machine Usage.

class MyElementClass extends BehaviorElementClass
  func new()
    var ECBehaviorStateMachine smbehavior = ECBehaviorStateMachine.new(this)
    smbehavior.getPath().setValue("/content/myBehavior.desm")
    
    // here you can add now behaviors assigining actions and conditions for
    // the state machine to use
    ...
    
    // add listeners to behaviors to send events to the state machine
    var ECBehaviorTwoStateAnimated animated = ...
    animated.addActionConditionFactory(MyEventListener.Factory.new(smbehavior))
  end
  
  // two state listeners used to send events
  class MyEventListener extends ECBehaviorTwoStateAnimated.DefaultListener
    class Factory implements ECBehaviorTwoStateAnimated.ActionConditionFactory
      public var ECBehaviorStateMachine stateMachine
      
      func new(ECBehaviorStateMachine stateMachine)
        this.stateMachine = stateMachine
      end
      
      func ECBehaviorTwoStateAnimated.Listener createListener(ECBehaviorTwoStateAnimated.Instance instance)
        return MyEventListener.new(stateMachine.instance(instance.getElement()))
      end
    end
    
    public var ECBehaviorStateMachine.Instance stateMachine
    
    func new(ECBehaviorStateMachine.Instance stateMachine)
      this.stateMachine = stateMachine
    end
    
    func void stopActivate(ECBehaviorTwoStateAnimated.Instance instance)
      stateMachine.runEvent("animated activated")
    end
    
    func void stopDeactivate(ECBehaviorTwoStateAnimated.Instance instance)
      stateMachine.runEvent("animated deactivated")
    end
  end
end

Example of the Multiple State Machine Usage.

class MyElementClass extends BehaviorElementClass
  func new()
    var ECBehaviorStateMachine smSpecific = ECBehaviorStateMachine.new(this, "specific")
    smSpecific.getPath().setValue("/content/mySpecificBehavior.desm")
    
    var ECBehaviorStateMachine smGeneric = ECBehaviorStateMachine.new(this, "idle")
    smGeneric.getPath().setValue("/content/myGenericBehavior.desm")
    
    // here you can add now behaviors assigining actions and conditions for both
    // state machines to use
    ...
    
    // add listeners to behaviors to send events to the state machine. the same
    // MyEventListener is used as in the single state machine example. the example
    // here uses two animated behaviors each sending events to one of the state
    // machines. in general using multiple state machines the events should be
    // disjoint but it is fully valid to send the same event to both if the
    // state machines are written to deal with this properly.
    var ECBehaviorTwoStateAnimated animated1 = ...
    animated1.addActionConditionFactory(MyEventListener.Factory.new(smSpecific))
    
    var ECBehaviorTwoStateAnimated animated2 = ...
    animated2.addActionConditionFactory(MyEventListener.Factory.new(smGeneric))
  end
end

The above example loads and runs two state machines. The first one is running specific state machine. The second state machine provides two separate state machines able to handle multiple logic at the same time. By writing the state machines properly the two state machienes do not interfere with each other and allow to split up state machines into multiple ones which can help create complex logic more simple and stable.

Action and Condition Factory

This example shows how to use a factory to add a condition checking for a trigger and an action manipulating a trigger.

class MyElementClass extends BehaviorElementClass
  func new()
    var ECBehaviorStateMachine smbehavior = ECBehaviorStateMachine.new(this)
    smbehavior.getPath().setValue("/content/mySpecificBehavior.desm")
    
    // add factory to create actions and conditions later on. this example uses
    // a code block for simplicity. using classes implementing ActionConditionFactory
    // is preferred since it allows to reuse factories across element classes.
    smbehavior.setActionConditionFactory(block ECBehaviorStateMachine.Instance instance
      // add condition evaluating to true if "player.insideZone" trigger is in fired state.
      // the condition can be used in the state machine using the name "player is inside zone".
      instance.setCondition("player is inside zone", SMConditionTrigger.new(\
        "player.insideZone", SMConditionTrigger.TestMode.fired))
      
      // add action pulsing (fire and immediately reset) "player.damage" trigger.
      // the action can be run in the state machine using the name "hurt playe".
      instance.setAction("hurt player", SMActionTrigger.new("player.damage", SMActionTrigger.Action.pulse))
    end)
  end
end

Behavior Factory

Using element class supporting adding behaviors the behavior can be added like this:

<?xml version='1.0' encoding='UTF-8'?>
<elementClass name='MyClass' class='GenericBehaviorElement'>
  <behavior type='ECBehaviorStateMachine'>
    <!-- set element properties. omit property prefix if used inside behavior tag -->
    <string name='.path'>actor.desm</string>
  </behavior>
 
  <!-- for adding multiple behaviors use unique identifiers -->
  <behavior type='ECBehaviorStateMachine' id='second'/>
</elementClass>

Live Examples

You could leave a comment if you were logged in.
dragengine/modules/dragonscript/behavior_statemachine.txt · Last modified: 2025/05/06 14:50 by dragonlord