Add instancing to behavior tree

This commit is contained in:
Serhii Snitsaruk 2022-09-21 16:13:17 +02:00
parent 6cac198092
commit 7be7ca276d
7 changed files with 36 additions and 16 deletions

View File

@ -2,6 +2,7 @@
#include "behavior_tree.h"
#include "core/class_db.h"
#include "core/error_macros.h"
#include "core/list.h"
#include "core/object.h"
#include "core/variant.h"
@ -32,6 +33,13 @@ Ref<BehaviorTree> BehaviorTree::clone() const {
return copy;
}
Ref<BTTask> BehaviorTree::instance(Object *p_agent, const Ref<Blackboard> &p_blackboard) const {
ERR_FAIL_COND_V_MSG(root_task == nullptr, memnew(BTTask), "Trying to instance a behavior tree with no valid root task.");
Ref<BTTask> inst = root_task->clone();
inst->initialize(p_agent, p_blackboard);
return inst;
}
void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_description", "p_value"), &BehaviorTree::set_description);
ClassDB::bind_method(D_METHOD("get_description"), &BehaviorTree::get_description);
@ -39,6 +47,7 @@ void BehaviorTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_root_task"), &BehaviorTree::get_root_task);
ClassDB::bind_method(D_METHOD("init"), &BehaviorTree::init);
ClassDB::bind_method(D_METHOD("clone"), &BehaviorTree::clone);
ClassDB::bind_method(D_METHOD("instance", "p_agent", "p_blackboard"), &BehaviorTree::instance);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_task", PROPERTY_HINT_RESOURCE_TYPE, "BTTask"), "set_root_task", "get_root_task");

View File

@ -3,10 +3,10 @@
#ifndef BEHAVIOR_TREE_H
#define BEHAVIOR_TREE_H
#include "bt_task.h"
#include "core/object.h"
#include "core/resource.h"
#include "bt_task.h"
#include "modules/limboai/blackboard.h"
class BehaviorTree : public Resource {
GDCLASS(BehaviorTree, Resource);
@ -33,6 +33,7 @@ public:
void init();
Ref<BehaviorTree> clone() const;
Ref<BTTask> instance(Object *p_agent, const Ref<Blackboard> &p_blackboard) const;
};
#endif // BEHAVIOR_TREE_H

View File

@ -21,8 +21,7 @@ void BTPlayer::_load_tree() {
ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer needs a valid behavior tree.");
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "Behavior tree has no valid root task.");
_loaded_tree = behavior_tree;
_root_task = _loaded_tree->get_root_task()->clone();
_root_task->initialize(get_owner(), blackboard);
_root_task = _loaded_tree->instance(get_owner(), blackboard);
}
void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {

View File

@ -93,7 +93,8 @@ void BTTask::initialize(Object *p_agent, const Ref<Blackboard> &p_blackboard) {
Ref<BTTask> BTTask::clone() const {
Ref<BTTask> inst = duplicate(false);
inst->parent = nullptr;
CRASH_COND(inst->get_parent().is_valid());
inst->agent = nullptr;
inst->blackboard.unref();
for (int i = 0; i < children.size(); i++) {
Ref<BTTask> c = get_child(i)->clone();
c->parent = inst.ptr();
@ -186,6 +187,11 @@ void BTTask::remove_child(Ref<BTTask> p_child) {
}
}
void BTTask::remove_child_at_index(int p_idx) {
ERR_FAIL_INDEX(p_idx, get_child_count());
children.remove(p_idx);
}
bool BTTask::has_child(const Ref<BTTask> &p_child) const {
return children.find(p_child) != -1;
}
@ -277,6 +283,7 @@ void BTTask::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_child", "p_child"), &BTTask::add_child);
ClassDB::bind_method(D_METHOD("add_child_at_index", "p_child", "p_idx"), &BTTask::add_child_at_index);
ClassDB::bind_method(D_METHOD("remove_child", "p_child"), &BTTask::remove_child);
ClassDB::bind_method(D_METHOD("remove_child_at_index", "p_idx"), &BTTask::remove_child_at_index);
ClassDB::bind_method(D_METHOD("has_child", "p_child"), &BTTask::has_child);
ClassDB::bind_method(D_METHOD("is_descendant_of", "p_task"), &BTTask::is_descendant_of);
ClassDB::bind_method(D_METHOD("get_child_index", "p_child"), &BTTask::get_child_index);

View File

@ -57,8 +57,8 @@ public:
void set_custom_name(const String &p_name);
String get_task_name() const;
virtual void initialize(Object *p_agent, const Ref<Blackboard> &p_blackboard);
virtual Ref<BTTask> clone() const;
virtual void initialize(Object *p_agent, const Ref<Blackboard> &p_blackboard);
int execute(float p_delta);
void cancel();
Ref<BTTask> get_child(int p_idx) const;
@ -66,6 +66,7 @@ public:
void add_child(Ref<BTTask> p_child);
void add_child_at_index(Ref<BTTask> p_child, int p_idx);
void remove_child(Ref<BTTask> p_child);
void remove_child_at_index(int p_idx);
bool has_child(const Ref<BTTask> &p_child) const;
bool is_descendant_of(const Ref<BTTask> &p_task) const;
int get_child_index(const Ref<BTTask> &p_child) const;

View File

@ -11,6 +11,7 @@
#include "modules/limboai/bt/actions/bt_fail.h"
#include "modules/limboai/bt/bt_task.h"
#include "modules/limboai/bt/decorators/bt_decorator.h"
#include "modules/limboai/bt/decorators/bt_new_scope.h"
String BTSubtree::_generate_name() const {
String s;
@ -24,16 +25,18 @@ String BTSubtree::_generate_name() const {
return vformat("Subtree %s", s);
}
Ref<BTTask> BTSubtree::clone() const {
Ref<BTTask> copy = BTDecorator::clone();
if (!Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_COND_V_MSG(!subtree.is_valid(), copy, "Subtree is not assigned.");
ERR_FAIL_COND_V_MSG(!subtree->get_root_task().is_valid(), copy, "Subtree root task is not valid.");
ERR_FAIL_COND_V_MSG(get_child_count() != 0, copy, "Subtree prototype shouldn't have children.");
void BTSubtree::initialize(Object *p_agent, const Ref<Blackboard> &p_blackboard) {
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(get_child_count() != 0, "Subtree task shouldn't have children during initialization.");
copy->add_child(subtree->get_root_task()->clone());
}
return copy;
// while (get_child_count() > 0) {
// remove_child_at_index(get_child_count() - 1);
// }
add_child(subtree->get_root_task()->clone());
BTNewScope::initialize(p_agent, p_blackboard);
}
int BTSubtree::_tick(float p_delta) {

View File

@ -26,7 +26,7 @@ public:
}
Ref<BehaviorTree> get_subtree() const { return subtree; }
virtual Ref<BTTask> clone() const;
virtual void initialize(Object *p_agent, const Ref<Blackboard> &p_blackboard);
virtual String get_configuration_warning() const;
};