Skip to content
19 changes: 19 additions & 0 deletions addons/behaviour_toolkit/behaviour_tree/bt_composite.gd
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTComposite.svg")
class_name BTComposite extends BTBehaviour


## The leaves under the composite node.
@onready var leaves: Array = get_children()


func _get_configuration_warnings() -> PackedStringArray:
var warnings: Array = []

var parent = get_parent()
var children = get_children()

if not parent is BTComposite and not parent is BTRoot and not parent is BTDecorator:
warnings.append("BTComposite node must be a child of BTComposite or BTRoot node.")

if children.size() == 0:
warnings.append("BTComposite node must have at least one child.")

if children.size() == 1:
warnings.append("BTComposite node should have more than one child.")

return warnings
28 changes: 24 additions & 4 deletions addons/behaviour_toolkit/behaviour_tree/bt_decorator.gd
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTDecorator.svg")
class_name BTDecorator extends BTBehaviour

Expand All @@ -7,7 +8,26 @@ class_name BTDecorator extends BTBehaviour


func _get_leaf() -> BTBehaviour:
if get_child_count() == 0:
return null

return get_child(0)
if get_child_count() == 0:
return null

return get_child(0)


func _get_configuration_warnings() -> PackedStringArray:
var warnings: Array = []

var parent = get_parent()
var children = get_children()

if not parent is BTComposite and not parent is BTRoot:
warnings.append("Decorator node should be a child of a composite node or the root node.")

if children.size() == 0:
warnings.append("Decorator node should have a child.")
elif children.size() > 1:
warnings.append("Decorator node should have only one child.")
elif not children[0] is BTBehaviour:
warnings.append("Decorator node should have a BTBehaviour node as a child.")

return warnings
16 changes: 16 additions & 0 deletions addons/behaviour_toolkit/behaviour_tree/bt_leaf.gd
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTLeaf.svg")
class_name BTLeaf extends BTBehaviour


func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus:
return BTStatus.SUCCESS


func _get_configuration_warnings() -> PackedStringArray:
var warnings: Array = []

var parent = get_parent()
var children = get_children()

if not parent is BTBehaviour and not parent is BTRoot:
warnings.append("BTLeaf node must be a child of BTBehaviour or BTRoot node.")

if children.size() > 0:
warnings.append("BTLeaf node must not have any children.")

return warnings
17 changes: 16 additions & 1 deletion addons/behaviour_toolkit/behaviour_tree/bt_leaf_integration.gd
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTLeafIntegration.svg")
class_name BTLeafIntegration extends BTLeaf


@export var state_machine: FiniteStateMachine
@export var state_machine: FiniteStateMachine:
set(value):
state_machine = value
update_configuration_warnings()


func _get_configuration_warnings():
var warnings: Array = []

warnings.append_array(super._get_configuration_warnings())

if state_machine == null:
warnings.append("No state machine set.")

return warnings
23 changes: 23 additions & 0 deletions addons/behaviour_toolkit/behaviour_tree/bt_root.gd
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTRoot.svg")
class_name BTRoot extends BehaviourToolkit
## Node used as a base parent (root) of a Behaviour Tree
Expand Down Expand Up @@ -32,6 +33,12 @@ var current_status: BTBehaviour.BTStatus


func _ready() -> void:
# Don't run in editor
if Engine.is_editor_hint():
set_physics_process(false)
set_process(false)
return

if blackboard == null:
blackboard = _create_local_blackboard()

Expand Down Expand Up @@ -68,3 +75,19 @@ func _create_local_blackboard() -> Blackboard:
func _setup_processing() -> void:
set_physics_process(process_type == ProcessType.PHYSICS)
set_process(process_type == ProcessType.IDLE)


func _get_configuration_warnings() -> PackedStringArray:
var warnings: Array = []

var children = get_children()

if children.size() == 0:
warnings.append("Behaviour Tree needs to have one Behaviour child.")
elif children.size() == 1:
if not children[0] is BTBehaviour:
warnings.append("The child of Behaviour Tree needs to be a Behaviour.")
elif children.size() > 1:
warnings.append("Behaviour Tree can have only one Behaviour child.")

return warnings
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTCompositeIntegration.svg")
class_name BTIntegratedFSM extends BTComposite


@onready var state_machine: FiniteStateMachine = _get_machine()
var state_machine: FiniteStateMachine = null

func _ready():
if not Engine.is_editor_hint():
state_machine = _get_machine()


func tick(_delta: float, _actor: Node, _blackboard: Blackboard) -> BTStatus:
if state_machine.active == false:
Expand All @@ -20,3 +25,20 @@ func _get_machine() -> FiniteStateMachine:
return null
else:
return get_child(0)


func _get_configuration_warnings():
var warnings: Array = []
var children = get_children()

if children.size() == 0:
warnings.append("BTIntegratedFSM must have a child node. The first child will be used as the state machine.")

if children.size() > 1:
warnings.append("BTIntegratedFSM can only have one child node. The first child will be used as the state machine.")

if children.size() == 1:
if not children[0] is FiniteStateMachine:
warnings.append("BTIntegratedFSM's child node must be a FiniteStateMachine. The first child will be used as the state machine.")

return warnings
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTCompositeRandomSelector.svg")
class_name BTRandomSelector extends BTComposite
## The selector composite but with a random order of the leaves.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTCompositeRandomSequence.svg")
class_name BTRandomSequence extends BTComposite
## The squence composite but with a random order of the leaves.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTCompositeSelector.svg")
class_name BTSelector extends BTComposite
## Selects the first child that succeeds, or fails if none do.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTCompositeSequence.svg")
class_name BTSequence extends BTComposite
## A sequence node will return success if all of its children return success.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTSimpleParallel.svg")
class_name BTSimpleParallel extends BTComposite
## Executes all children in parallel, and returns SUCCESS depending on the policy. It returns FAILURE if any child returns FAILURE.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTDecoratorFail.svg")
class_name BTAlwaysFail extends BTDecorator
## The leaf will always fail after running.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTDecoratorSucceed.svg")
class_name BTAlwaysSucceed extends BTDecorator
## The leaf will always succeed after running.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTDecoratorNot.svg")
class_name BTInverter extends BTDecorator
## The result of the leaf is inverted.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTDecoratorLimiter.svg")
class_name BTLimiter extends BTDecorator
## Limits the number of times a leaf can be run. (The leaf will fully run, before triggering the limit.)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTDecoratorRepeat.svg")
class_name BTRepeat extends BTDecorator
## Repeats the leaf a number of times.
Expand Down
70 changes: 47 additions & 23 deletions addons/behaviour_toolkit/behaviour_tree/leaves/leaf_call.gd
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@tool
@icon("res://addons/behaviour_toolkit/icons/BTLeafCall.svg")
class_name LeafCall extends BTLeaf
## Leaf that calls a method on a target node. The target can be the actor, the blackboard or a custom node.
Expand All @@ -6,39 +7,62 @@ class_name LeafCall extends BTLeaf

## The target type of the call. Can be the actor, the blackboard or a custom node.
enum CallTarget {
ACTOR, ## The actor node set on the BTRoot node.
BLACKBOARD, ## The blackboard node set on the BTRoot node.
CUSTOM ## A custom node set on the custom_target variable.
ACTOR, ## The actor node set on the BTRoot node.
BLACKBOARD, ## The blackboard node set on the BTRoot node.
CUSTOM ## A custom node set on the custom_target variable.
}


## The method to call on the target node.
@export var method: StringName
@export var method: StringName:
set(value):
method = value
update_configuration_warnings()
## The arguments to pass to the method.
@export var arguments: Array = []

@export_category("Target")
## The target type of the call. Can be the actor, the blackboard or a custom node.
@export var target_type: CallTarget = CallTarget.ACTOR
@export var target_type: CallTarget = CallTarget.ACTOR:
set(value):
target_type = value
update_configuration_warnings()
## The custom node to call the method on. Only used if target_type is set to CallTarget.CUSTOM.
@export var custom_target: Node
@export var custom_target: Node:
set(value):
custom_target = value
update_configuration_warnings()


func tick(delta: float, actor: Node, blackboard: Blackboard):
var target

match target_type:
CallTarget.ACTOR:
target = actor
CallTarget.BLACKBOARD:
target = blackboard
CallTarget.CUSTOM:
target = custom_target

if target.has_method(method):
target.callv(method, arguments)
else:
print("Method " + method + " not found on target " + target.to_string())
return BTStatus.FAILURE

return BTStatus.SUCCESS
var target

match target_type:
CallTarget.ACTOR:
target = actor
CallTarget.BLACKBOARD:
target = blackboard
CallTarget.CUSTOM:
target = custom_target

if target.has_method(method):
target.callv(method, arguments)
else:
print("Method " + method + " not found on target " + target.to_string())
return BTStatus.FAILURE

return BTStatus.SUCCESS


func _get_configuration_warnings():
var warnings: Array = []

warnings.append_array(super._get_configuration_warnings())

if method == "":
warnings.append("Method is not set.")

if target_type == CallTarget.CUSTOM and custom_target == null:
warnings.append("Target type is set to CUSTOM but no custom target is set.")

return warnings
Loading