This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
dragengine:modules:dragonscript:behavior_statemachine [2020/09/13 15:59] – created dragonlord | dragengine:modules:dragonscript:behavior_statemachine [2025/03/13 17:10] (current) – dragonlord | ||
---|---|---|---|
Line 1: | Line 1: | ||
{{tag> | {{tag> | ||
<WRAP youarehere> | <WRAP youarehere> | ||
- | [[: | + | [[: |
</ | </ | ||
Line 16: | Line 16: | ||
</ | </ | ||
- | Behavior element behavior adding | + | Behavior element behavior adding StateMachine support. |
- | Loads state machine from file (*.desm) and creates | + | Loads state machine from file (*.desm) and creates |
+ | |||
+ | You can assign # | ||
This behavior can be used in different ways depending on the needs. | This behavior can be used in different ways depending on the needs. | ||
- | Single state machine 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. | + | //Single State Machine Usage// |
- | This is an example code for such a setup: | + | This is the most simple solution where only one state machine is used. For many situations |
- | < | + | |
- | class MyElementClass extends BehaviorElementClass | + | |
- | | + | |
- | var ECBehaviorStateMachine smbehavior = ECBehaviorStateMachine.new(this) | + | |
- | smbehavior.getPath().setValue("/ | + | |
- | + | ||
- | // here you can add now behaviors | + | |
- | // the state machine to use | + | |
- | ... | + | |
- | + | ||
- | // add listeners to behaviors to send events | + | |
- | 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 | + | |
- | | + | |
- | + | ||
- | | + | |
- | this.stateMachine = stateMachine | + | |
- | end | + | |
- | + | ||
- | | + | |
- | return MyEventListener.new(stateMachine.instance(instance.getElement())) | + | |
- | end | + | |
- | end | + | |
- | + | ||
- | | + | |
- | + | ||
- | | + | |
- | this.stateMachine = stateMachine | + | |
- | end | + | |
- | + | ||
- | | + | |
- | stateMachine.runEvent(" | + | |
- | end | + | |
- | + | ||
- | | + | |
- | stateMachine.runEvent(" | + | |
- | end | + | |
- | end | + | |
- | end | + | |
- | </ | + | |
- | **Action and Condition Factory** | + | See [[# |
- | You can assign [[https://developer.dragondreams.ch/docs/dragonscript/ | + | //Multiple State Machine Usage// |
- | The example below shows how to use a factory | + | You can add multiple instances of ECBehaviorStateMachine |
- | < | + | |
- | class MyElementClass extends BehaviorElementClass | + | See [[# |
- | | + | |
- | var ECBehaviorStateMachine smbehavior = ECBehaviorStateMachine.new(this) | + | |
- | smbehavior.getPath().setValue("/ | + | |
- | + | ||
- | // add factory to create | + | |
- | // a code block for simplicity. using classes implementing ActionConditionFactory | + | |
- | // is preferred since it allows | + | |
- | smbehavior.setActionConditionFactory( block ECBehaviorStateMachine.Instance instance | + | |
- | // add condition evaluating to true if " | + | |
- | // the condition can be used in the state machine using the name " | + | |
- | | + | |
- | " | + | |
- | + | ||
- | // add action pulsing (fire and immediately reset) " | + | |
- | // the action can be run in the state machine using the name "hurt playe". | + | |
- | instance.setAction(" | + | |
- | end ) | + | |
- | end | + | |
- | end | + | |
- | </code> | + | |
====== Instance Counts ====== | ====== Instance Counts ====== | ||
- | + | This behavior | |
- | You can add multiple instances of **ECBehaviorStateMachine** to the element to load and use multiple state machines. | + | |
- | + | ||
- | This is an example code for such a setup: | + | |
- | < | + | |
- | class MyElementClass extends BehaviorElementClass | + | |
- | | + | |
- | var ECBehaviorStateMachine smSpecific = ECBehaviorStateMachine.new(this, | + | |
- | smSpecific.getPath().setValue("/ | + | |
- | + | ||
- | var ECBehaviorStateMachine smGeneric = ECBehaviorStateMachine.new(this, | + | |
- | smGeneric.getPath().setValue("/ | + | |
- | + | ||
- | // here you can add now behaviors assigining actions and conditions for both | + | |
- | // state machines | + | |
- | ... | + | |
- | + | ||
- | // 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 | + | |
- | // disjoint but it is fully valid to send the same event to both if the | + | |
- | // state machines are written | + | |
- | 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 | + | |
====== Element Class Properties ====== | ====== Element Class Properties ====== | ||
- | + | Element class properties have the prefix | |
- | Element class properties have the prefix | + | |
===== path ===== | ===== path ===== | ||
- | Path to state machine | + | Set path to state machine |
- | * Full name: "stateMachine.path" | + | * Full name: '' |
- | * Type: Path (*.desm) | + | * Type: string |
- | * Default Value "" | + | * Default Value: empty string |
- | * Example (*.deeclass) <code xml>< | + | * Expected File Type: '' |
+ | * Example (*.deeclass) <code xml>< | ||
+ | |||
+ | ===== Events ===== | ||
+ | |||
+ | This behavior has no events. | ||
====== Required Behaviors ====== | ====== Required Behaviors ====== | ||
- | This behavior | + | This behavior |
====== Optional Behaviors ====== | ====== Optional Behaviors ====== | ||
Line 155: | Line 64: | ||
====== Persistency ====== | ====== Persistency ====== | ||
- | This behavior does support element class to be persistable (setPersistable). Saves state machine content ([[https:// | + | This behavior does support element class to be persistable (setPersistable). Saves state machine content (# |
====== API Documentation ====== | ====== API Documentation ====== | ||
- | [[https:// | + | # |
- | Since DragonScript Module Version | + | Since DragonScript Module Version |
====== Use Cases ====== | ====== Use Cases ====== | ||
Line 171: | Line 81: | ||
====== Element Class Example ====== | ====== Element Class Example ====== | ||
- | Element class using a state machine loaded from " | + | Example of the //Single State Machine Usage//. |
< | < | ||
class MyElementClass extends BehaviorElementClass | class MyElementClass extends BehaviorElementClass | ||
- | | + | |
- | var ECBehaviorStateMachine smbehavior = ECBehaviorStateMachine.new(this) | + | var ECBehaviorStateMachine smbehavior = ECBehaviorStateMachine.new(this) |
- | smbehavior.getPath().setValue("/ | + | smbehavior.getPath().setValue("/ |
+ | |||
+ | // 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) |
- | // 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 | + | |
- | | + | |
- | + | ||
- | | + | |
- | this.stateMachine = stateMachine | + | |
- | end | + | |
- | + | ||
- | | + | |
- | return MyEventListener.new(stateMachine.instance(instance.getElement())) | + | |
- | end | + | |
- | end | + | |
- | + | ||
- | | + | |
- | + | ||
- | | + | |
this.stateMachine = stateMachine | this.stateMachine = stateMachine | ||
- | end | + | end |
- | | + | |
- | | + | func ECBehaviorTwoStateAnimated.Listener createListener(ECBehaviorTwoStateAnimated.Instance instance) |
- | stateMachine.runEvent(" | + | return MyEventListener.new(stateMachine.instance(instance.getElement())) |
- | | + | end |
- | | + | end |
- | public | + | |
- | stateMachine.runEvent(" | + | |
- | | + | |
+ | func new(ECBehaviorStateMachine.Instance stateMachine) | ||
+ | this.stateMachine = stateMachine | ||
+ | end | ||
+ | |||
+ | | ||
+ | stateMachine.runEvent(" | ||
+ | end | ||
+ | |||
+ | func void stopDeactivate(ECBehaviorTwoStateAnimated.Instance instance) | ||
+ | stateMachine.runEvent(" | ||
+ | end | ||
end | end | ||
end | end | ||
+ | </ | ||
+ | |||
+ | Example of the //Multiple State Machine Usage//. | ||
+ | |||
+ | < | ||
+ | class MyElementClass extends BehaviorElementClass | ||
+ | func new() | ||
+ | var ECBehaviorStateMachine smSpecific = ECBehaviorStateMachine.new(this, | ||
+ | smSpecific.getPath().setValue("/ | ||
+ | | ||
+ | var ECBehaviorStateMachine smGeneric = ECBehaviorStateMachine.new(this, | ||
+ | smGeneric.getPath().setValue("/ | ||
+ | | ||
+ | // 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("/ | ||
+ | | ||
+ | // 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 " | ||
+ | // the condition can be used in the state machine using the name " | ||
+ | instance.setCondition(" | ||
+ | " | ||
+ | | ||
+ | // add action pulsing (fire and immediately reset) " | ||
+ | // the action can be run in the state machine using the name "hurt playe" | ||
+ | instance.setAction(" | ||
+ | end) | ||
+ | end | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | ====== Behavior Factory ====== | ||
+ | |||
+ | Using element class supporting adding behaviors the behavior can be added like this: | ||
+ | <code xml> | ||
+ | <?xml version=' | ||
+ | < | ||
+ | < | ||
+ | <!-- set element properties. omit property prefix if used inside behavior tag --> | ||
+ | <string name=' | ||
+ | </ | ||
+ | | ||
+ | <!-- for adding multiple behaviors use unique identifiers --> | ||
+ | < | ||
+ | </ | ||
</ | </ | ||