User Tools

Site Tools


dragengine:modules:dragonscript:behaviortrees

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
dragengine:modules:dragonscript:behaviortrees [2025/03/13 18:30] – removed - external edit (Unknown date) 127.0.0.1dragengine:modules:dragonscript:behaviortrees [2025/03/13 18:31] (current) dragonlord
Line 1: Line 1:
 +{{tag>graphic skin texture fileformat}}
 +<WRAP youarehere>
 +[[:start|Start Page]] >> [[:gamedev|Game Development with the Drag[en]gine]] >> **Behavior Tree File Format**
 +</WRAP>
 +
 +====== Behavior Trees ======
 +
 +Behavior trees are structured graphics describing the AI logic using a tree of rules. The behavior tree is at all times located at one of the rules in the tree. During each simulation step (typically during frame update) the behavior tree moves along the tree until an rule returns either ''BTResult.running'' . The behavior tree keeps on running the active rule each simulation step until the rule either returns ''BTResult.success'' or ''BTResult.failure''. The AI logic is formed by the logic behind each rule.
 +
 +Each can also have one or more conditions assigned. Before each run of the rule the conditions are evaluated. If any of the conditions evaluates to false the rule fails. Only the conditions of the active rule are evaluated. The conditions of the parent rule are only evaluated if the active node returns anything else but ''BTResult.running''. In this case the behavior tree wants to move to the next action. To do this the parent rule is run which then automatically evaluates the parent rule conditions.
 +
 +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.
 +
 +The following rules can be used:
 +
 +===== Action =====
 +
 +This is the main working rule connecting game logic to the behavior tree. BTAction subclasses are created by the game developer and added to the behavior tree. If the rule is run the action is looked up and run. The return value of the action becomes the return value of the rule.
 +
 +For performance reasons the action is looked up once then stored in the rule. This is correct behavior as long as the rules are not changed at run-time. If you need changing actions at run-time implement a BTAction forwarding to the desired BTAction. This way the cached action stays valid while the actual BTAction called inside can change. This is though an elaborate situation. Usually actions are added to the behavior tree once and then never change.
 +
 +If the named action is not found the rule fails with ''BTResult.failure''.
 +
 +There exists convenience implementations of the BTAction interface linking to action sources present in the game engine:
 +^Script Class^Description^
 +|BTActionParameterTable|Updates the value of a ParameterTree entry.|
 +|BTActionTrigger|Fire or reset a trigger target.|
 +|BTActionSendGlobalEvent|Send a global even using GlobalEvents class, typically BaseGameApp.getApp().getGlobalEvents().|
 +|BTBlockAction|<WRAP>Action running a script block like this:
 +<code>
 +new BTBlockAction(block BTContext context, Dictionary parameters
 +  // do something
 +  return BTResult.running // or .success or .failure
 +end)
 +</code>
 +This allows to quickly add actions without needing to write a new script class.</WRAP>|
 +
 +Actions can be paramtrized by adding one or more parameters to the rule. The actions 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 rule conditions. And while actions already define the ''source'' part rather well for conditions this is unknown.
 +
 +===== Sequence =====
 +
 +Runs all actions in sequence. Returns ''BTResult.success'' if all actions returned ''BTResult.success'' . If an action return ''BTResult.failure'' processing of the rule stops and ''BTResult.failure'' is returned. If no actions are present ''BTResult.failure'' is returned.
 +
 +If looping is set to true the sequence restarts at the beginning if all actions returns ''BTResult.success'' . This allows to keep looping a sequence until the first time any action returns ''BTResult.failure'' .
 +
 +===== Choice =====
 +
 +Runs all actions in sequence. Returns ''BTResult.failure'' if all actions returned ''BTResult.failure'' . If an action returns ''BTResult.success'' processing of the rule stops and ''BTResult.success'' is returned. If no actions are present ''BTResult.failure'' is returned.
 +
 +If looping is set to true the choice restarts at the beginning if the first action returns ''BTResult.success'' . This allows to keep looping a choice until the first time all actions return ''BTResult.failure'' .
 +
 +===== Success =====
 +
 +Returns always ''BTResult.success'' unless a rule condition evaluates to false.
 +
 +The main use for this rule is to test rule conditions without needing to attach them to some other rule.
 +
 +===== Failure =====
 +
 +Returns always ''BTResult.failure''.
 +
 +The main use for this rule is to fail a sequence rule by placing this last.
 +
 +===== Running =====
 +
 +Returns always ''BTResult.running'' unless a rule condition evaluates to false.
 +
 +The main use for this rule is to force waiting until a rule conditions fails.
 +
 +
 +====== File Format (*.debtree) ======
 +
 +The behavior tree file format is recognized by the LoadBehaviorTree script class. The file is an XML file with a simple structure to define a behavior tree using XML.
 +
 +<uml>
 +@startuml
 +
 +object "behaviorTree" as behaviorTree {
 +  <#transparent,#transparent>|action||
 +  |sequence||
 +  |choice||
 +  |success||
 +  |failure||
 +  |running||
 +  |subtree|  <color:gray>string|
 +}
 +
 +object "action" as action {
 +  <#transparent,#transparent>|parameter|  <color:gray>string|
 +  |condition|  <color:gray>string|
 +  |conditionMode|  <color:gray>enum|
 +}
 +behaviorTree --> action
 +
 +object "sequence" as sequence {
 +  <#transparent,#transparent>|parameter|  <color:gray>string|
 +  |condition|  <color:gray>string|
 +  |conditionMode|  <color:gray>enum|
 +  |action||
 +  |sequence||
 +  |choice||
 +  |success||
 +  |failure||
 +  |running||
 +  |subtree|  <color:gray>string|
 +}
 +behaviorTree --> sequence
 +
 +object "choice" as choice {
 +  <#transparent,#transparent>|parameter|  <color:gray>string|
 +  |condition|  <color:gray>string|
 +  |conditionMode|  <color:gray>enum|
 +  |action||
 +  |sequence||
 +  |choice||
 +  |success||
 +  |failure||
 +  |running||
 +  |subtree|  <color:gray>string|
 +}
 +behaviorTree --> choice
 +
 +object "success" as success {
 +  <#transparent,#transparent>|parameter|  <color:gray>string|
 +  |condition|  <color:gray>string|
 +  |conditionMode|  <color:gray>enum|
 +}
 +behaviorTree --> success
 +
 +object "failure" as failure {
 +  <#transparent,#transparent>|parameter|  <color:gray>string|
 +  |condition|  <color:gray>string|
 +  |conditionMode|  <color:gray>enum|
 +}
 +behaviorTree --> failure
 +
 +object "running" as running {
 +  <#transparent,#transparent>|parameter|  <color:gray>string|
 +  |condition|  <color:gray>string|
 +  |conditionMode|  <color:gray>enum|
 +}
 +behaviorTree --> running
 +
 +@enduml
 +</uml>
 +
 +====== Tags ======
 +
 +===== behaviorTree =====
 +
 +^Tag^Description^Occurance^Default^
 +|action|Add action rule|0..N|-|
 +|sequence|Add sequence rule|0..N|-|
 +|choice|Add choice rule|0..N|-|
 +|success|Add success rule|0..N|-|
 +|failure|Add failure rule|0..N|-|
 +|running|Add running rule|0..N|-|
 +|subtree|Load behavior tree using path from tag text content. Subtree is added to the behavior tree as a sequence rule containing the loaded behavior tree|0..N|-|
 +
 +===== action =====
 +
 +Adds an action rule.
 +
 +^Attribute^Description^Occurance^Default^
 +|name|Name of action to run.|Required|-|
 +
 +^Tag^Description^Occurance^Default^
 +|parameter|<WRAP>Add parameter. Parameter value is text content of node which can be empty. Attributes:
 +  * ''name'': Name of parameter. Required.
 +</WRAP>|0..N|-|
 +|condition|Add condition. Condition name is text content of node|0..N|-|
 +|conditionMode|<WRAP>How conditions are evaluated. Valid values:
 +  * ''allTrue'': All conditions have to evaluate to true.
 +  * ''anyTrue'': At least one condition has to evaluate to true.
 +  * ''anyFalse'': At least one condition has to evaluate to false.
 +  * ''allFalse'': All conditions have to evaluate to false.
 +</WRAP>|0..1|''allTrue''|
 +
 +===== sequence =====
 +
 +Adds a sequence rule.
 +
 +^Attribute^Description^Occurance^Default^
 +|loop|Loop sequence.|Optional|''false''|
 +|doNotFail|If sequence fails return ''BTResult.success''. Useful to optional sequences running as many rules in a sequence as possible without failing the parent rule.|Optional|''false''|
 +
 +^Tag^Description^Occurance^Default^
 +|parameter|<WRAP>Add parameter. Parameter value is text content of node which can be empty. Attributes:
 +  * ''name'': Name of parameter. Required.
 +</WRAP>|0..N|-|
 +|condition|Add condition. Condition name is text content of node|0..N|-|
 +|conditionMode|<WRAP>How conditions are evaluated. Valid values:
 +  * ''allTrue'': All conditions have to evaluate to true.
 +  * ''anyTrue'': At least one condition has to evaluate to true.
 +  * ''anyFalse'': At least one condition has to evaluate to false.
 +  * ''allFalse'': All conditions have to evaluate to false.
 +</WRAP>|0..1|''allTrue''|
 +|action|Add action rule|0..N|-|
 +|sequence|Add sequence rule|0..N|-|
 +|choice|Add choice rule|0..N|-|
 +|success|Add success rule|0..N|-|
 +|failure|Add failure rule|0..N|-|
 +|running|Add running rule|0..N|-|
 +|subtree|Load behavior tree using path from tag text content. Subtree is added to the behavior tree as a sequence rule containing the loaded behavior tree|0..N|-|
 +
 +===== choice =====
 +
 +Adds a choice rule.
 +
 +^Attribute^Description^Occurance^Default^
 +|loop|Loop choice.|Optional|''false''|
 +|doNotFail|If choice fails return ''BTResult.success''. Useful for optional choices there failing the choice should not fail the parent rule.|Optional|''false''|
 +
 +^Tag^Description^Occurance^Default^
 +|parameter|<WRAP>Add parameter. Parameter value is text content of node which can be empty. Attributes:
 +  * ''name'': Name of parameter. Required.
 +</WRAP>|0..N|-|
 +|condition|Add condition. Condition name is text content of node|0..N|-|
 +|conditionMode|<WRAP>How conditions are evaluated. Valid values:
 +  * ''allTrue'': All conditions have to evaluate to true.
 +  * ''anyTrue'': At least one condition has to evaluate to true.
 +  * ''anyFalse'': At least one condition has to evaluate to false.
 +  * ''allFalse'': All conditions have to evaluate to false.
 +</WRAP>|0..1|''allTrue''|
 +|action|Add action rule|0..N|-|
 +|sequence|Add sequence rule|0..N|-|
 +|choice|Add choice rule|0..N|-|
 +|success|Add success rule|0..N|-|
 +|failure|Add failure rule|0..N|-|
 +|running|Add running rule|0..N|-|
 +|subtree|Load behavior tree using path from tag text content. Subtree is added to the behavior tree as a sequence rule containing the loaded behavior tree|0..N|-|
 +
 +===== success =====
 +
 +Adds a success rule.
 +
 +^Tag^Description^Occurance^Default^
 +|parameter|<WRAP>Add parameter. Parameter value is text content of node which can be empty. Attributes:
 +  * ''name'': Name of parameter. Required.
 +</WRAP>|0..N|-|
 +|condition|Add condition. Condition name is text content of node|0..N|-|
 +|conditionMode|<WRAP>How conditions are evaluated. Valid values:
 +  * ''allTrue'': All conditions have to evaluate to true.
 +  * ''anyTrue'': At least one condition has to evaluate to true.
 +  * ''anyFalse'': At least one condition has to evaluate to false.
 +  * ''allFalse'': All conditions have to evaluate to false.
 +</WRAP>|0..1|''allTrue''|
 +
 +===== failure =====
 +
 +Adds a failure rule.
 +
 +^Tag^Description^Occurance^Default^
 +|parameter|<WRAP>Add parameter. Parameter value is text content of node which can be empty. Attributes:
 +  * ''name'': Name of parameter. Required.
 +</WRAP>|0..N|-|
 +|condition|Add condition. Condition name is text content of node|0..N|-|
 +|conditionMode|<WRAP>How conditions are evaluated. Valid values:
 +  * ''allTrue'': All conditions have to evaluate to true.
 +  * ''anyTrue'': At least one condition has to evaluate to true.
 +  * ''anyFalse'': At least one condition has to evaluate to false.
 +  * ''allFalse'': All conditions have to evaluate to false.
 +</WRAP>|0..1|''allTrue''|
 +
 +===== running =====
 +
 +Adds a running rule.
 +
 +^Tag^Description^Occurance^Default^
 +|parameter|<WRAP>Add parameter. Parameter value is text content of node which can be empty. Attributes:
 +  * ''name'': Name of parameter. Required.
 +</WRAP>|0..N|-|
 +|condition|Add condition. Condition name is text content of node|0..N|-|
 +|conditionMode|<WRAP>How conditions are evaluated. Valid values:
 +  * ''allTrue'': All conditions have to evaluate to true.
 +  * ''anyTrue'': At least one condition has to evaluate to true.
 +  * ''anyFalse'': At least one condition has to evaluate to false.
 +  * ''allFalse'': All conditions have to evaluate to false.
 +</WRAP>|0..1|''allTrue''|
 +
 +====== Examples ======
 +
 +Example from the ExampleApp. A simple behavior tree making the actor wander around and if the player gets close tries to stay away from him. If the player is moving fast the actor gets jumpy.
 +
 +This uses the basic behavior tree system from the game engine with some ready made actions.
 +
 +<code xml><?xml version='1.0' encoding='ISO-8859-1'?>
 +<behaviorTree>
 + <!--
 + The basic AI loop. For this example we use a choice with all supported
 + behaviors. This could be also done differently but avoids the need to
 + use "success" rules to make a choice always succeed if no of the supported
 + behaviors applies.
 +
 + It is possible to add the loop="true" attribute. This would cause the
 + root rule to be looping. The difference is subtle but potentially
 + problematic. If the rule ends with a success state and looping is set
 + to true then the rule will start again from the beginning. As you can
 + imagine this can lead to a run-away situation if the rule continues
 + to return success state. If the rule is not looping with a success state
 + the processing ends for this stepping of the behavior tree. It is
 + recommended to not use looping on the root rule uness you have a
 + specific need to do so.
 +
 + Looping rules can be used anywhere in the behavior tree for both
 + sequence and choice rules. Looping can be useful in some situations.
 +
 + This choice is structed in a way all regular actions come first. One of
 + them is going to succeed so the interruption rule is never used. This
 + rule is only jumped to directly hence the name. It would be also possible
 + to embed the interruption behavior into the regular processing of the
 + behavior tree. In this case interruption actions would only be possible
 + after another action finished running.
 +
 + Rules are not required to have identifiers under certain circumstances.
 + Identifiers are used by these actions:
 + - Mandatory: Switch current rule (jumping) from script code
 + - Mandatory: Saving behavior tree context state to save states
 + - Optional: Debug logging to identify what rule is processed
 + For mandatory usage an exception will be thrown if rule identifiers are
 + null. If a rule only returns success or failure state and never returns
 + running state the identifier can be skipped. This works since only
 + running rules can be the current rule and thus only the identifier or
 + such rules are saved to file writers. If you never intend to save state
 + nor jump to rules you can skip them entirly.
 + -->
 + <choice id='root'>
 + <!--
 + Choice of behaviors reacting to player getting too close.
 +
 + This rule is jumped to directly if the player gets close. This makes
 + this rule an "interruption" rule. Such rules can be jumped to directly
 + but also work if run inside regular AI looping. Jumping to simply
 + makes the actor react immediatly. Without jumping the actor would
 + react after finishing his current sequence of actions.
 +
 + To make writing identifiers simpler a trick can be used. If the
 + identifier begins with a period the parent rule identifier is used
 + as prefix. For example the ID ".child" inside a parent with ID "parent"
 + becomes "parent.child".
 + -->
 +
 + <!--
 + Wander to a random position. This rule keeps running until the actor
 + arrives at the target. The action succeeds once the actor arrived at
 + the desired position. This action fails as long as player is too close.
 +
 + This action has a 25% chance.
 +
 + The attribute "name" defines the action to run and has to match a
 + BTAction present in the game scripts.
 + -->
 + <action id='wander' name='wander'>
 + <!--
 + Parameters have string key and value. The action-tag and custom BTAction
 + subclasses can use these parameters to modify the way the selected action
 + runs. Certain conditions and custom BTCondition subclasses can also use
 + the same parameters to modify the run checks.
 +
 + Since parameters are shared across all these elements care has to be taken
 + how the parameters are named. If for example two conditions use the same
 + parameter name they will receive the same value. If you need unique values
 + for specific types of conditions you have to choose individual parameter
 + names in your game scripts when adding the conditions to the context to
 + allow you to define them separately in your behavior trees.
 +
 + The condition and parameter tags can appear in any order.
 + -->
 + <parameter name='chance'>0.25</parameter>
 +
 + <!--
 + All actions use this condition to be interrupted. This could be also
 + achieved by jumping to a specific rule manually. In this example the
 + actions contain the interrupt condition.
 +
 + Each rule can have any number of conditions. The conditionMode states
 + how the rules are checked. Supported are these modes:
 + - 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
 + -->
 + <conditionMode>allFalse</conditionMode>
 + <condition>playerNearby</condition>
 +
 + <!--
 + The above condition is an example. To keep conditions more compact
 + you can create a negated version of the condition. This has been
 + done in the two actions below.
 + -->
 + </action>
 +
 + <!--
 + Randomly rotate. This action has a 35% chance.
 + -->
 + <action id='turning' name='turning'>
 + <parameter name='chance'>0.35</parameter>
 + <condition>playerNotNearby</condition>
 + </action>
 +
 + <!--
 + Wait a random amount of time. This action has a 100% chance.
 + -->
 + <action id='wait' name='wait'>
 + <parameter name='chance'>1</parameter>
 + <condition>playerNotNearby</condition>
 + </action>
 +
 + <!--
 + If the player is close enough and moving fast the actor tries to
 + flee by running and does a little jump for show. If any condition
 + is false this action is not triggered.
 +
 + Condition checks are best done inside the action itself instead of
 + using a construct like this:
 + <sequence>
 + <condition>isConditionTrue</condition>
 + <action>doAction</action>
 + </sequence>
 +
 + Using this construct is not wrong but prevents actions from being
 + interrupted if a condition changes. The condition in the example
 + above would be evaluated when the sequence is first entered and
 + whenever an inner action fails and the next one is tried.
 +
 + To make writing the identifiers simpler a trick can be used. If the
 + identifier begins with a period the parent rule identifier is used
 + as prefix. In this example the ID ".flee" becomes "interrupt.flee"
 + -->
 + <action id='flee' name='flee'>
 + <condition>playerNearby</condition>
 + </action>
 +
 + <!--
 + If the player is close enough and not moving fast the actor tries
 + to increase his distance to the player by walking. If any condition
 + is false this action is not triggered.
 + -->
 + <action id='backOff' name='backOff'>
 + <condition>playerNearby</condition>
 + </action>
 +
 + <!--
 + If we end up here no event condition is true. We want to loop again
 + so we need to use the success rule. Using failure instead (same as
 + doing nothing here) would fail the behavior tree and throw an exception.
 +
 + This is a good example where rule identifier is not required since the
 + rule never returns running and thus never will be the current rule
 + after the behavior tree finished stepping. Another such rule is
 + <failure/> which always fails.
 + -->
 + <success/>
 + </choice>
 +</behaviorTree>
 +</code>