Merge pull request #183 from limbonaut/btplayer-allow-changing-instance

BTPlayer: Allow switching BT instance at runtime
This commit is contained in:
Serhii Snitsaruk 2024-08-04 13:16:48 +02:00 committed by GitHub
commit 8b2770116d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 128 additions and 25 deletions

View File

@ -81,6 +81,7 @@ Ref<BTInstance> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &
ERR_FAIL_COND_V_MSG(root_task == nullptr, nullptr, "BehaviorTree: Instantiation failed - BT has no valid root task."); ERR_FAIL_COND_V_MSG(root_task == nullptr, nullptr, "BehaviorTree: Instantiation failed - BT has no valid root task.");
ERR_FAIL_NULL_V_MSG(p_agent, nullptr, "BehaviorTree: Instantiation failed - agent can't be null."); ERR_FAIL_NULL_V_MSG(p_agent, nullptr, "BehaviorTree: Instantiation failed - agent can't be null.");
ERR_FAIL_NULL_V_MSG(p_instance_owner, nullptr, "BehaviorTree: Instantiation failed -- instance owner can't be null."); ERR_FAIL_NULL_V_MSG(p_instance_owner, nullptr, "BehaviorTree: Instantiation failed -- instance owner can't be null.");
ERR_FAIL_NULL_V_MSG(p_blackboard, nullptr, "BehaviorTree: Instantiation failed - blackboard can't be null.");
Node *scene_root = p_instance_owner->get_owner(); Node *scene_root = p_instance_owner->get_owner();
ERR_FAIL_NULL_V_MSG(scene_root, nullptr, "BehaviorTree: Instantiation failed - can't get scene root, because instance_owner not owned by a scene node. Hint: Try my_player.set_owner(get_owner())."); ERR_FAIL_NULL_V_MSG(scene_root, nullptr, "BehaviorTree: Instantiation failed - can't get scene root, because instance_owner not owned by a scene node. Hint: Try my_player.set_owner(get_owner()).");
Ref<BTTask> root_copy = root_task->clone(); Ref<BTTask> root_copy = root_task->clone();

View File

@ -127,6 +127,10 @@ void BTInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_owner_node"), &BTInstance::get_owner_node); ClassDB::bind_method(D_METHOD("get_owner_node"), &BTInstance::get_owner_node);
ClassDB::bind_method(D_METHOD("get_last_status"), &BTInstance::get_last_status); ClassDB::bind_method(D_METHOD("get_last_status"), &BTInstance::get_last_status);
ClassDB::bind_method(D_METHOD("get_source_bt_path"), &BTInstance::get_source_bt_path); ClassDB::bind_method(D_METHOD("get_source_bt_path"), &BTInstance::get_source_bt_path);
ClassDB::bind_method(D_METHOD("get_agent"), &BTInstance::get_agent);
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTInstance::get_blackboard);
ClassDB::bind_method(D_METHOD("is_instance_valid"), &BTInstance::is_instance_valid);
ClassDB::bind_method(D_METHOD("set_monitor_performance", "monitor"), &BTInstance::set_monitor_performance); ClassDB::bind_method(D_METHOD("set_monitor_performance", "monitor"), &BTInstance::set_monitor_performance);
ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTInstance::get_monitor_performance); ClassDB::bind_method(D_METHOD("get_monitor_performance"), &BTInstance::get_monitor_performance);

View File

@ -41,8 +41,11 @@ public:
_FORCE_INLINE_ Ref<BTTask> get_root_task() const { return root_task; } _FORCE_INLINE_ Ref<BTTask> get_root_task() const { return root_task; }
_FORCE_INLINE_ Node *get_owner_node() const { return owner_node_id ? Object::cast_to<Node>(OBJECT_DB_GET_INSTANCE(owner_node_id)) : nullptr; } _FORCE_INLINE_ Node *get_owner_node() const { return owner_node_id ? Object::cast_to<Node>(OBJECT_DB_GET_INSTANCE(owner_node_id)) : nullptr; }
_FORCE_INLINE_ BT::Status get_last_status() const { return last_status; } _FORCE_INLINE_ BT::Status get_last_status() const { return last_status; }
_FORCE_INLINE_ bool is_instance_valid() const { return root_task.is_valid(); }
_FORCE_INLINE_ String get_source_bt_path() const { return source_bt_path; } _FORCE_INLINE_ String get_source_bt_path() const { return source_bt_path; }
_FORCE_INLINE_ Node *get_agent() const { return root_task.is_valid() ? root_task->get_agent() : nullptr; }
_FORCE_INLINE_ Ref<Blackboard> get_blackboard() const { return root_task.is_valid() ? root_task->get_blackboard() : Ref<Blackboard>(); }
_FORCE_INLINE_ bool is_instance_valid() const { return root_task.is_valid(); }
BT::Status update(double p_delta); BT::Status update(double p_delta);

View File

@ -69,6 +69,18 @@ void BTPlayer::_update_blackboard_plan() {
blackboard_plan->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr); blackboard_plan->set_base_plan(behavior_tree.is_valid() ? behavior_tree->get_blackboard_plan() : nullptr);
} }
void BTPlayer::set_bt_instance(const Ref<BTInstance> &p_bt_instance) {
ERR_FAIL_COND_MSG(p_bt_instance.is_null(), "BTPlayer: Failed to set behavior tree instance - instance is null.");
ERR_FAIL_COND_MSG(!p_bt_instance->is_instance_valid(), "BTPlayer: Failed to set behavior tree instance - instance is not valid.");
bt_instance = p_bt_instance;
blackboard = p_bt_instance->get_blackboard();
agent_node = p_bt_instance->get_agent()->get_path();
blackboard_plan.unref();
behavior_tree.unref();
}
void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) { void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) { if (behavior_tree.is_valid() && behavior_tree->is_connected(LW_NAME(plan_changed), callable_mp(this, &BTPlayer::_update_blackboard_plan))) {
@ -217,6 +229,7 @@ void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart); ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart);
ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTPlayer::get_bt_instance); ClassDB::bind_method(D_METHOD("get_bt_instance"), &BTPlayer::get_bt_instance);
ClassDB::bind_method(D_METHOD("set_bt_instance", "bt_instance"), &BTPlayer::set_bt_instance);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "agent_node"), "set_agent_node", "get_agent_node"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "agent_node"), "set_agent_node", "get_agent_node");

View File

@ -77,6 +77,7 @@ public:
void restart(); void restart();
Ref<BTInstance> get_bt_instance() { return bt_instance; } Ref<BTInstance> get_bt_instance() { return bt_instance; }
void set_bt_instance(const Ref<BTInstance> &p_bt_instance);
BTPlayer(); BTPlayer();
~BTPlayer(); ~BTPlayer();

View File

@ -174,7 +174,7 @@ Returns the root task of the BehaviorTree resource.
:ref:`BTInstance<class_BTInstance>` **instantiate**\ (\ agent\: ``Node``, blackboard\: :ref:`Blackboard<class_Blackboard>`, instance_owner\: ``Node``\ ) |const| :ref:`🔗<class_BehaviorTree_method_instantiate>` :ref:`BTInstance<class_BTInstance>` **instantiate**\ (\ agent\: ``Node``, blackboard\: :ref:`Blackboard<class_Blackboard>`, instance_owner\: ``Node``\ ) |const| :ref:`🔗<class_BehaviorTree_method_instantiate>`
Instantiates the behavior tree and returns :ref:`BTInstance<class_BTInstance>`. ``instance_owner`` should be the scene node that will own the behavior tree instance. This is typically a :ref:`BTPlayer<class_BTPlayer>`, :ref:`BTState<class_BTState>`, or a custom player node that controls the behavior tree execution. Instantiates the behavior tree and returns :ref:`BTInstance<class_BTInstance>`. ``instance_owner`` should be the scene node that will own the behavior tree instance. This is typically a :ref:`BTPlayer<class_BTPlayer>`, :ref:`BTState<class_BTState>`, or a custom player node that controls the behavior tree execution. Make sure to pass a :ref:`Blackboard<class_Blackboard>` with values populated from :ref:`blackboard_plan<class_BehaviorTree_property_blackboard_plan>`. See also ``BlackboardPlan.populate_blackboard`` & ``BlackboardPlan.create_blackboard``.
.. rst-class:: classref-item-separator .. rst-class:: classref-item-separator

View File

@ -41,21 +41,27 @@ Methods
.. table:: .. table::
:widths: auto :widths: auto
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| ``Node`` | :ref:`get_agent<class_BTInstance_method_get_agent>`\ (\ ) |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------+
| :ref:`Blackboard<class_Blackboard>` | :ref:`get_blackboard<class_BTInstance_method_get_blackboard>`\ (\ ) |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------+
| :ref:`Status<enum_BT_Status>` | :ref:`get_last_status<class_BTInstance_method_get_last_status>`\ (\ ) |const| | | :ref:`Status<enum_BT_Status>` | :ref:`get_last_status<class_BTInstance_method_get_last_status>`\ (\ ) |const| |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| ``Node`` | :ref:`get_owner_node<class_BTInstance_method_get_owner_node>`\ (\ ) |const| | | ``Node`` | :ref:`get_owner_node<class_BTInstance_method_get_owner_node>`\ (\ ) |const| |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_root_task<class_BTInstance_method_get_root_task>`\ (\ ) |const| | | :ref:`BTTask<class_BTTask>` | :ref:`get_root_task<class_BTInstance_method_get_root_task>`\ (\ ) |const| |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| ``String`` | :ref:`get_source_bt_path<class_BTInstance_method_get_source_bt_path>`\ (\ ) |const| | | ``String`` | :ref:`get_source_bt_path<class_BTInstance_method_get_source_bt_path>`\ (\ ) |const| |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| ``bool`` | :ref:`is_instance_valid<class_BTInstance_method_is_instance_valid>`\ (\ ) |const| |
+-------------------------------------+-----------------------------------------------------------------------------------------+
| |void| | :ref:`register_with_debugger<class_BTInstance_method_register_with_debugger>`\ (\ ) | | |void| | :ref:`register_with_debugger<class_BTInstance_method_register_with_debugger>`\ (\ ) |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| |void| | :ref:`unregister_with_debugger<class_BTInstance_method_unregister_with_debugger>`\ (\ ) | | |void| | :ref:`unregister_with_debugger<class_BTInstance_method_unregister_with_debugger>`\ (\ ) |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
| :ref:`Status<enum_BT_Status>` | :ref:`update<class_BTInstance_method_update>`\ (\ delta\: ``float``\ ) | | :ref:`Status<enum_BT_Status>` | :ref:`update<class_BTInstance_method_update>`\ (\ delta\: ``float``\ ) |
+-------------------------------+-----------------------------------------------------------------------------------------+ +-------------------------------------+-----------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator .. rst-class:: classref-section-separator
@ -117,6 +123,30 @@ If ``true``, adds a performance monitor for this instance to "Debugger->Monitors
Method Descriptions Method Descriptions
------------------- -------------------
.. _class_BTInstance_method_get_agent:
.. rst-class:: classref-method
``Node`` **get_agent**\ (\ ) |const| :ref:`🔗<class_BTInstance_method_get_agent>`
Returns the agent of the behavior tree instance.
.. rst-class:: classref-item-separator
----
.. _class_BTInstance_method_get_blackboard:
.. rst-class:: classref-method
:ref:`Blackboard<class_Blackboard>` **get_blackboard**\ (\ ) |const| :ref:`🔗<class_BTInstance_method_get_blackboard>`
Returns the blackboard of the behavior tree instance.
.. rst-class:: classref-item-separator
----
.. _class_BTInstance_method_get_last_status: .. _class_BTInstance_method_get_last_status:
.. rst-class:: classref-method .. rst-class:: classref-method
@ -165,6 +195,18 @@ Returns the file path to the behavior tree resource that was used to create this
---- ----
.. _class_BTInstance_method_is_instance_valid:
.. rst-class:: classref-method
``bool`` **is_instance_valid**\ (\ ) |const| :ref:`🔗<class_BTInstance_method_is_instance_valid>`
Returns ``true`` if the behavior tree instance is properly initialized and can be used.
.. rst-class:: classref-item-separator
----
.. _class_BTInstance_method_register_with_debugger: .. _class_BTInstance_method_register_with_debugger:
.. rst-class:: classref-method .. rst-class:: classref-method

View File

@ -55,13 +55,15 @@ Methods
.. table:: .. table::
:widths: auto :widths: auto
+-------------------------------------+----------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTInstance<class_BTInstance>` | :ref:`get_bt_instance<class_BTPlayer_method_get_bt_instance>`\ (\ ) | | :ref:`BTInstance<class_BTInstance>` | :ref:`get_bt_instance<class_BTPlayer_method_get_bt_instance>`\ (\ ) |
+-------------------------------------+----------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`restart<class_BTPlayer_method_restart>`\ (\ ) | | |void| | :ref:`restart<class_BTPlayer_method_restart>`\ (\ ) |
+-------------------------------------+----------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`set_bt_instance<class_BTPlayer_method_set_bt_instance>`\ (\ bt_instance\: :ref:`BTInstance<class_BTInstance>`\ ) |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
| |void| | :ref:`update<class_BTPlayer_method_update>`\ (\ delta\: ``float``\ ) | | |void| | :ref:`update<class_BTPlayer_method_update>`\ (\ delta\: ``float``\ ) |
+-------------------------------------+----------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator .. rst-class:: classref-section-separator
@ -289,6 +291,18 @@ Resets the behavior tree's execution. Each running task will be aborted and the
---- ----
.. _class_BTPlayer_method_set_bt_instance:
.. rst-class:: classref-method
|void| **set_bt_instance**\ (\ bt_instance\: :ref:`BTInstance<class_BTInstance>`\ ) :ref:`🔗<class_BTPlayer_method_set_bt_instance>`
Sets the :ref:`BTInstance<class_BTInstance>` to play. This method is useful when you want to switch to a different behavior tree instance at runtime. See also :ref:`BehaviorTree.instantiate<class_BehaviorTree_property_instantiate>`.
.. rst-class:: classref-item-separator
----
.. _class_BTPlayer_method_update: .. _class_BTPlayer_method_update:
.. rst-class:: classref-method .. rst-class:: classref-method

View File

@ -9,6 +9,18 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_agent" qualifiers="const">
<return type="Node" />
<description>
Returns the agent of the behavior tree instance.
</description>
</method>
<method name="get_blackboard" qualifiers="const">
<return type="Blackboard" />
<description>
Returns the blackboard of the behavior tree instance.
</description>
</method>
<method name="get_last_status" qualifiers="const"> <method name="get_last_status" qualifiers="const">
<return type="int" enum="BT.Status" /> <return type="int" enum="BT.Status" />
<description> <description>
@ -33,6 +45,12 @@
Returns the file path to the behavior tree resource that was used to create this instance. Returns the file path to the behavior tree resource that was used to create this instance.
</description> </description>
</method> </method>
<method name="is_instance_valid" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the behavior tree instance is properly initialized and can be used.
</description>
</method>
<method name="register_with_debugger"> <method name="register_with_debugger">
<return type="void" /> <return type="void" />
<description> <description>

View File

@ -22,6 +22,13 @@
Resets the behavior tree's execution. Each running task will be aborted and the next tree execution will start anew. This method does not reset [Blackboard]. Resets the behavior tree's execution. Each running task will be aborted and the next tree execution will start anew. This method does not reset [Blackboard].
</description> </description>
</method> </method>
<method name="set_bt_instance">
<return type="void" />
<param index="0" name="bt_instance" type="BTInstance" />
<description>
Sets the [BTInstance] to play. This method is useful when you want to switch to a different behavior tree instance at runtime. See also [member BehaviorTree.instantiate].
</description>
</method>
<method name="update"> <method name="update">
<return type="void" /> <return type="void" />
<param index="0" name="delta" type="float" /> <param index="0" name="delta" type="float" />

View File

@ -40,7 +40,7 @@
<param index="1" name="blackboard" type="Blackboard" /> <param index="1" name="blackboard" type="Blackboard" />
<param index="2" name="instance_owner" type="Node" /> <param index="2" name="instance_owner" type="Node" />
<description> <description>
Instantiates the behavior tree and returns [BTInstance]. [param instance_owner] should be the scene node that will own the behavior tree instance. This is typically a [BTPlayer], [BTState], or a custom player node that controls the behavior tree execution. Instantiates the behavior tree and returns [BTInstance]. [param instance_owner] should be the scene node that will own the behavior tree instance. This is typically a [BTPlayer], [BTState], or a custom player node that controls the behavior tree execution. Make sure to pass a [Blackboard] with values populated from [member blackboard_plan]. See also [BlackboardPlan.populate_blackboard] &amp; [BlackboardPlan.create_blackboard].
</description> </description>
</method> </method>
<method name="set_root_task"> <method name="set_root_task">