Compare commits

...

10 Commits

Author SHA1 Message Date
Serhii Snitsaruk e55611a1a9
Bump doc version 2024-05-12 17:34:12 +02:00
Serhii Snitsaruk ba467ad62c
Merge pull request #102 from limbonaut/btplayer-agent-property
Allow specifying agent in `BTPlayer` node via inspector
2024-05-12 17:29:05 +02:00
Serhii Snitsaruk e5d04b9eda
Doc: Update doc pages and examples 2024-05-02 19:38:05 +02:00
Serhii Snitsaruk e36ea6d3e6
Better error handling in BTState, BTPlayer & BehaviorTree 2024-05-02 14:10:29 +02:00
Serhii Snitsaruk 803da63fa8
Doc: Update class docs 2024-05-02 13:39:19 +02:00
Serhii Snitsaruk 84c89356a6
Print error if agent node is set after initialization 2024-05-02 12:49:32 +02:00
Serhii Snitsaruk a2dae24b99
Rename BTPlayer's agent => agent_node 2024-05-02 12:11:59 +02:00
Serhii Snitsaruk af23272e3d
Fix unnamed arguments in method bindings 2024-05-02 01:27:14 +02:00
Serhii Snitsaruk 506d8aa967
Use `scene_root` with `BBParam` 2024-05-01 23:39:09 +02:00
Serhii Snitsaruk 5dff2e537b
Add `agent` parameter to `BTPlayer` to propagate upon `BehaviorTree` initialization, and add `scene_root` property to `BTTask`
`scene_root` is useful to resolve exported NodePath properties in `BTTask` instances (and for BBNode parameters).
2024-05-01 23:20:17 +02:00
57 changed files with 302 additions and 194 deletions

View File

@ -20,9 +20,9 @@
#include <godot_cpp/classes/node.hpp> #include <godot_cpp/classes/node.hpp>
#endif // LIMBOAI_GDEXTENSION #endif // LIMBOAI_GDEXTENSION
Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default) { Variant BBNode::get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
ERR_FAIL_COND_V(p_agent == nullptr, Variant()); ERR_FAIL_NULL_V_MSG(p_scene_root, Variant(), "BBNode: get_value() failed - scene_root is null.");
ERR_FAIL_COND_V(!p_blackboard.is_valid(), Variant()); ERR_FAIL_NULL_V_MSG(p_blackboard, Variant(), "BBNode: get_value() failed - blackboard is null.");
Variant val; Variant val;
if (get_value_source() == SAVED_VALUE) { if (get_value_source() == SAVED_VALUE) {
@ -32,9 +32,7 @@ Variant BBNode::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard,
} }
if (val.get_type() == Variant::NODE_PATH) { if (val.get_type() == Variant::NODE_PATH) {
Node *agent = Object::cast_to<Node>(p_agent); return p_scene_root->get_node_or_null(val);
ERR_FAIL_COND_V_MSG(agent == nullptr, Variant(), "BBNode: p_agent must be a Node.");
return agent->get_node_or_null(val);
} else { } else {
Object *obj = val; Object *obj = val;
if (unlikely(obj == nullptr && val.get_type() != Variant::NIL)) { if (unlikely(obj == nullptr && val.get_type() != Variant::NIL)) {

View File

@ -21,7 +21,7 @@ protected:
virtual Variant::Type get_type() const override { return Variant::NODE_PATH; } virtual Variant::Type get_type() const override { return Variant::NODE_PATH; }
public: public:
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()) override; virtual Variant get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()) override;
}; };
#endif // BB_NODE_H #endif // BB_NODE_H

View File

@ -75,7 +75,7 @@ String BBParam::_to_string() {
} }
} }
Variant BBParam::get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default) { Variant BBParam::get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default) {
ERR_FAIL_COND_V(!p_blackboard.is_valid(), p_default); ERR_FAIL_COND_V(!p_blackboard.is_valid(), p_default);
if (value_source == SAVED_VALUE) { if (value_source == SAVED_VALUE) {
@ -105,7 +105,7 @@ void BBParam::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_variable", "variable_name"), &BBParam::set_variable); ClassDB::bind_method(D_METHOD("set_variable", "variable_name"), &BBParam::set_variable);
ClassDB::bind_method(D_METHOD("get_variable"), &BBParam::get_variable); ClassDB::bind_method(D_METHOD("get_variable"), &BBParam::get_variable);
ClassDB::bind_method(D_METHOD("get_type"), &BBParam::get_type); ClassDB::bind_method(D_METHOD("get_type"), &BBParam::get_type);
ClassDB::bind_method(D_METHOD("get_value", "agent", "blackboard", "default"), &BBParam::get_value, Variant()); ClassDB::bind_method(D_METHOD("get_value", "scene_root", "blackboard", "default"), &BBParam::get_value, Variant());
ADD_PROPERTY(PropertyInfo(Variant::INT, "value_source", PROPERTY_HINT_ENUM, "Saved Value,Blackboard Var"), "set_value_source", "get_value_source"); ADD_PROPERTY(PropertyInfo(Variant::INT, "value_source", PROPERTY_HINT_ENUM, "Saved Value,Blackboard Var"), "set_value_source", "get_value_source");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable", PROPERTY_HINT_NONE, "", 0), "set_variable", "get_variable"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "variable", PROPERTY_HINT_NONE, "", 0), "set_variable", "get_variable");

View File

@ -66,7 +66,7 @@ public:
virtual String _to_string(); virtual String _to_string();
#endif #endif
virtual Variant get_value(Object *p_agent, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant()); virtual Variant get_value(Node *p_scene_root, const Ref<Blackboard> &p_blackboard, const Variant &p_default = Variant());
BBParam(); BBParam();
}; };

View File

@ -71,10 +71,12 @@ void BehaviorTree::copy_other(const Ref<BehaviorTree> &p_other) {
root_task = p_other->get_root_task(); root_task = p_other->get_root_task();
} }
Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const { Ref<BTTask> BehaviorTree::instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) const {
ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task."); ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task.");
ERR_FAIL_NULL_V_MSG(p_agent, memnew(BTTask), "Trying to instance a behavior tree with no valid agent.");
ERR_FAIL_NULL_V_MSG(p_scene_root, memnew(BTTask), "Trying to instance a behavior tree with no valid scene root.");
Ref<BTTask> inst = root_task->clone(); Ref<BTTask> inst = root_task->clone();
inst->initialize(p_agent, p_blackboard); inst->initialize(p_agent, p_blackboard, p_scene_root);
return inst; return inst;
} }
@ -92,7 +94,7 @@ void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task); ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task);
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone); ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone);
ClassDB::bind_method(D_METHOD("copy_other", "other"), &BehaviorTree::copy_other); ClassDB::bind_method(D_METHOD("copy_other", "other"), &BehaviorTree::copy_other);
ClassDB::bind_method(D_METHOD("instantiate", "agent", "blackboard"), &BehaviorTree::instantiate); ClassDB::bind_method(D_METHOD("instantiate", "agent", "blackboard", "scene_root"), &BehaviorTree::instantiate);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard_plan", PROPERTY_HINT_RESOURCE_TYPE, "BlackboardPlan", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_blackboard_plan", "get_blackboard_plan");

View File

@ -53,7 +53,7 @@ public:
Ref<BehaviorTree> clone() const; Ref<BehaviorTree> clone() const;
void copy_other(const Ref<BehaviorTree> &p_other); void copy_other(const Ref<BehaviorTree> &p_other);
Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard) const; Ref<BTTask> instantiate(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) const;
BehaviorTree(); BehaviorTree();
~BehaviorTree(); ~BehaviorTree();

View File

@ -50,9 +50,13 @@ void BTPlayer::_load_tree() {
} }
#endif #endif
tree_instance.unref(); tree_instance.unref();
ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Needs a valid behavior tree."); ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Initialization failed - needs a valid behavior tree.");
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Behavior tree has no valid root task."); ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "BTPlayer: Initialization failed - behavior tree has no valid root task.");
tree_instance = behavior_tree->instantiate(get_owner(), blackboard); Node *agent = GET_NODE(this, agent_node);
ERR_FAIL_NULL_MSG(agent, vformat("BTPlayer: Initialization failed - can't get agent with path '%s'.", agent_node));
Node *scene_root = get_owner();
ERR_FAIL_NULL_MSG(scene_root, "BTPlayer: Initialization failed - can't get scene root (make sure the BTPlayer's owner property is set).");
tree_instance = behavior_tree->instantiate(agent, blackboard, scene_root);
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (IS_DEBUGGER_ACTIVE()) { if (IS_DEBUGGER_ACTIVE()) {
LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path()); LimboDebugger::get_singleton()->register_bt_instance(tree_instance, get_path());
@ -89,6 +93,13 @@ void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
} }
} }
void BTPlayer::set_agent_node(const NodePath &p_agent_node) {
agent_node = p_agent_node;
if (tree_instance.is_valid()) {
ERR_PRINT("BTPlayer: Agent node cannot be set after the behavior tree is instantiated. This change will not affect the behavior tree instance.");
}
}
void BTPlayer::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) { void BTPlayer::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
blackboard_plan = p_plan; blackboard_plan = p_plan;
_update_blackboard_plan(); _update_blackboard_plan();
@ -228,6 +239,8 @@ void BTPlayer::_notification(int p_notification) {
void BTPlayer::_bind_methods() { void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTPlayer::set_behavior_tree); ClassDB::bind_method(D_METHOD("set_behavior_tree", "behavior_tree"), &BTPlayer::set_behavior_tree);
ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTPlayer::get_behavior_tree); ClassDB::bind_method(D_METHOD("get_behavior_tree"), &BTPlayer::get_behavior_tree);
ClassDB::bind_method(D_METHOD("set_agent_node", "agent_node"), &BTPlayer::set_agent_node);
ClassDB::bind_method(D_METHOD("get_agent_node"), &BTPlayer::get_agent_node);
ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &BTPlayer::set_update_mode); ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &BTPlayer::set_update_mode);
ClassDB::bind_method(D_METHOD("get_update_mode"), &BTPlayer::get_update_mode); ClassDB::bind_method(D_METHOD("get_update_mode"), &BTPlayer::get_update_mode);
ClassDB::bind_method(D_METHOD("set_active", "active"), &BTPlayer::set_active); ClassDB::bind_method(D_METHOD("set_active", "active"), &BTPlayer::set_active);
@ -245,6 +258,7 @@ void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tree_instance"), &BTPlayer::get_tree_instance); ClassDB::bind_method(D_METHOD("get_tree_instance"), &BTPlayer::get_tree_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::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Idle,Physics,Manual"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "get_active"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "get_active");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "set_blackboard", "get_blackboard"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "set_blackboard", "get_blackboard");
@ -266,6 +280,7 @@ void BTPlayer::_bind_methods() {
BTPlayer::BTPlayer() { BTPlayer::BTPlayer() {
blackboard = Ref<Blackboard>(memnew(Blackboard)); blackboard = Ref<Blackboard>(memnew(Blackboard));
agent_node = LW_NAME(node_pp);
} }
BTPlayer::~BTPlayer() { BTPlayer::~BTPlayer() {

View File

@ -37,6 +37,7 @@ public:
private: private:
Ref<BehaviorTree> behavior_tree; Ref<BehaviorTree> behavior_tree;
NodePath agent_node;
Ref<BlackboardPlan> blackboard_plan; Ref<BlackboardPlan> blackboard_plan;
UpdateMode update_mode = UpdateMode::PHYSICS; UpdateMode update_mode = UpdateMode::PHYSICS;
bool active = true; bool active = true;
@ -57,6 +58,9 @@ public:
void set_behavior_tree(const Ref<BehaviorTree> &p_tree); void set_behavior_tree(const Ref<BehaviorTree> &p_tree);
Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; }; Ref<BehaviorTree> get_behavior_tree() const { return behavior_tree; };
void set_agent_node(const NodePath &p_agent_node);
NodePath get_agent_node() const { return agent_node; }
void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan); void set_blackboard_plan(const Ref<BlackboardPlan> &p_plan);
Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; } Ref<BlackboardPlan> get_blackboard_plan() const { return blackboard_plan; }

View File

@ -52,8 +52,9 @@ void BTState::_update_blackboard_plan() {
void BTState::_setup() { void BTState::_setup() {
LimboState::_setup(); LimboState::_setup();
ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned."); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
// TODO: BBNode relies on agent to be scene owner, so if the user provides anything else, the behavior tree can break. Node *scene_root = get_owner();
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard()); ERR_FAIL_NULL_MSG(scene_root, "BTState: Initialization failed - can't get scene root (make sure the BTState's owner property is set).");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard(), scene_root);
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) { if (tree_instance.is_valid() && IS_DEBUGGER_ACTIVE()) {

View File

@ -57,7 +57,7 @@ BT::Status BTCheckVar::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(!get_blackboard()->has_var(variable), FAILURE, vformat("BTCheckVar: Blackboard variable doesn't exist: \"%s\". Returning FAILURE.", variable)); ERR_FAIL_COND_V_MSG(!get_blackboard()->has_var(variable), FAILURE, vformat("BTCheckVar: Blackboard variable doesn't exist: \"%s\". Returning FAILURE.", variable));
Variant left_value = get_blackboard()->get_var(variable, Variant()); Variant left_value = get_blackboard()->get_var(variable, Variant());
Variant right_value = value->get_value(get_agent(), get_blackboard()); Variant right_value = value->get_value(get_scene_root(), get_blackboard());
return LimboUtility::get_singleton()->perform_check(check_type, left_value, right_value) ? SUCCESS : FAILURE; return LimboUtility::get_singleton()->perform_check(check_type, left_value, right_value) ? SUCCESS : FAILURE;
} }

View File

@ -26,7 +26,7 @@ BT::Status BTSetVar::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetVar: `value` is not set."); ERR_FAIL_COND_V_MSG(!value.is_valid(), FAILURE, "BTSetVar: `value` is not set.");
Variant result; Variant result;
Variant error_result = LW_NAME(error_value); Variant error_result = LW_NAME(error_value);
Variant right_value = value->get_value(get_agent(), get_blackboard(), error_result); Variant right_value = value->get_value(get_scene_root(), get_blackboard(), error_result);
ERR_FAIL_COND_V_MSG(right_value == error_result, FAILURE, "BTSetVar: Failed to get parameter value. Returning FAILURE."); ERR_FAIL_COND_V_MSG(right_value == error_result, FAILURE, "BTSetVar: Failed to get parameter value. Returning FAILURE.");
if (operation == LimboUtility::OPERATION_NONE) { if (operation == LimboUtility::OPERATION_NONE) {
result = right_value; result = right_value;

View File

@ -159,13 +159,15 @@ void BTTask::set_custom_name(const String &p_name) {
} }
}; };
void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) { void BTTask::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) {
ERR_FAIL_COND(p_agent == nullptr); ERR_FAIL_NULL(p_agent);
ERR_FAIL_COND(p_blackboard == nullptr); ERR_FAIL_NULL(p_blackboard);
ERR_FAIL_NULL(p_scene_root);
data.agent = p_agent; data.agent = p_agent;
data.blackboard = p_blackboard; data.blackboard = p_blackboard;
data.scene_root = p_scene_root;
for (int i = 0; i < data.children.size(); i++) { for (int i = 0; i < data.children.size(); i++) {
get_child(i)->initialize(p_agent, p_blackboard); get_child(i)->initialize(p_agent, p_blackboard, p_scene_root);
} }
VCALL_OR_NATIVE(_setup); VCALL_OR_NATIVE(_setup);
@ -378,7 +380,7 @@ void BTTask::_bind_methods() {
// Public Methods. // Public Methods.
ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root); ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root);
ClassDB::bind_method(D_METHOD("get_root"), &BTTask::get_root); ClassDB::bind_method(D_METHOD("get_root"), &BTTask::get_root);
ClassDB::bind_method(D_METHOD("initialize", "agent", "blackboard"), &BTTask::initialize); ClassDB::bind_method(D_METHOD("initialize", "agent", "blackboard", "scene_root"), &BTTask::initialize);
ClassDB::bind_method(D_METHOD("clone"), &BTTask::clone); ClassDB::bind_method(D_METHOD("clone"), &BTTask::clone);
ClassDB::bind_method(D_METHOD("execute", "delta"), &BTTask::execute); ClassDB::bind_method(D_METHOD("execute", "delta"), &BTTask::execute);
ClassDB::bind_method(D_METHOD("get_child", "idx"), &BTTask::get_child); ClassDB::bind_method(D_METHOD("get_child", "idx"), &BTTask::get_child);
@ -399,6 +401,7 @@ void BTTask::_bind_methods() {
// Properties, setters and getters. // Properties, setters and getters.
ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent); ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent);
ClassDB::bind_method(D_METHOD("set_agent", "agent"), &BTTask::set_agent); ClassDB::bind_method(D_METHOD("set_agent", "agent"), &BTTask::set_agent);
ClassDB::bind_method(D_METHOD("get_scene_root"), &BTTask::get_scene_root);
ClassDB::bind_method(D_METHOD("_get_children"), &BTTask::_get_children); ClassDB::bind_method(D_METHOD("_get_children"), &BTTask::_get_children);
ClassDB::bind_method(D_METHOD("_set_children", "children"), &BTTask::_set_children); ClassDB::bind_method(D_METHOD("_set_children", "children"), &BTTask::_set_children);
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTTask::get_blackboard); ClassDB::bind_method(D_METHOD("get_blackboard"), &BTTask::get_blackboard);
@ -410,6 +413,7 @@ void BTTask::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_custom_name"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_custom_name");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_agent", "get_agent"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_agent", "get_agent");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_NODE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_scene_root");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_RESOURCE_TYPE, "Blackboard", PROPERTY_USAGE_NONE), "", "get_blackboard");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_children", "_get_children"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_children", "_get_children");
ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status"); ADD_PROPERTY(PropertyInfo(Variant::INT, "status", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_status");

View File

@ -75,6 +75,7 @@ private:
int index = -1; int index = -1;
String custom_name; String custom_name;
Node *agent = nullptr; Node *agent = nullptr;
Node *scene_root = nullptr;
Ref<Blackboard> blackboard; Ref<Blackboard> blackboard;
BTTask *parent = nullptr; BTTask *parent = nullptr;
Vector<Ref<BTTask>> children; Vector<Ref<BTTask>> children;
@ -116,6 +117,8 @@ public:
_FORCE_INLINE_ Node *get_agent() const { return data.agent; } _FORCE_INLINE_ Node *get_agent() const { return data.agent; }
void set_agent(Node *p_agent) { data.agent = p_agent; } void set_agent(Node *p_agent) { data.agent = p_agent; }
_FORCE_INLINE_ Node *get_scene_root() const { return data.scene_root; }
void set_display_collapsed(bool p_display_collapsed); void set_display_collapsed(bool p_display_collapsed);
bool is_displayed_collapsed() const; bool is_displayed_collapsed() const;
@ -126,7 +129,7 @@ public:
Ref<BTTask> get_root() const; Ref<BTTask> get_root() const;
virtual Ref<BTTask> clone() const; virtual Ref<BTTask> clone() const;
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard); virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root);
virtual PackedStringArray get_configuration_warnings(); // ! Native version. virtual PackedStringArray get_configuration_warnings(); // ! Native version.
Status execute(double p_delta); Status execute(double p_delta);

View File

@ -20,7 +20,7 @@ void BTNewScope::set_blackboard_plan(const Ref<BlackboardPlan> &p_plan) {
emit_changed(); emit_changed();
} }
void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) { void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) {
ERR_FAIL_COND(p_agent == nullptr); ERR_FAIL_COND(p_agent == nullptr);
ERR_FAIL_COND(p_blackboard == nullptr); ERR_FAIL_COND(p_blackboard == nullptr);
@ -33,7 +33,7 @@ void BTNewScope::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard)
bb->set_parent(p_blackboard); bb->set_parent(p_blackboard);
BTDecorator::initialize(p_agent, bb); BTDecorator::initialize(p_agent, bb, p_scene_root);
} }
BT::Status BTNewScope::_tick(double p_delta) { BT::Status BTNewScope::_tick(double p_delta) {

View File

@ -34,7 +34,7 @@ protected:
virtual Status _tick(double p_delta) override; virtual Status _tick(double p_delta) override;
public: public:
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) override; virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) override;
}; };
#endif // BT_NEW_SCOPE_H #endif // BT_NEW_SCOPE_H

View File

@ -44,14 +44,14 @@ String BTSubtree::_generate_name() {
return vformat("Subtree %s", s); return vformat("Subtree %s", s);
} }
void BTSubtree::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) { void BTSubtree::initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) {
ERR_FAIL_COND_MSG(!subtree.is_valid(), "Subtree is not assigned."); ERR_FAIL_COND_MSG(!subtree.is_valid(), "Subtree is not assigned.");
ERR_FAIL_COND_MSG(!subtree->get_root_task().is_valid(), "Subtree root task is not valid."); ERR_FAIL_COND_MSG(!subtree->get_root_task().is_valid(), "Subtree root task is not valid.");
ERR_FAIL_COND_MSG(get_child_count() != 0, "Subtree task shouldn't have children during initialization."); ERR_FAIL_COND_MSG(get_child_count() != 0, "Subtree task shouldn't have children during initialization.");
add_child(subtree->get_root_task()->clone()); add_child(subtree->get_root_task()->clone());
BTNewScope::initialize(p_agent, p_blackboard); BTNewScope::initialize(p_agent, p_blackboard, p_scene_root);
} }
BT::Status BTSubtree::_tick(double p_delta) { BT::Status BTSubtree::_tick(double p_delta) {

View File

@ -35,7 +35,7 @@ public:
void set_subtree(const Ref<BehaviorTree> &p_value); void set_subtree(const Ref<BehaviorTree> &p_value);
Ref<BehaviorTree> get_subtree() const { return subtree; } Ref<BehaviorTree> get_subtree() const { return subtree; }
virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard) override; virtual void initialize(Node *p_agent, const Ref<Blackboard> &p_blackboard, Node *p_scene_root) override;
virtual PackedStringArray get_configuration_warnings() override; virtual PackedStringArray get_configuration_warnings() override;
BTSubtree() = default; BTSubtree() = default;

View File

@ -62,7 +62,7 @@ String BTAwaitAnimation::_generate_name() {
void BTAwaitAnimation::_setup() { void BTAwaitAnimation::_setup() {
setup_failed = true; setup_failed = true;
ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTAwaitAnimation: AnimationPlayer parameter is not set."); ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTAwaitAnimation: AnimationPlayer parameter is not set.");
animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_agent(), get_blackboard())); animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_scene_root(), get_blackboard()));
ERR_FAIL_COND_MSG(animation_player == nullptr, "BTAwaitAnimation: Failed to get AnimationPlayer."); ERR_FAIL_COND_MSG(animation_player == nullptr, "BTAwaitAnimation: Failed to get AnimationPlayer.");
ERR_FAIL_COND_MSG(animation_name == StringName(), "BTAwaitAnimation: Animation Name is not set."); ERR_FAIL_COND_MSG(animation_name == StringName(), "BTAwaitAnimation: Animation Name is not set.");
ERR_FAIL_COND_MSG(!animation_player->has_animation(animation_name), vformat("BTAwaitAnimation: Animation not found: %s", animation_name)); ERR_FAIL_COND_MSG(!animation_player->has_animation(animation_name), vformat("BTAwaitAnimation: Animation not found: %s", animation_name));

View File

@ -62,7 +62,7 @@ BT::Status BTCheckAgentProperty::_tick(double p_delta) {
Variant left_value = get_agent()->get(property); Variant left_value = get_agent()->get(property);
#endif #endif
Variant right_value = value->get_value(get_agent(), get_blackboard()); Variant right_value = value->get_value(get_scene_root(), get_blackboard());
return LimboUtility::get_singleton()->perform_check(check_type, left_value, right_value) ? SUCCESS : FAILURE; return LimboUtility::get_singleton()->perform_check(check_type, left_value, right_value) ? SUCCESS : FAILURE;
} }

View File

@ -44,7 +44,7 @@ String BTPauseAnimation::_generate_name() {
void BTPauseAnimation::_setup() { void BTPauseAnimation::_setup() {
setup_failed = true; setup_failed = true;
ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTPauseAnimation: AnimationPlayer parameter is not set."); ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTPauseAnimation: AnimationPlayer parameter is not set.");
animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_agent(), get_blackboard())); animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_scene_root(), get_blackboard()));
ERR_FAIL_COND_MSG(animation_player == nullptr, "BTPauseAnimation: Failed to get AnimationPlayer."); ERR_FAIL_COND_MSG(animation_player == nullptr, "BTPauseAnimation: Failed to get AnimationPlayer.");
setup_failed = false; setup_failed = false;
} }

View File

@ -77,7 +77,7 @@ String BTPlayAnimation::_generate_name() {
void BTPlayAnimation::_setup() { void BTPlayAnimation::_setup() {
setup_failed = true; setup_failed = true;
ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTPlayAnimation: AnimationPlayer parameter is not set."); ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTPlayAnimation: AnimationPlayer parameter is not set.");
animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_agent(), get_blackboard())); animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_scene_root(), get_blackboard()));
ERR_FAIL_COND_MSG(animation_player == nullptr, "BTPlayAnimation: Failed to get AnimationPlayer."); ERR_FAIL_COND_MSG(animation_player == nullptr, "BTPlayAnimation: Failed to get AnimationPlayer.");
ERR_FAIL_COND_MSG(animation_name != StringName() && !animation_player->has_animation(animation_name), vformat("BTPlayAnimation: Animation not found: %s", animation_name)); ERR_FAIL_COND_MSG(animation_name != StringName() && !animation_player->has_animation(animation_name), vformat("BTPlayAnimation: Animation not found: %s", animation_name));
if (animation_name == StringName() && await_completion > 0.0) { if (animation_name == StringName() && await_completion > 0.0) {

View File

@ -55,7 +55,7 @@ BT::Status BTSetAgentProperty::_tick(double p_delta) {
Variant result; Variant result;
StringName error_value = LW_NAME(error_value); StringName error_value = LW_NAME(error_value);
Variant right_value = value->get_value(get_agent(), get_blackboard(), error_value); Variant right_value = value->get_value(get_scene_root(), get_blackboard(), error_value);
ERR_FAIL_COND_V_MSG(right_value == Variant(error_value), FAILURE, "BTSetAgentProperty: Couldn't get value of value-parameter."); ERR_FAIL_COND_V_MSG(right_value == Variant(error_value), FAILURE, "BTSetAgentProperty: Couldn't get value of value-parameter.");
bool r_valid; bool r_valid;
if (operation == LimboUtility::OPERATION_NONE) { if (operation == LimboUtility::OPERATION_NONE) {

View File

@ -56,7 +56,7 @@ String BTStopAnimation::_generate_name() {
void BTStopAnimation::_setup() { void BTStopAnimation::_setup() {
setup_failed = true; setup_failed = true;
ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTStopAnimation: AnimationPlayer parameter is not set."); ERR_FAIL_COND_MSG(animation_player_param.is_null(), "BTStopAnimation: AnimationPlayer parameter is not set.");
animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_agent(), get_blackboard())); animation_player = Object::cast_to<AnimationPlayer>(animation_player_param->get_value(get_scene_root(), get_blackboard()));
ERR_FAIL_COND_MSG(animation_player == nullptr, "BTStopAnimation: Failed to get AnimationPlayer."); ERR_FAIL_COND_MSG(animation_player == nullptr, "BTStopAnimation: Failed to get AnimationPlayer.");
if (animation_name != StringName()) { if (animation_name != StringName()) {
ERR_FAIL_COND_MSG(!animation_player->has_animation(animation_name), vformat("BTStopAnimation: Animation not found: %s", animation_name)); ERR_FAIL_COND_MSG(!animation_player->has_animation(animation_name), vformat("BTStopAnimation: Animation not found: %s", animation_name));

View File

@ -83,7 +83,7 @@ String BTCallMethod::_generate_name() {
BT::Status BTCallMethod::_tick(double p_delta) { BT::Status BTCallMethod::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(method == StringName(), FAILURE, "BTCallMethod: Method Name is not set."); ERR_FAIL_COND_V_MSG(method == StringName(), FAILURE, "BTCallMethod: Method Name is not set.");
ERR_FAIL_COND_V_MSG(node_param.is_null(), FAILURE, "BTCallMethod: Node parameter is not set."); ERR_FAIL_COND_V_MSG(node_param.is_null(), FAILURE, "BTCallMethod: Node parameter is not set.");
Object *obj = node_param->get_value(get_agent(), get_blackboard()); Object *obj = node_param->get_value(get_scene_root(), get_blackboard());
ERR_FAIL_COND_V_MSG(obj == nullptr, FAILURE, "BTCallMethod: Failed to get object: " + node_param->to_string()); ERR_FAIL_COND_V_MSG(obj == nullptr, FAILURE, "BTCallMethod: Failed to get object: " + node_param->to_string());
Variant result; Variant result;
@ -101,7 +101,7 @@ BT::Status BTCallMethod::_tick(double p_delta) {
} }
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
Ref<BBVariant> param = args[i]; Ref<BBVariant> param = args[i];
call_args.push_back(param->get_value(get_agent(), get_blackboard())); call_args.push_back(param->get_value(get_scene_root(), get_blackboard()));
argptrs[i + int(include_delta)] = &call_args[i]; argptrs[i + int(include_delta)] = &call_args[i];
} }
} }
@ -117,7 +117,7 @@ BT::Status BTCallMethod::_tick(double p_delta) {
} }
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
Ref<BBVariant> param = args[i]; Ref<BBVariant> param = args[i];
call_args.push_back(param->get_value(get_agent(), get_blackboard())); call_args.push_back(param->get_value(get_scene_root(), get_blackboard()));
} }
// TODO: Unsure how to detect call error, so we return SUCCESS for now... // TODO: Unsure how to detect call error, so we return SUCCESS for now...

View File

@ -107,7 +107,7 @@ String BTEvaluateExpression::_generate_name() {
BT::Status BTEvaluateExpression::_tick(double p_delta) { BT::Status BTEvaluateExpression::_tick(double p_delta) {
ERR_FAIL_COND_V_MSG(expression_string.is_empty(), FAILURE, "BTEvaluateExpression: Expression String is not set."); ERR_FAIL_COND_V_MSG(expression_string.is_empty(), FAILURE, "BTEvaluateExpression: Expression String is not set.");
ERR_FAIL_COND_V_MSG(node_param.is_null(), FAILURE, "BTEvaluateExpression: Node parameter is not set."); ERR_FAIL_COND_V_MSG(node_param.is_null(), FAILURE, "BTEvaluateExpression: Node parameter is not set.");
Object *obj = node_param->get_value(get_agent(), get_blackboard()); Object *obj = node_param->get_value(get_scene_root(), get_blackboard());
ERR_FAIL_COND_V_MSG(obj == nullptr, FAILURE, "BTEvaluateExpression: Failed to get object: " + node_param->to_string()); ERR_FAIL_COND_V_MSG(obj == nullptr, FAILURE, "BTEvaluateExpression: Failed to get object: " + node_param->to_string());
ERR_FAIL_COND_V_MSG(is_parsed != Error::OK, FAILURE, "BTEvaluateExpression: Failed to parse expression: " + expression.get_error_text()); ERR_FAIL_COND_V_MSG(is_parsed != Error::OK, FAILURE, "BTEvaluateExpression: Failed to parse expression: " + expression.get_error_text());
@ -116,7 +116,7 @@ BT::Status BTEvaluateExpression::_tick(double p_delta) {
} }
for (int i = 0; i < input_values.size(); ++i) { for (int i = 0; i < input_values.size(); ++i) {
const Ref<BBVariant> &bb_variant = input_values[i]; const Ref<BBVariant> &bb_variant = input_values[i];
processed_input_values[i + int(input_include_delta)] = bb_variant->get_value(get_agent(), get_blackboard()); processed_input_values[i + int(input_include_delta)] = bb_variant->get_value(get_scene_root(), get_blackboard());
} }
Variant result = expression.execute(processed_input_values, obj, false); Variant result = expression.execute(processed_input_values, obj, false);

View File

@ -49,11 +49,11 @@ Methods
.. table:: .. table::
:widths: auto :widths: auto
+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Variant.Type<enum_@GlobalScope_Variant.Type>` | :ref:`get_type<class_BBParam_method_get_type>` **(** **)** |const| | | :ref:`Variant.Type<enum_@GlobalScope_Variant.Type>` | :ref:`get_type<class_BBParam_method_get_type>` **(** **)** |const| |
+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| Variant | :ref:`get_value<class_BBParam_method_get_value>` **(** Object agent, :ref:`Blackboard<class_Blackboard>` blackboard, Variant default=null **)** | | Variant | :ref:`get_value<class_BBParam_method_get_value>` **(** Node scene_root, :ref:`Blackboard<class_Blackboard>` blackboard, Variant default=null **)** |
+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator .. rst-class:: classref-section-separator
@ -167,7 +167,7 @@ Returns the expected data type of the parameter.
.. rst-class:: classref-method .. rst-class:: classref-method
Variant **get_value** **(** Object agent, :ref:`Blackboard<class_Blackboard>` blackboard, Variant default=null **)** Variant **get_value** **(** Node scene_root, :ref:`Blackboard<class_Blackboard>` blackboard, Variant default=null **)**
Returns the value of the parameter. Returns the value of the parameter.

View File

@ -55,17 +55,17 @@ Methods
.. table:: .. table::
:widths: auto :widths: auto
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BehaviorTree<class_BehaviorTree>` | :ref:`clone<class_BehaviorTree_method_clone>` **(** **)** |const| | | :ref:`BehaviorTree<class_BehaviorTree>` | :ref:`clone<class_BehaviorTree_method_clone>` **(** **)** |const| |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`copy_other<class_BehaviorTree_method_copy_other>` **(** :ref:`BehaviorTree<class_BehaviorTree>` other **)** | | void | :ref:`copy_other<class_BehaviorTree_method_copy_other>` **(** :ref:`BehaviorTree<class_BehaviorTree>` other **)** |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_root_task<class_BehaviorTree_method_get_root_task>` **(** **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`get_root_task<class_BehaviorTree_method_get_root_task>` **(** **)** |const| |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`instantiate<class_BehaviorTree_method_instantiate>` **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`instantiate<class_BehaviorTree_method_instantiate>` **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard, Node scene_root **)** |const| |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`set_root_task<class_BehaviorTree_method_set_root_task>` **(** :ref:`BTTask<class_BTTask>` task **)** | | void | :ref:`set_root_task<class_BehaviorTree_method_set_root_task>` **(** :ref:`BTTask<class_BTTask>` task **)** |
+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator .. rst-class:: classref-section-separator
@ -172,9 +172,9 @@ Returns the root task of the BehaviorTree resource.
.. rst-class:: classref-method .. rst-class:: classref-method
:ref:`BTTask<class_BTTask>` **instantiate** **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard **)** |const| :ref:`BTTask<class_BTTask>` **instantiate** **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard, Node scene_root **)** |const|
Instantiates the Behavior Tree and returns the root :ref:`BTTask<class_BTTask>`. Instantiates the behavior tree and returns the root :ref:`BTTask<class_BTTask>`. ``scene_root`` should be the root node of the scene that the Behavior Tree will be used in (e.g., the owner of the node that contains the behavior tree).
.. rst-class:: classref-item-separator .. rst-class:: classref-item-separator

View File

@ -33,27 +33,27 @@ Methods
.. table:: .. table::
:widths: auto :widths: auto
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`bind_var_to_property<class_Blackboard_method_bind_var_to_property>` **(** StringName var_name, Object object, StringName property, bool create **)** | | void | :ref:`bind_var_to_property<class_Blackboard_method_bind_var_to_property>` **(** StringName var_name, Object object, StringName property, bool create=false **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`erase_var<class_Blackboard_method_erase_var>` **(** StringName var_name **)** | | void | :ref:`erase_var<class_Blackboard_method_erase_var>` **(** StringName var_name **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Blackboard<class_Blackboard>` | :ref:`get_parent<class_Blackboard_method_get_parent>` **(** **)** |const| | | :ref:`Blackboard<class_Blackboard>` | :ref:`get_parent<class_Blackboard_method_get_parent>` **(** **)** |const| |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Variant | :ref:`get_var<class_Blackboard_method_get_var>` **(** StringName var_name, Variant default=null, bool complain=true **)** |const| | | Variant | :ref:`get_var<class_Blackboard_method_get_var>` **(** StringName var_name, Variant default=null, bool complain=true **)** |const| |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| bool | :ref:`has_var<class_Blackboard_method_has_var>` **(** StringName var_name **)** |const| | | bool | :ref:`has_var<class_Blackboard_method_has_var>` **(** StringName var_name **)** |const| |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`link_var<class_Blackboard_method_link_var>` **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var, bool create **)** | | void | :ref:`link_var<class_Blackboard_method_link_var>` **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var, bool create=false **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`set_parent<class_Blackboard_method_set_parent>` **(** :ref:`Blackboard<class_Blackboard>` blackboard **)** | | void | :ref:`set_parent<class_Blackboard_method_set_parent>` **(** :ref:`Blackboard<class_Blackboard>` blackboard **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`set_var<class_Blackboard_method_set_var>` **(** StringName var_name, Variant value **)** | | void | :ref:`set_var<class_Blackboard_method_set_var>` **(** StringName var_name, Variant value **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Blackboard<class_Blackboard>` | :ref:`top<class_Blackboard_method_top>` **(** **)** |const| | | :ref:`Blackboard<class_Blackboard>` | :ref:`top<class_Blackboard_method_top>` **(** **)** |const| |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`unbind_var<class_Blackboard_method_unbind_var>` **(** StringName var_name **)** | | void | :ref:`unbind_var<class_Blackboard_method_unbind_var>` **(** StringName var_name **)** |
+-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator .. rst-class:: classref-section-separator
@ -68,7 +68,7 @@ Method Descriptions
.. rst-class:: classref-method .. rst-class:: classref-method
void **bind_var_to_property** **(** StringName var_name, Object object, StringName property, bool create **)** void **bind_var_to_property** **(** StringName var_name, Object object, StringName property, bool create=false **)**
Establish a binding between a variable and the object's property specified by ``property`` and ``object``. Changes to the variable update the property, and vice versa. If ``create`` is ``true``, the variable will be created if it doesn't exist. Establish a binding between a variable and the object's property specified by ``property`` and ``object``. Changes to the variable update the property, and vice versa. If ``create`` is ``true``, the variable will be created if it doesn't exist.
@ -128,7 +128,7 @@ Returns ``true`` if the Blackboard contains the ``var_name`` variable, including
.. rst-class:: classref-method .. rst-class:: classref-method
void **link_var** **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var, bool create **)** void **link_var** **(** StringName var_name, :ref:`Blackboard<class_Blackboard>` target_blackboard, StringName target_var, bool create=false **)**
Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. If ``create`` is ``true``, the variable will be created if it doesn't exist. Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. If ``create`` is ``true``, the variable will be created if it doesn't exist.

View File

@ -19,7 +19,7 @@ Player of :ref:`BehaviorTree<class_BehaviorTree>` resources.
Description Description
----------- -----------
BTPlayer node is used for the instantiation and playback of :ref:`BehaviorTree<class_BehaviorTree>` resources at runtime. During instantiation, the behavior tree instance is initialized with a reference to the agent and the :ref:`blackboard<class_BTPlayer_property_blackboard>`. Agent is the owner of the BTPlayer node (see :ref:`Node.owner<class_Node_member_owner>`). **BTPlayer** node is used to instantiate and play :ref:`BehaviorTree<class_BehaviorTree>` resources at runtime. During initialization, the behavior tree instance is given references to the agent, the :ref:`blackboard<class_BTPlayer_property_blackboard>`, and the current scene root. The agent can be specified by the :ref:`agent_node<class_BTPlayer_property_agent_node>` property (defaults to the BTPlayer's parent node).
For an introduction to behavior trees, see :ref:`BehaviorTree<class_BehaviorTree>`. For an introduction to behavior trees, see :ref:`BehaviorTree<class_BehaviorTree>`.
@ -31,19 +31,21 @@ Properties
.. table:: .. table::
:widths: auto :widths: auto
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| bool | :ref:`active<class_BTPlayer_property_active>` | ``true`` | | bool | :ref:`active<class_BTPlayer_property_active>` | ``true`` |
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| NodePath | :ref:`agent_node<class_BTPlayer_property_agent_node>` | ``NodePath("..")`` |
+---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| :ref:`BehaviorTree<class_BehaviorTree>` | :ref:`behavior_tree<class_BTPlayer_property_behavior_tree>` | | | :ref:`BehaviorTree<class_BehaviorTree>` | :ref:`behavior_tree<class_BTPlayer_property_behavior_tree>` | |
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| :ref:`Blackboard<class_Blackboard>` | :ref:`blackboard<class_BTPlayer_property_blackboard>` | | | :ref:`Blackboard<class_Blackboard>` | :ref:`blackboard<class_BTPlayer_property_blackboard>` | |
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| :ref:`BlackboardPlan<class_BlackboardPlan>` | :ref:`blackboard_plan<class_BTPlayer_property_blackboard_plan>` | | | :ref:`BlackboardPlan<class_BlackboardPlan>` | :ref:`blackboard_plan<class_BTPlayer_property_blackboard_plan>` | |
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| bool | :ref:`monitor_performance<class_BTPlayer_property_monitor_performance>` | ``false`` | | bool | :ref:`monitor_performance<class_BTPlayer_property_monitor_performance>` | ``false`` |
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
| :ref:`UpdateMode<enum_BTPlayer_UpdateMode>` | :ref:`update_mode<class_BTPlayer_property_update_mode>` | ``1`` | | :ref:`UpdateMode<enum_BTPlayer_UpdateMode>` | :ref:`update_mode<class_BTPlayer_property_update_mode>` | ``1`` |
+---------------------------------------------+-------------------------------------------------------------------------+-----------+ +---------------------------------------------+-------------------------------------------------------------------------+--------------------+
.. rst-class:: classref-reftable-group .. rst-class:: classref-reftable-group
@ -161,6 +163,23 @@ If ``true``, the behavior tree will be executed during update.
---- ----
.. _class_BTPlayer_property_agent_node:
.. rst-class:: classref-property
NodePath **agent_node** = ``NodePath("..")``
.. rst-class:: classref-property-setget
- void **set_agent_node** **(** NodePath value **)**
- NodePath **get_agent_node** **(** **)**
Path to the node that will be used as the agent. Setting it after instantiation will have no effect.
.. rst-class:: classref-item-separator
----
.. _class_BTPlayer_property_behavior_tree: .. _class_BTPlayer_property_behavior_tree:
.. rst-class:: classref-property .. rst-class:: classref-property

View File

@ -46,6 +46,8 @@ Properties
+-------------------------------------+---------------------------------------------------------+--------+ +-------------------------------------+---------------------------------------------------------+--------+
| float | :ref:`elapsed_time<class_BTTask_property_elapsed_time>` | | | float | :ref:`elapsed_time<class_BTTask_property_elapsed_time>` | |
+-------------------------------------+---------------------------------------------------------+--------+ +-------------------------------------+---------------------------------------------------------+--------+
| Node | :ref:`scene_root<class_BTTask_property_scene_root>` | |
+-------------------------------------+---------------------------------------------------------+--------+
| :ref:`Status<enum_BT_Status>` | :ref:`status<class_BTTask_property_status>` | | | :ref:`Status<enum_BT_Status>` | :ref:`status<class_BTTask_property_status>` | |
+-------------------------------------+---------------------------------------------------------+--------+ +-------------------------------------+---------------------------------------------------------+--------+
@ -57,59 +59,59 @@ Methods
.. table:: .. table::
:widths: auto :widths: auto
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`_enter<class_BTTask_private_method__enter>` **(** **)** |virtual| | | void | :ref:`_enter<class_BTTask_private_method__enter>` **(** **)** |virtual| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`_exit<class_BTTask_private_method__exit>` **(** **)** |virtual| | | void | :ref:`_exit<class_BTTask_private_method__exit>` **(** **)** |virtual| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| String | :ref:`_generate_name<class_BTTask_private_method__generate_name>` **(** **)** |virtual| |const| | | String | :ref:`_generate_name<class_BTTask_private_method__generate_name>` **(** **)** |virtual| |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| PackedStringArray | :ref:`_get_configuration_warnings<class_BTTask_private_method__get_configuration_warnings>` **(** **)** |virtual| |const| | | PackedStringArray | :ref:`_get_configuration_warnings<class_BTTask_private_method__get_configuration_warnings>` **(** **)** |virtual| |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`_setup<class_BTTask_private_method__setup>` **(** **)** |virtual| | | void | :ref:`_setup<class_BTTask_private_method__setup>` **(** **)** |virtual| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Status<enum_BT_Status>` | :ref:`_tick<class_BTTask_private_method__tick>` **(** float delta **)** |virtual| | | :ref:`Status<enum_BT_Status>` | :ref:`_tick<class_BTTask_private_method__tick>` **(** float delta **)** |virtual| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`abort<class_BTTask_method_abort>` **(** **)** | | void | :ref:`abort<class_BTTask_method_abort>` **(** **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`add_child<class_BTTask_method_add_child>` **(** :ref:`BTTask<class_BTTask>` task **)** | | void | :ref:`add_child<class_BTTask_method_add_child>` **(** :ref:`BTTask<class_BTTask>` task **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`add_child_at_index<class_BTTask_method_add_child_at_index>` **(** :ref:`BTTask<class_BTTask>` task, int idx **)** | | void | :ref:`add_child_at_index<class_BTTask_method_add_child_at_index>` **(** :ref:`BTTask<class_BTTask>` task, int idx **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`clone<class_BTTask_method_clone>` **(** **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`clone<class_BTTask_method_clone>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`Status<enum_BT_Status>` | :ref:`execute<class_BTTask_method_execute>` **(** float delta **)** | | :ref:`Status<enum_BT_Status>` | :ref:`execute<class_BTTask_method_execute>` **(** float delta **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_child<class_BTTask_method_get_child>` **(** int idx **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`get_child<class_BTTask_method_get_child>` **(** int idx **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| int | :ref:`get_child_count<class_BTTask_method_get_child_count>` **(** **)** |const| | | int | :ref:`get_child_count<class_BTTask_method_get_child_count>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| int | :ref:`get_child_count_excluding_comments<class_BTTask_method_get_child_count_excluding_comments>` **(** **)** |const| | | int | :ref:`get_child_count_excluding_comments<class_BTTask_method_get_child_count_excluding_comments>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| int | :ref:`get_index<class_BTTask_method_get_index>` **(** **)** |const| | | int | :ref:`get_index<class_BTTask_method_get_index>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_parent<class_BTTask_method_get_parent>` **(** **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`get_parent<class_BTTask_method_get_parent>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`get_root<class_BTTask_method_get_root>` **(** **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`get_root<class_BTTask_method_get_root>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| String | :ref:`get_task_name<class_BTTask_method_get_task_name>` **(** **)** | | String | :ref:`get_task_name<class_BTTask_method_get_task_name>` **(** **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| bool | :ref:`has_child<class_BTTask_method_has_child>` **(** :ref:`BTTask<class_BTTask>` task **)** |const| | | bool | :ref:`has_child<class_BTTask_method_has_child>` **(** :ref:`BTTask<class_BTTask>` task **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`initialize<class_BTTask_method_initialize>` **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard **)** | | void | :ref:`initialize<class_BTTask_method_initialize>` **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard, Node scene_root **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| bool | :ref:`is_descendant_of<class_BTTask_method_is_descendant_of>` **(** :ref:`BTTask<class_BTTask>` task **)** |const| | | bool | :ref:`is_descendant_of<class_BTTask_method_is_descendant_of>` **(** :ref:`BTTask<class_BTTask>` task **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| bool | :ref:`is_root<class_BTTask_method_is_root>` **(** **)** |const| | | bool | :ref:`is_root<class_BTTask_method_is_root>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| :ref:`BTTask<class_BTTask>` | :ref:`next_sibling<class_BTTask_method_next_sibling>` **(** **)** |const| | | :ref:`BTTask<class_BTTask>` | :ref:`next_sibling<class_BTTask_method_next_sibling>` **(** **)** |const| |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`print_tree<class_BTTask_method_print_tree>` **(** int initial_tabs=0 **)** | | void | :ref:`print_tree<class_BTTask_method_print_tree>` **(** int initial_tabs=0 **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`remove_child<class_BTTask_method_remove_child>` **(** :ref:`BTTask<class_BTTask>` task **)** | | void | :ref:`remove_child<class_BTTask_method_remove_child>` **(** :ref:`BTTask<class_BTTask>` task **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
| void | :ref:`remove_child_at_index<class_BTTask_method_remove_child_at_index>` **(** int idx **)** | | void | :ref:`remove_child_at_index<class_BTTask_method_remove_child_at_index>` **(** int idx **)** |
+-------------------------------+---------------------------------------------------------------------------------------------------------------------------+ +-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
.. rst-class:: classref-section-separator .. rst-class:: classref-section-separator
@ -131,7 +133,7 @@ Node **agent**
- void **set_agent** **(** Node value **)** - void **set_agent** **(** Node value **)**
- Node **get_agent** **(** **)** - Node **get_agent** **(** **)**
The agent is a contextual object for the task's :ref:`BehaviorTree<class_BehaviorTree>` instance. Usually, agent is the owner of the :ref:`BTPlayer<class_BTPlayer>` node containing the :ref:`BehaviorTree<class_BehaviorTree>` resource. The agent is the contextual object for the :ref:`BehaviorTree<class_BehaviorTree>` instance. This is usually the parent of the :ref:`BTPlayer<class_BTPlayer>` node that utilizes the :ref:`BehaviorTree<class_BehaviorTree>` resource.
.. rst-class:: classref-item-separator .. rst-class:: classref-item-separator
@ -190,6 +192,33 @@ Returns ``0`` when task is not ``RUNNING``.
---- ----
.. _class_BTTask_property_scene_root:
.. rst-class:: classref-property
Node **scene_root**
.. rst-class:: classref-property-setget
- Node **get_scene_root** **(** **)**
Root node of the scene the behavior tree is used in (e.g., the owner of the :ref:`BTPlayer<class_BTPlayer>` node). Can be uses to retrieve ``NodePath`` references.
\ **Example:**\
::
extends BTAction
@export var node_path: NodePath
func _setup():
var node: Node = scene_root.get_node(node_path)
.. rst-class:: classref-item-separator
----
.. _class_BTTask_property_status: .. _class_BTTask_property_status:
.. rst-class:: classref-property .. rst-class:: classref-property
@ -457,11 +486,11 @@ Returns ``true`` if ``task`` is a child of this task.
.. rst-class:: classref-method .. rst-class:: classref-method
void **initialize** **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard **)** void **initialize** **(** Node agent, :ref:`Blackboard<class_Blackboard>` blackboard, Node scene_root **)**
Initilizes the task. Assigns :ref:`agent<class_BTTask_property_agent>` and :ref:`blackboard<class_BTTask_property_blackboard>`, and calls :ref:`_setup<class_BTTask_private_method__setup>` for the task and its children. Initilizes the task. Assigns :ref:`agent<class_BTTask_property_agent>` and :ref:`blackboard<class_BTTask_property_blackboard>`, and calls :ref:`_setup<class_BTTask_private_method__setup>` for the task and its children.
The method is called recursively for each child task. The method is called recursively for each child task. ``scene_root`` should be the root node of the scene the behavior tree is used in (e.g., the owner of the node that contains the behavior tree).
.. rst-class:: classref-item-separator .. rst-class:: classref-item-separator

View File

@ -3,9 +3,10 @@
Accessing nodes in the scene tree Accessing nodes in the scene tree
================================= =================================
There are several ways to access nodes in the agent's scene tree. There are several ways to access nodes in the agent's scene tree from a :ref:`BTTask<class_BTTask>`.
**🛈 Note:** Agent is the owner of :ref:`BTPlayer<class_BTPlayer>` node. **🛈 Note:** The root node of the agent's scene tree can be accessed with the
:ref:`scene_root<class_BTTask_property_scene_root>` property.
With ``BBNode`` property With ``BBNode`` property
@ -16,7 +17,7 @@ With ``BBNode`` property
@export var cast_param: BBNode @export var cast_param: BBNode
func _tick(delta) -> Status: func _tick(delta) -> Status:
var node: ShapeCast3D = cast_param.get_value(agent, blackboard) var node: ShapeCast3D = cast_param.get_value(scene_root, blackboard)
With ``NodePath`` property With ``NodePath`` property
@ -27,14 +28,16 @@ With ``NodePath`` property
@export var cast_path: NodePath @export var cast_path: NodePath
func _tick(delta) -> Status: func _tick(delta) -> Status:
var node: ShapeCast3D = agent.get_node(cast_path) var node: ShapeCast3D = scene_root.get_node(cast_path)
Using blackboard plan Using blackboard plan
--------------------- ---------------------
You can :ref:`create a blackboard variable<editing_plan>` in the editor with the type ``NodePath`` You can :ref:`create a blackboard variable<editing_plan>` in the editor with the type ``NodePath``
and point it to the proper node in the :ref:`BTPlayer<class_BTPlayer>` blackboard plan. and point it to the proper node in the :ref:`BTPlayer<class_BTPlayer>` blackboard plan. By default,
any ``NodePath`` variable will be replaced with the node instance when the blackboard is instantiated
at runtime (see :ref:`BlackboardPlan.prefetch_nodepath_vars<class_BlackboardPlan_property_prefetch_nodepath_vars>`).
.. code:: gdscript .. code:: gdscript

View File

@ -92,7 +92,7 @@ Example 1: A simple action
# Called each time this task is ticked (aka executed). # Called each time this task is ticked (aka executed).
func _tick(p_delta: float) -> Status: func _tick(p_delta: float) -> Status:
var n: CanvasItem = agent.get_node_or_null(node_path) var n: CanvasItem = scene_root.get_node_or_null(node_path)
if is_instance_valid(n): if is_instance_valid(n):
n.visible = visible n.visible = visible
return SUCCESS return SUCCESS

View File

@ -91,7 +91,7 @@ Usage example:
@export var speed: BBFloat @export var speed: BBFloat
func _tick(delta: float) -> Status: func _tick(delta: float) -> Status:
var current_speed: float = speed.get_value(agent, blackboard, 0.0) var current_speed: float = speed.get_value(scene_root, blackboard, 0.0)
... ...
Advanced topic: Blackboard scopes Advanced topic: Blackboard scopes

View File

@ -18,7 +18,7 @@
</method> </method>
<method name="get_value"> <method name="get_value">
<return type="Variant" /> <return type="Variant" />
<param index="0" name="agent" type="Object" /> <param index="0" name="scene_root" type="Node" />
<param index="1" name="blackboard" type="Blackboard" /> <param index="1" name="blackboard" type="Blackboard" />
<param index="2" name="default" type="Variant" default="null" /> <param index="2" name="default" type="Variant" default="null" />
<description> <description>

View File

@ -4,7 +4,7 @@
Player of [BehaviorTree] resources. Player of [BehaviorTree] resources.
</brief_description> </brief_description>
<description> <description>
BTPlayer node is used for the instantiation and playback of [BehaviorTree] resources at runtime. During instantiation, the behavior tree instance is initialized with a reference to the agent and the [member blackboard]. Agent is the owner of the BTPlayer node (see [member Node.owner]). [BTPlayer] node is used to instantiate and play [BehaviorTree] resources at runtime. During initialization, the behavior tree instance is given references to the agent, the [member blackboard], and the current scene root. The agent can be specified by the [member agent_node] property (defaults to the BTPlayer's parent node).
For an introduction to behavior trees, see [BehaviorTree]. For an introduction to behavior trees, see [BehaviorTree].
</description> </description>
<tutorials> <tutorials>
@ -40,6 +40,9 @@
<member name="active" type="bool" setter="set_active" getter="get_active" default="true"> <member name="active" type="bool" setter="set_active" getter="get_active" default="true">
If [code]true[/code], the behavior tree will be executed during update. If [code]true[/code], the behavior tree will be executed during update.
</member> </member>
<member name="agent_node" type="NodePath" setter="set_agent_node" getter="get_agent_node" default="NodePath(&quot;..&quot;)">
Path to the node that will be used as the agent. Setting it after instantiation will have no effect.
</member>
<member name="behavior_tree" type="BehaviorTree" setter="set_behavior_tree" getter="get_behavior_tree"> <member name="behavior_tree" type="BehaviorTree" setter="set_behavior_tree" getter="get_behavior_tree">
[BehaviorTree] resource to instantiate and execute at runtime. [BehaviorTree] resource to instantiate and execute at runtime.
</member> </member>

View File

@ -144,9 +144,10 @@
<return type="void" /> <return type="void" />
<param index="0" name="agent" type="Node" /> <param index="0" name="agent" type="Node" />
<param index="1" name="blackboard" type="Blackboard" /> <param index="1" name="blackboard" type="Blackboard" />
<param index="2" name="scene_root" type="Node" />
<description> <description>
Initilizes the task. Assigns [member agent] and [member blackboard], and calls [method _setup] for the task and its children. Initilizes the task. Assigns [member agent] and [member blackboard], and calls [method _setup] for the task and its children.
The method is called recursively for each child task. The method is called recursively for each child task. [param scene_root] should be the root node of the scene the behavior tree is used in (e.g., the owner of the node that contains the behavior tree).
</description> </description>
</method> </method>
<method name="is_descendant_of" qualifiers="const"> <method name="is_descendant_of" qualifiers="const">
@ -193,7 +194,7 @@
</methods> </methods>
<members> <members>
<member name="agent" type="Node" setter="set_agent" getter="get_agent"> <member name="agent" type="Node" setter="set_agent" getter="get_agent">
The agent is a contextual object for the task's [BehaviorTree] instance. Usually, agent is the owner of the [BTPlayer] node containing the [BehaviorTree] resource. The agent is the contextual object for the [BehaviorTree] instance. This is usually the parent of the [BTPlayer] node that utilizes the [BehaviorTree] resource.
</member> </member>
<member name="blackboard" type="Blackboard" setter="" getter="get_blackboard"> <member name="blackboard" type="Blackboard" setter="" getter="get_blackboard">
Provides access to the [Blackboard]. Blackboard is used to share data among tasks of the associated [BehaviorTree]. Provides access to the [Blackboard]. Blackboard is used to share data among tasks of the associated [BehaviorTree].
@ -206,6 +207,18 @@
Elapsed time since the task was "entered". See [method _enter]. Elapsed time since the task was "entered". See [method _enter].
Returns [code]0[/code] when task is not [code]RUNNING[/code]. Returns [code]0[/code] when task is not [code]RUNNING[/code].
</member> </member>
<member name="scene_root" type="Node" setter="" getter="get_scene_root">
Root node of the scene the behavior tree is used in (e.g., the owner of the [BTPlayer] node). Can be uses to retrieve [NodePath] references.
[b]Example:[/b]
[codeblock]
extends BTAction
@export var node_path: NodePath
func _setup():
var node: Node = scene_root.get_node(node_path)
[/codeblock]
</member>
<member name="status" type="int" setter="" getter="get_status" enum="BT.Status"> <member name="status" type="int" setter="" getter="get_status" enum="BT.Status">
Last execution [enum BT.Status] returned by [method _tick]. Last execution [enum BT.Status] returned by [method _tick].
</member> </member>

View File

@ -38,8 +38,9 @@
<return type="BTTask" /> <return type="BTTask" />
<param index="0" name="agent" type="Node" /> <param index="0" name="agent" type="Node" />
<param index="1" name="blackboard" type="Blackboard" /> <param index="1" name="blackboard" type="Blackboard" />
<param index="2" name="scene_root" type="Node" />
<description> <description>
Instantiates the Behavior Tree and returns the root [BTTask]. Instantiates the behavior tree and returns the root [BTTask]. [param scene_root] should be the root node of the scene that the Behavior Tree will be used in (e.g., the owner of the node that contains the behavior tree).
</description> </description>
</method> </method>
<method name="set_root_task"> <method name="set_root_task">

View File

@ -16,7 +16,7 @@
<param index="0" name="var_name" type="StringName" /> <param index="0" name="var_name" type="StringName" />
<param index="1" name="object" type="Object" /> <param index="1" name="object" type="Object" />
<param index="2" name="property" type="StringName" /> <param index="2" name="property" type="StringName" />
<param index="3" name="create" type="bool" /> <param index="3" name="create" type="bool" default="false" />
<description> <description>
Establish a binding between a variable and the object's property specified by [param property] and [param object]. Changes to the variable update the property, and vice versa. If [param create] is [code]true[/code], the variable will be created if it doesn't exist. Establish a binding between a variable and the object's property specified by [param property] and [param object]. Changes to the variable update the property, and vice versa. If [param create] is [code]true[/code], the variable will be created if it doesn't exist.
</description> </description>
@ -55,7 +55,7 @@
<param index="0" name="var_name" type="StringName" /> <param index="0" name="var_name" type="StringName" />
<param index="1" name="target_blackboard" type="Blackboard" /> <param index="1" name="target_blackboard" type="Blackboard" />
<param index="2" name="target_var" type="StringName" /> <param index="2" name="target_var" type="StringName" />
<param index="3" name="create" type="bool" /> <param index="3" name="create" type="bool" default="false" />
<description> <description>
Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. If [param create] is [code]true[/code], the variable will be created if it doesn't exist. Links a variable to another Blackboard variable. If a variable is linked to another variable, their state will always be identical, and any change to one will be reflected in the other. If [param create] is [code]true[/code], the variable will be created if it doesn't exist.
You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance. A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables. You can use this method to link a variable in the current scope to a variable in another scope, or in another Blackboard instance. A variable can only be linked to one other variable. Calling this method again will overwrite the previous link. However, it is possible to link to the same variable from multiple different variables.

View File

@ -51,13 +51,13 @@ TEST_CASE("[SceneTree][LimboAI] BTAwaitAnimation") {
SUBCASE("When AnimationPlayer doesn't exist") { SUBCASE("When AnimationPlayer doesn't exist") {
player_param->set_saved_value(NodePath("./NotFound")); player_param->set_saved_value(NodePath("./NotFound"));
ERR_PRINT_OFF; ERR_PRINT_OFF;
awa->initialize(dummy, bb); awa->initialize(dummy, bb, dummy);
CHECK(awa->execute(0.01666) == BTTask::FAILURE); CHECK(awa->execute(0.01666) == BTTask::FAILURE);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
SUBCASE("When AnimationPlayer exists") { SUBCASE("When AnimationPlayer exists") {
player_param->set_saved_value(player->get_path()); player_param->set_saved_value(player->get_path());
awa->initialize(dummy, bb); awa->initialize(dummy, bb, dummy);
SUBCASE("When AnimationPlayer is not playing") { SUBCASE("When AnimationPlayer is not playing") {
REQUIRE_FALSE(player->is_playing()); REQUIRE_FALSE(player->is_playing());

View File

@ -47,7 +47,7 @@ TEST_CASE("[Modules][LimboAI] BTCallMethod") {
node_param->set_variable("object"); node_param->set_variable("object");
cm->set_method("callback"); cm->set_method("callback");
cm->initialize(dummy, bb); cm->initialize(dummy, bb, dummy);
SUBCASE("When method is empty") { SUBCASE("When method is empty") {
cm->set_method(""); cm->set_method("");

View File

@ -39,7 +39,7 @@ TEST_CASE("[Modules][LimboAI] BTCheckAgentProperty") {
Ref<BTCheckAgentProperty> cap = memnew(BTCheckAgentProperty); Ref<BTCheckAgentProperty> cap = memnew(BTCheckAgentProperty);
Node *agent = memnew(Node); Node *agent = memnew(Node);
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
cap->initialize(agent, bb); cap->initialize(agent, bb, agent);
StringName agent_name = "SimpleNode"; StringName agent_name = "SimpleNode";
agent->set_name(agent_name); agent->set_name(agent_name);

View File

@ -24,7 +24,7 @@ TEST_CASE("[Modules][LimboAI] BTCheckTrigger") {
Node *dummy = memnew(Node); Node *dummy = memnew(Node);
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
ct->initialize(dummy, bb); ct->initialize(dummy, bb, dummy);
SUBCASE("Empty") { SUBCASE("Empty") {
ERR_PRINT_OFF; ERR_PRINT_OFF;

View File

@ -36,7 +36,7 @@ TEST_CASE("[Modules][LimboAI] BTCheckVar") {
Ref<BTCheckVar> cv = memnew(BTCheckVar); Ref<BTCheckVar> cv = memnew(BTCheckVar);
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
Node *dummy = memnew(Node); Node *dummy = memnew(Node);
cv->initialize(dummy, bb); cv->initialize(dummy, bb, dummy);
SUBCASE("Check with empty variable and value") { SUBCASE("Check with empty variable and value") {
cv->set_variable(""); cv->set_variable("");

View File

@ -47,7 +47,7 @@ TEST_CASE("[Modules][LimboAI] BTEvaluateExpression") {
node_param->set_variable("object"); node_param->set_variable("object");
ee->set_expression_string("callback()"); ee->set_expression_string("callback()");
ee->initialize(dummy, bb); ee->initialize(dummy, bb, dummy);
SUBCASE("When expression string is empty") { SUBCASE("When expression string is empty") {
ee->set_expression_string(""); ee->set_expression_string("");

View File

@ -23,7 +23,7 @@ TEST_CASE("[Modules][LimboAI] BTForEach") {
Ref<BTForEach> fe = memnew(BTForEach); Ref<BTForEach> fe = memnew(BTForEach);
Node *dummy = memnew(Node); Node *dummy = memnew(Node);
Ref<Blackboard> blackboard = memnew(Blackboard); Ref<Blackboard> blackboard = memnew(Blackboard);
fe->initialize(dummy, blackboard); fe->initialize(dummy, blackboard, dummy);
Array arr; Array arr;
arr.append("apple"); arr.append("apple");

View File

@ -26,7 +26,7 @@ TEST_CASE("[Modules][LimboAI] BTNewScope") {
SUBCASE("When empty") { SUBCASE("When empty") {
ERR_PRINT_OFF; ERR_PRINT_OFF;
ns->initialize(dummy, parent_bb); ns->initialize(dummy, parent_bb, dummy);
CHECK(ns->execute(0.01666) == BTTask::FAILURE); CHECK(ns->execute(0.01666) == BTTask::FAILURE);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
@ -45,7 +45,7 @@ TEST_CASE("[Modules][LimboAI] BTNewScope") {
REQUIRE(parent_bb->has_var("vegetable")); REQUIRE(parent_bb->has_var("vegetable"));
REQUIRE(parent_bb->get_var("vegetable", "wetgoop") == "carrot"); REQUIRE(parent_bb->get_var("vegetable", "wetgoop") == "carrot");
parent->initialize(dummy, parent_bb); parent->initialize(dummy, parent_bb, dummy);
CHECK(ns->get_blackboard() != parent->get_blackboard()); CHECK(ns->get_blackboard() != parent->get_blackboard());
CHECK(ns->get_blackboard() == child->get_blackboard()); CHECK(ns->get_blackboard() == child->get_blackboard());

View File

@ -48,13 +48,13 @@ TEST_CASE("[SceneTree][LimboAI] BTPauseAnimation") {
SUBCASE("When AnimationPlayer doesn't exist") { SUBCASE("When AnimationPlayer doesn't exist") {
player_param->set_saved_value(NodePath("./NotFound")); player_param->set_saved_value(NodePath("./NotFound"));
ERR_PRINT_OFF; ERR_PRINT_OFF;
pa->initialize(dummy, bb); pa->initialize(dummy, bb, dummy);
CHECK(pa->execute(0.01666) == BTTask::FAILURE); CHECK(pa->execute(0.01666) == BTTask::FAILURE);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
SUBCASE("When AnimationPlayer exists") { SUBCASE("When AnimationPlayer exists") {
player_param->set_saved_value(player->get_path()); player_param->set_saved_value(player->get_path());
pa->initialize(dummy, bb); pa->initialize(dummy, bb, dummy);
SUBCASE("When AnimationPlayer is not playing") { SUBCASE("When AnimationPlayer is not playing") {
REQUIRE_FALSE(player->is_playing()); REQUIRE_FALSE(player->is_playing());

View File

@ -49,13 +49,13 @@ TEST_CASE("[SceneTree][LimboAI] BTPlayAnimation") {
SUBCASE("When AnimationPlayer doesn't exist") { SUBCASE("When AnimationPlayer doesn't exist") {
player_param->set_saved_value(NodePath("./NotFound")); player_param->set_saved_value(NodePath("./NotFound"));
ERR_PRINT_OFF; ERR_PRINT_OFF;
pa->initialize(dummy, bb); pa->initialize(dummy, bb, dummy);
CHECK(pa->execute(0.01666) == BTTask::FAILURE); CHECK(pa->execute(0.01666) == BTTask::FAILURE);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
SUBCASE("When AnimationPlayer exists") { SUBCASE("When AnimationPlayer exists") {
player_param->set_saved_value(player->get_path()); player_param->set_saved_value(player->get_path());
pa->initialize(dummy, bb); pa->initialize(dummy, bb, dummy);
SUBCASE("When not waiting to finish") { SUBCASE("When not waiting to finish") {
pa->set_await_completion(0.0); pa->set_await_completion(0.0);

View File

@ -28,7 +28,7 @@ TEST_CASE("[Modules][LimboAI] BTSetAgentProperty") {
Ref<BTSetAgentProperty> sap = memnew(BTSetAgentProperty); Ref<BTSetAgentProperty> sap = memnew(BTSetAgentProperty);
Node *agent = memnew(Node); Node *agent = memnew(Node);
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
sap->initialize(agent, bb); sap->initialize(agent, bb, agent);
sap->set_property("process_priority"); // * property that will be set by the task sap->set_property("process_priority"); // * property that will be set by the task
Ref<BBVariant> value = memnew(BBVariant); Ref<BBVariant> value = memnew(BBVariant);

View File

@ -29,7 +29,7 @@ TEST_CASE("[Modules][LimboAI] BTSetVar") {
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
Node *dummy = memnew(Node); Node *dummy = memnew(Node);
sv->initialize(dummy, bb); sv->initialize(dummy, bb, dummy);
SUBCASE("When variable is not set") { SUBCASE("When variable is not set") {
ERR_PRINT_OFF; ERR_PRINT_OFF;

View File

@ -48,13 +48,13 @@ TEST_CASE("[SceneTree][LimboAI] BTStopAnimation") {
SUBCASE("When AnimationPlayer doesn't exist") { SUBCASE("When AnimationPlayer doesn't exist") {
player_param->set_saved_value(NodePath("./NotFound")); player_param->set_saved_value(NodePath("./NotFound"));
ERR_PRINT_OFF; ERR_PRINT_OFF;
sa->initialize(dummy, bb); sa->initialize(dummy, bb, dummy);
CHECK(sa->execute(0.01666) == BTTask::FAILURE); CHECK(sa->execute(0.01666) == BTTask::FAILURE);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
SUBCASE("When AnimationPlayer exists") { SUBCASE("When AnimationPlayer exists") {
player_param->set_saved_value(player->get_path()); player_param->set_saved_value(player->get_path());
sa->initialize(dummy, bb); sa->initialize(dummy, bb, dummy);
SUBCASE("When AnimationPlayer is not playing") { SUBCASE("When AnimationPlayer is not playing") {
REQUIRE_FALSE(player->is_playing()); REQUIRE_FALSE(player->is_playing());

View File

@ -29,7 +29,7 @@ TEST_CASE("[Modules][LimboAI] BTSubtree") {
SUBCASE("When empty") { SUBCASE("When empty") {
ERR_PRINT_OFF; ERR_PRINT_OFF;
st->initialize(dummy, bb); st->initialize(dummy, bb, dummy);
CHECK(st->execute(0.01666) == BTTask::FAILURE); CHECK(st->execute(0.01666) == BTTask::FAILURE);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
@ -41,7 +41,7 @@ TEST_CASE("[Modules][LimboAI] BTSubtree") {
st->set_subtree(bt); st->set_subtree(bt);
CHECK(st->get_child_count() == 0); CHECK(st->get_child_count() == 0);
st->initialize(dummy, bb); st->initialize(dummy, bb, dummy);
CHECK(st->get_child_count() == 1); CHECK(st->get_child_count() == 1);
CHECK(st->get_child(0) != task); CHECK(st->get_child(0) != task);

View File

@ -162,7 +162,7 @@ TEST_CASE("[Modules][LimboAI] BTTask") {
Node *dummy = memnew(Node); Node *dummy = memnew(Node);
Ref<Blackboard> bb = memnew(Blackboard); Ref<Blackboard> bb = memnew(Blackboard);
SUBCASE("With valid parameters") { SUBCASE("With valid parameters") {
task->initialize(dummy, bb); task->initialize(dummy, bb, dummy);
CHECK(task->get_agent() == dummy); CHECK(task->get_agent() == dummy);
CHECK(task->get_blackboard() == bb); CHECK(task->get_blackboard() == bb);
CHECK(child1->get_agent() == dummy); CHECK(child1->get_agent() == dummy);
@ -174,12 +174,17 @@ TEST_CASE("[Modules][LimboAI] BTTask") {
} }
SUBCASE("Test if not crashes when agent is null") { SUBCASE("Test if not crashes when agent is null") {
ERR_PRINT_OFF; ERR_PRINT_OFF;
task->initialize(nullptr, bb); task->initialize(nullptr, bb, dummy);
ERR_PRINT_ON;
}
SUBCASE("Test if not crashes when scene_owner is null") {
ERR_PRINT_OFF;
task->initialize(dummy, bb, nullptr);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
SUBCASE("Test if not crashes when BB is null") { SUBCASE("Test if not crashes when BB is null") {
ERR_PRINT_OFF; ERR_PRINT_OFF;
task->initialize(dummy, nullptr); task->initialize(dummy, nullptr, dummy);
ERR_PRINT_ON; ERR_PRINT_ON;
} }
memdelete(dummy); memdelete(dummy);

View File

@ -53,6 +53,7 @@
#define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable, Variant())) #define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable, Variant()))
#define GET_SCRIPT(m_obj) (m_obj->get_script_instance() ? m_obj->get_script_instance()->get_script() : nullptr) #define GET_SCRIPT(m_obj) (m_obj->get_script_instance() ? m_obj->get_script_instance()->get_script() : nullptr)
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_style_override(m_name, m_stylebox)) #define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_style_override(m_name, m_stylebox))
#define GET_NODE(m_parent, m_path) m_parent->get_node(m_path)
_FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) { _FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) {
bool r_valid; bool r_valid;
@ -137,6 +138,7 @@ using namespace godot;
#define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable)) #define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable))
#define GET_SCRIPT(m_obj) (m_obj->get_script()) #define GET_SCRIPT(m_obj) (m_obj->get_script())
#define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_stylebox_override(m_name, m_stylebox)) #define ADD_STYLEBOX_OVERRIDE(m_control, m_name, m_stylebox) (m_control->add_theme_stylebox_override(m_name, m_stylebox))
#define GET_NODE(m_parent, m_path) m_parent->get_node_internal(m_path)
_FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) { _FORCE_INLINE_ bool OBJECT_HAS_PROPERTY(Object *p_obj, const StringName &p_prop) {
return Variant(p_obj).has_key(p_prop); return Variant(p_obj).has_key(p_prop);

View File

@ -166,4 +166,6 @@ LimboStringNames::LimboStringNames() {
repeat_forever.parse_utf8("Repeat ∞"); repeat_forever.parse_utf8("Repeat ∞");
output_var_prefix.parse_utf8(""); output_var_prefix.parse_utf8("");
node_pp = NodePath("..");
} }

View File

@ -13,6 +13,7 @@
#define LIMBO_STRING_NAMES_H #define LIMBO_STRING_NAMES_H
#ifdef LIMBOAI_MODULE #ifdef LIMBOAI_MODULE
#include "core/string/node_path.h"
#include "core/string/string_name.h" #include "core/string/string_name.h"
#include "core/typedefs.h" #include "core/typedefs.h"
#include "modules/register_module_types.h" #include "modules/register_module_types.h"
@ -20,6 +21,7 @@
#ifdef LIMBOAI_GDEXTENSION #ifdef LIMBOAI_GDEXTENSION
#include "godot_cpp/variant/string.hpp" #include "godot_cpp/variant/string.hpp"
#include <godot_cpp/variant/node_path.hpp>
#include <godot_cpp/variant/string_name.hpp> #include <godot_cpp/variant/string_name.hpp>
using namespace godot; using namespace godot;
#endif // LIMBOAI_GDEXTENSION #endif // LIMBOAI_GDEXTENSION
@ -181,6 +183,8 @@ public:
String repeat_forever; String repeat_forever;
String output_var_prefix; String output_var_prefix;
NodePath node_pp;
}; };
#define LW_NAME(m_arg) LimboStringNames::get_singleton()->m_arg #define LW_NAME(m_arg) LimboStringNames::get_singleton()->m_arg

View File

@ -36,7 +36,7 @@ using namespace godot;
#define LOGICAL_XOR(a, b) (a) ? !(b) : (b) #define LOGICAL_XOR(a, b) (a) ? !(b) : (b)
#define LIMBO_DOC_VERSION "v1.0" #define LIMBO_DOC_VERSION "latest"
class LimboUtility : public Object { class LimboUtility : public Object {
GDCLASS(LimboUtility, Object); GDCLASS(LimboUtility, Object);