Updating `BTSubTree.subtree` at runtime
onze opened this issue · comments
My tree contains a BTSubTree that I want to load dynamically. In order to do this, I leave the subtree field unset, and a sibling custom node does this:
var target_subtree: BTSubtree = find_btask(
bt_player.get_tree_instance(),
my_subtree_task_name
) as BTSubtree
# assert target_subtree != null
target_subtree.subtree = null
var new_btree := ... # roughly load('res://...') as BehaviorTree
target_subtree.subtree = new_btree
In the editor, before this runs, I get the following error:
my_file.gd:95 @ <anonymous lambda>(): Subtree root task is not valid.
<C++ Error> Condition "!subtree->get_root_task().is_valid()" is true.
<C++ Source> limboai/bt/tasks/decorators/bt_subtree.cpp:33 @ initialize()
And when my code above runs, the task doesn't update properly.
As a workaround, I tried creating a dummy btree and assign it to the BTSubTree, so that the error isn't raised and the subtree can be replaced. It works until I try to set subtree
to the new BehaviorTree, which doesn't raise an issue and doesn't update it.
Is this supported?
There was a discussion some time ago: #58
It is currently not supported, as BTSubtree
is designed to be a simple loader. However, you can do it dynamically, you just need to do it without BTSubtree
, either by using a custom decorator, or by walking the tree and inserting your branch where you need it to be. Here's a simple example decorator (written from memory):
extends BTDecorator
## MyCustomBranch
func _setup() -> void:
var bt: BehaviorTree = load("res://...")
var my_branch: BTTask = bt.instantiate(agent, blackboard)
add_child(my_branch)
func _tick(delta) -> Status:
var child: BTTask = get_child(0)
return child.execute(delta)
You may or may not want to isolate the blackboard scope for your subtree like this:
var new_scope := Blackboard.new()
new_scope.set_parent(blackboard)
var my_branch: BTTask = bt.instantiate(agent, new_scope)
If your branch utilizes blackboard plan system:
# Using new scope:
var new_scope: Blackboard = bt.blackboard_plan.create_blackboard(agent)
var my_branch: BTTask = bt.instantiate(agent, new_scope)
# Or not using new scope:
bt.blackboard_plan.populate_blackboard(blackboard, false, agent)
var my_branch: BTTask = bt.instantiate(agent, blackboard)