Add instancing to behavior tree
This commit is contained in:
parent
6cac198092
commit
7be7ca276d
|
@ -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");
|
||||
|
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue