generated from krampus/template-godot4
123 lines
3.9 KiB
GDScript
123 lines
3.9 KiB
GDScript
@tool
|
|
@icon("../../icons/simple_parallel.svg")
|
|
class_name SimpleParallelComposite extends Composite
|
|
|
|
## Simple Parallel nodes will attampt to execute all chidren at same time and
|
|
## can only have exactly two children. First child as primary node, second
|
|
## child as secondary node.
|
|
## This node will always report primary node's state, and continue tick while
|
|
## primary node return 'RUNNING'. The state of secondary node will be ignored
|
|
## and executed like a subtree.
|
|
## If primary node return 'SUCCESS' or 'FAILURE', this node will interrupt
|
|
## secondary node and return primary node's result.
|
|
## If this node is running under delay mode, it will wait seconday node
|
|
## finish its action after primary node terminates.
|
|
|
|
#how many times should secondary node repeat, zero means loop forever
|
|
@export var secondary_node_repeat_count: int = 0
|
|
|
|
#wether to wait secondary node finish its current action after primary node finished
|
|
@export var delay_mode: bool = false
|
|
|
|
var delayed_result := SUCCESS
|
|
var main_task_finished: bool = false
|
|
var secondary_node_running: bool = false
|
|
var secondary_node_repeat_left: int = 0
|
|
|
|
|
|
func _get_configuration_warnings() -> PackedStringArray:
|
|
var warnings: PackedStringArray = super._get_configuration_warnings()
|
|
|
|
if get_child_count() != 2:
|
|
warnings.append("SimpleParallel should have exactly two child nodes.")
|
|
|
|
if not get_child(0) is ActionLeaf:
|
|
warnings.append("SimpleParallel should have an action leaf node as first child node.")
|
|
|
|
return warnings
|
|
|
|
|
|
func tick(actor, blackboard: Blackboard):
|
|
for c in get_children():
|
|
var node_index = c.get_index()
|
|
if node_index == 0 and not main_task_finished:
|
|
if c != running_child:
|
|
c.before_run(actor, blackboard)
|
|
|
|
var response = c.tick(actor, blackboard)
|
|
if can_send_message(blackboard):
|
|
BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response)
|
|
|
|
delayed_result = response
|
|
match response:
|
|
SUCCESS, FAILURE:
|
|
_cleanup_running_task(c, actor, blackboard)
|
|
c.after_run(actor, blackboard)
|
|
main_task_finished = true
|
|
if not delay_mode:
|
|
if secondary_node_running:
|
|
get_child(1).interrupt(actor, blackboard)
|
|
_reset()
|
|
return delayed_result
|
|
RUNNING:
|
|
running_child = c
|
|
if c is ActionLeaf:
|
|
blackboard.set_value("running_action", c, str(actor.get_instance_id()))
|
|
|
|
elif node_index == 1:
|
|
if secondary_node_repeat_count == 0 or secondary_node_repeat_left > 0:
|
|
if not secondary_node_running:
|
|
c.before_run(actor, blackboard)
|
|
var subtree_response = c.tick(actor, blackboard)
|
|
if subtree_response != RUNNING:
|
|
secondary_node_running = false
|
|
c.after_run(actor, blackboard)
|
|
if delay_mode and main_task_finished:
|
|
_reset()
|
|
return delayed_result
|
|
elif secondary_node_repeat_left > 0:
|
|
secondary_node_repeat_left -= 1
|
|
else:
|
|
secondary_node_running = true
|
|
|
|
return RUNNING
|
|
|
|
|
|
func before_run(actor: Node, blackboard: Blackboard) -> void:
|
|
secondary_node_repeat_left = secondary_node_repeat_count
|
|
super(actor, blackboard)
|
|
|
|
|
|
func interrupt(actor: Node, blackboard: Blackboard) -> void:
|
|
if not main_task_finished:
|
|
get_child(0).interrupt(actor, blackboard)
|
|
if secondary_node_running:
|
|
get_child(1).interrupt(actor, blackboard)
|
|
_reset()
|
|
super(actor, blackboard)
|
|
|
|
|
|
func after_run(actor: Node, blackboard: Blackboard) -> void:
|
|
_reset()
|
|
super(actor, blackboard)
|
|
|
|
|
|
func _reset() -> void:
|
|
main_task_finished = false
|
|
secondary_node_running = false
|
|
|
|
|
|
## Changes `running_action` and `running_child` after the node finishes executing.
|
|
func _cleanup_running_task(finished_action: Node, actor: Node, blackboard: Blackboard):
|
|
var blackboard_name = str(actor.get_instance_id())
|
|
if finished_action == running_child:
|
|
running_child = null
|
|
if finished_action == blackboard.get_value("running_action", null, blackboard_name):
|
|
blackboard.set_value("running_action", null, blackboard_name)
|
|
|
|
|
|
func get_class_name() -> Array[StringName]:
|
|
var classes := super()
|
|
classes.push_back(&"SimpleParallelComposite")
|
|
return classes
|