diff --git a/bt/bt_player.h b/bt/bt_player.h index 8f14d31..325175c 100644 --- a/bt/bt_player.h +++ b/bt/bt_player.h @@ -43,7 +43,7 @@ private: UpdateMode update_mode = UpdateMode::PHYSICS; bool active = true; Ref blackboard; - Node *scene_root_hint; + Node *scene_root_hint = nullptr; Ref bt_instance; diff --git a/bt/bt_state.cpp b/bt/bt_state.cpp index e482e27..9a4d6c5 100644 --- a/bt/bt_state.cpp +++ b/bt/bt_state.cpp @@ -37,6 +37,13 @@ void BTState::set_behavior_tree(const Ref &p_tree) { _update_blackboard_plan(); } +void BTState::set_scene_root_hint(Node *p_scene_root) { + ERR_FAIL_NULL_MSG(p_scene_root, "BTState: Failed to set scene root hint - scene root is null."); + ERR_FAIL_COND_MSG(bt_instance.is_valid(), "BTState: Scene root hint shouldn't be set after initialization. This change will not affect the current behavior tree instance."); + + scene_root_hint = p_scene_root; +} + #ifdef DEBUG_ENABLED void BTState::_set_monitor_performance(bool p_monitor) { monitor_performance = p_monitor; @@ -61,10 +68,10 @@ void BTState::_update_blackboard_plan() { void BTState::_setup() { LimboState::_setup(); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); - Node *scene_root = get_owner(); - ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - can't get scene root (make sure the BTState's owner property is set)."); + Node *scene_root = scene_root_hint ? scene_root_hint : get_owner(); + ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - unable to establish scene root. This is likely due to BTState not being owned by a scene node. Check BTState.set_scene_root_hint()."); bt_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), this); - ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - can't instantiate behavior tree."); + ERR_FAIL_COND_MSG(bt_instance.is_null(), "BTState: Initialization failed - failed to instantiate behavior tree."); #ifdef DEBUG_ENABLED bt_instance->register_with_debugger(); @@ -137,6 +144,8 @@ void BTState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_failure_event", "event"), &BTState::set_failure_event); ClassDB::bind_method(D_METHOD("get_failure_event"), &BTState::get_failure_event); + ClassDB::bind_method(D_METHOD("set_scene_root_hint", "scene_root"), &BTState::set_scene_root_hint); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "behavior_tree", PROPERTY_HINT_RESOURCE_TYPE, "BehaviorTree"), "set_behavior_tree", "get_behavior_tree"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "success_event"), "set_success_event", "get_success_event"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "failure_event"), "set_failure_event", "get_failure_event"); diff --git a/bt/bt_state.h b/bt/bt_state.h index f601917..ed687a3 100644 --- a/bt/bt_state.h +++ b/bt/bt_state.h @@ -25,6 +25,7 @@ private: Ref bt_instance; StringName success_event; StringName failure_event; + Node *scene_root_hint = nullptr; protected: static void _bind_methods(); @@ -50,6 +51,8 @@ public: void set_failure_event(const StringName &p_failure_event) { failure_event = p_failure_event; } StringName get_failure_event() const { return failure_event; } + void set_scene_root_hint(Node *p_node); + BTState(); #ifdef DEBUG_ENABLED diff --git a/doc/source/classes/class_btstate.rst b/doc/source/classes/class_btstate.rst index c72c2a3..b9fdcef 100644 --- a/doc/source/classes/class_btstate.rst +++ b/doc/source/classes/class_btstate.rst @@ -47,9 +47,11 @@ Methods .. table:: :widths: auto - +-------------------------------------+----------------------------------------------------------------------------+ - | :ref:`BTInstance` | :ref:`get_bt_instance`\ (\ ) |const| | - +-------------------------------------+----------------------------------------------------------------------------+ + +-------------------------------------+---------------------------------------------------------------------------------------------------+ + | :ref:`BTInstance` | :ref:`get_bt_instance`\ (\ ) |const| | + +-------------------------------------+---------------------------------------------------------------------------------------------------+ + | |void| | :ref:`set_scene_root_hint`\ (\ scene_root\: ``Node``\ ) | + +-------------------------------------+---------------------------------------------------------------------------------------------------+ .. rst-class:: classref-section-separator @@ -136,6 +138,18 @@ Method Descriptions Returns the behavior tree instance. +.. rst-class:: classref-item-separator + +---- + +.. _class_BTState_method_set_scene_root_hint: + +.. rst-class:: classref-method + +|void| **set_scene_root_hint**\ (\ scene_root\: ``Node``\ ) :ref:`🔗` + +Sets the ``Node`` that will be used as the scene root for the newly instantiated behavior tree. Should be called before the state machine is initialized. This is typically useful when creating **BTState** nodes dynamically from code. + .. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)` .. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)` .. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)` diff --git a/doc_classes/BTState.xml b/doc_classes/BTState.xml index 7c72b13..d9d644d 100644 --- a/doc_classes/BTState.xml +++ b/doc_classes/BTState.xml @@ -15,6 +15,13 @@ Returns the behavior tree instance. + + + + + Sets the [Node] that will be used as the scene root for the newly instantiated behavior tree. Should be called before the state machine is initialized. This is typically useful when creating [BTState] nodes dynamically from code. + +