Refactor BTPlayer and BTState

This commit is contained in:
Serhii Snitsaruk 2022-12-16 15:29:36 +01:00
parent 0bb03c2b4c
commit c67216c1e1
5 changed files with 34 additions and 45 deletions

View File

@ -5,6 +5,7 @@
#include "../limbo_string_names.h" #include "../limbo_string_names.h"
#include "bt_task.h" #include "bt_task.h"
#include "core/config/engine.h" #include "core/config/engine.h"
#include "core/error/error_macros.h"
#include "core/io/resource_loader.h" #include "core/io/resource_loader.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/object/object.h" #include "core/object/object.h"
@ -15,23 +16,19 @@
VARIANT_ENUM_CAST(BTPlayer::UpdateMode); VARIANT_ENUM_CAST(BTPlayer::UpdateMode);
void BTPlayer::_load_tree() { void BTPlayer::_load_tree() {
_loaded_tree.unref(); tree_instance.unref();
_root_task.unref(); ERR_FAIL_COND_MSG(!behavior_tree.is_valid(), "BTPlayer: Needs a valid behavior 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(), "BTPlayer: Behavior tree has no valid root task.");
ERR_FAIL_COND_MSG(!behavior_tree->get_root_task().is_valid(), "Behavior tree has no valid root task.");
_loaded_tree = behavior_tree;
if (prefetch_nodepath_vars == true) { if (prefetch_nodepath_vars == true) {
// blackboard->prefetch_nodepath_vars(get_owner());
blackboard->prefetch_nodepath_vars(this); blackboard->prefetch_nodepath_vars(this);
} }
_root_task = _loaded_tree->instantiate(get_owner(), blackboard); tree_instance = behavior_tree->instantiate(get_owner(), blackboard);
} }
void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) { void BTPlayer::set_behavior_tree(const Ref<BehaviorTree> &p_tree) {
behavior_tree = p_tree; behavior_tree = p_tree;
if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) { if (Engine::get_singleton()->is_editor_hint() == false && get_owner()) {
_load_tree(); _load_tree();
set_update_mode(update_mode);
} }
} }
@ -42,44 +39,39 @@ void BTPlayer::set_update_mode(UpdateMode p_mode) {
void BTPlayer::set_active(bool p_active) { void BTPlayer::set_active(bool p_active) {
active = p_active; active = p_active;
if (!Engine::get_singleton()->is_editor_hint()) { bool is_not_editor = !Engine::get_singleton()->is_editor_hint();
set_process(update_mode == UpdateMode::IDLE); set_process(update_mode == UpdateMode::IDLE && active && is_not_editor);
set_physics_process(update_mode == UpdateMode::PHYSICS); set_physics_process(update_mode == UpdateMode::PHYSICS && active && is_not_editor);
} set_process_input(active && is_not_editor);
} }
void BTPlayer::update(float p_delta) { void BTPlayer::update(float p_delta) {
if (!_root_task.is_valid()) { if (!tree_instance.is_valid()) {
ERR_PRINT_ONCE(vformat("BTPlayer has no root task to update (owner: %s)", get_owner())); ERR_PRINT_ONCE(vformat("BTPlayer doesn't have a behavior tree with a valid root task to execute (owner: %s)", get_owner()));
return; return;
} }
if (active) { if (active) {
int status = _root_task->execute(p_delta); last_status = tree_instance->execute(p_delta);
if (status == BTTask::SUCCESS || status == BTTask::FAILURE) { if (last_status == BTTask::SUCCESS || last_status == BTTask::FAILURE) {
set_active(auto_restart); emit_signal(LimboStringNames::get_singleton()->behavior_tree_finished, last_status);
emit_signal(LimboStringNames::get_singleton()->behavior_tree_finished, status);
} }
} }
} }
void BTPlayer::restart() { void BTPlayer::restart() {
_root_task->cancel(); tree_instance->cancel();
set_active(true); set_active(true);
} }
void BTPlayer::_notification(int p_notification) { void BTPlayer::_notification(int p_notification) {
switch (p_notification) { switch (p_notification) {
case NOTIFICATION_PROCESS: { case NOTIFICATION_PROCESS: {
if (active) { Variant time = get_process_delta_time();
Variant time = get_process_delta_time(); update(time);
update(time);
}
} break; } break;
case NOTIFICATION_PHYSICS_PROCESS: { case NOTIFICATION_PHYSICS_PROCESS: {
if (active) { Variant time = get_process_delta_time();
Variant time = get_process_delta_time(); update(time);
update(time);
}
} break; } break;
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
if (!Engine::get_singleton()->is_editor_hint()) { if (!Engine::get_singleton()->is_editor_hint()) {
@ -99,8 +91,6 @@ void BTPlayer::_bind_methods() {
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", "p_active"), &BTPlayer::set_active); ClassDB::bind_method(D_METHOD("set_active", "p_active"), &BTPlayer::set_active);
ClassDB::bind_method(D_METHOD("get_active"), &BTPlayer::get_active); ClassDB::bind_method(D_METHOD("get_active"), &BTPlayer::get_active);
ClassDB::bind_method(D_METHOD("set_auto_restart", "p_value"), &BTPlayer::set_auto_restart);
ClassDB::bind_method(D_METHOD("get_auto_restart"), &BTPlayer::get_auto_restart);
ClassDB::bind_method(D_METHOD("set_blackboard", "p_blackboard"), &BTPlayer::set_blackboard); ClassDB::bind_method(D_METHOD("set_blackboard", "p_blackboard"), &BTPlayer::set_blackboard);
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTPlayer::get_blackboard); ClassDB::bind_method(D_METHOD("get_blackboard"), &BTPlayer::get_blackboard);
ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "p_value"), &BTPlayer::set_prefetch_nodepath_vars); ClassDB::bind_method(D_METHOD("set_prefetch_nodepath_vars", "p_value"), &BTPlayer::set_prefetch_nodepath_vars);
@ -111,11 +101,11 @@ void BTPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("update", "p_delta"), &BTPlayer::update); ClassDB::bind_method(D_METHOD("update", "p_delta"), &BTPlayer::update);
ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart); ClassDB::bind_method(D_METHOD("restart"), &BTPlayer::restart);
ClassDB::bind_method(D_METHOD("get_last_status"), &BTPlayer::get_last_status);
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::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::BOOL, "auto_restart"), "set_auto_restart", "get_auto_restart");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "", "get_blackboard"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "blackboard", PROPERTY_HINT_NONE, "Blackboard", 0), "", "get_blackboard");
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_blackboard_data", "_get_blackboard_data"); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_blackboard_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_blackboard_data", "_get_blackboard_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars"), "set_prefetch_nodepath_vars", "get_prefetch_nodepath_vars"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefetch_nodepath_vars"), "set_prefetch_nodepath_vars", "get_prefetch_nodepath_vars");

View File

@ -21,14 +21,13 @@ public:
private: private:
Ref<BehaviorTree> behavior_tree; Ref<BehaviorTree> behavior_tree;
UpdateMode update_mode = UpdateMode::IDLE; UpdateMode update_mode = UpdateMode::PHYSICS;
bool active = false; bool active = true;
bool auto_restart = false;
Ref<Blackboard> blackboard; Ref<Blackboard> blackboard;
bool prefetch_nodepath_vars = true; bool prefetch_nodepath_vars = true;
int last_status = -1;
Ref<BehaviorTree> _loaded_tree; Ref<BTTask> tree_instance;
Ref<BTTask> _root_task;
void _load_tree(); void _load_tree();
@ -50,9 +49,6 @@ public:
void set_active(bool p_active); void set_active(bool p_active);
bool get_active() const { return active; } bool get_active() const { return active; }
void set_auto_restart(bool p_value) { auto_restart = p_value; }
bool get_auto_restart() const { return auto_restart; }
Ref<Blackboard> get_blackboard() const { return blackboard; } Ref<Blackboard> get_blackboard() const { return blackboard; }
void set_blackboard(const Ref<Blackboard> &p_blackboard) { blackboard = p_blackboard; } void set_blackboard(const Ref<Blackboard> &p_blackboard) { blackboard = p_blackboard; }
@ -61,6 +57,7 @@ public:
void update(float p_delta); void update(float p_delta);
void restart(); void restart();
int get_last_status() const { return last_status; }
BTPlayer(); BTPlayer();
~BTPlayer(); ~BTPlayer();

View File

@ -1,21 +1,25 @@
/* bt_state.cpp */ /* bt_state.cpp */
#include "bt_state.h" #include "bt_state.h"
#include "core/error/error_macros.h"
#include "core/object/class_db.h" #include "core/object/class_db.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "modules/limboai/bt/bt_task.h" #include "modules/limboai/bt/bt_task.h"
#include "modules/limboai/limbo_state.h" #include "modules/limboai/limbo_state.h"
void BTState::_setup() { void BTState::_setup() {
root_task = behavior_tree->instantiate(get_agent(), get_blackboard()); ERR_FAIL_COND_MSG(behavior_tree.is_null(), "BTState: BehaviorTree is not assigned.");
tree_instance = behavior_tree->instantiate(get_agent(), get_blackboard());
} }
void BTState::_exit() { void BTState::_exit() {
root_task->cancel(); ERR_FAIL_COND(tree_instance == nullptr);
tree_instance->cancel();
} }
void BTState::_update(float p_delta) { void BTState::_update(float p_delta) {
int status = root_task->execute(p_delta); ERR_FAIL_COND(tree_instance == nullptr);
int status = tree_instance->execute(p_delta);
if (status == BTTask::SUCCESS) { if (status == BTTask::SUCCESS) {
get_root()->dispatch(success_event, Variant()); get_root()->dispatch(success_event, Variant());
} else if (status == BTTask::FAILURE) { } else if (status == BTTask::FAILURE) {

View File

@ -13,7 +13,7 @@ class BTState : public LimboState {
private: private:
Ref<BehaviorTree> behavior_tree; Ref<BehaviorTree> behavior_tree;
Ref<BTTask> root_task; Ref<BTTask> tree_instance;
String success_event; String success_event;
String failure_event; String failure_event;
@ -21,7 +21,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
virtual void _setup() override; virtual void _setup() override;
virtual void _enter() override {} // virtual void _enter() override {}
virtual void _exit() override; virtual void _exit() override;
virtual void _update(float p_delta) override; virtual void _update(float p_delta) override;

View File

@ -45,8 +45,6 @@ script = ExtResource("1_1l3ql")
[node name="BTPlayer" type="BTPlayer" parent="."] [node name="BTPlayer" type="BTPlayer" parent="."]
behavior_tree = ExtResource("2_58ujo") behavior_tree = ExtResource("2_58ujo")
update_mode = 1
active = true
_blackboard_data = { _blackboard_data = {
"speed": 500.0 "speed": 500.0
} }