Add first BT classes
This commit is contained in:
parent
b1f6386e52
commit
1123ffdced
|
@ -0,0 +1,5 @@
|
||||||
|
# SCsub
|
||||||
|
|
||||||
|
Import('env')
|
||||||
|
|
||||||
|
env.add_source_files(env.modules_sources, "*.cpp") # Add all cpp files to the build
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* bt_action.cpp */
|
||||||
|
|
||||||
|
#include "bt_action.h"
|
||||||
|
|
||||||
|
String BTAction::get_configuration_warning() const {
|
||||||
|
String warning = BTTask::get_configuration_warning();
|
||||||
|
if (!warning.empty()) {
|
||||||
|
warning += "\n";
|
||||||
|
}
|
||||||
|
if (get_child_count() != 0) {
|
||||||
|
warning += "Action can't have child tasks.\n";
|
||||||
|
}
|
||||||
|
return warning;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* bt_action.h */
|
||||||
|
|
||||||
|
#ifndef BT_ACTION_H
|
||||||
|
#define BT_ACTION_H
|
||||||
|
|
||||||
|
#include "bt_task.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
class BTAction : public BTTask {
|
||||||
|
GDCLASS(BTAction, BTTask);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_ACTION_H
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* bt_composite.cpp */
|
||||||
|
|
||||||
|
#include "bt_composite.h"
|
||||||
|
|
||||||
|
String BTComposite::get_configuration_warning() const {
|
||||||
|
String warning = BTTask::get_configuration_warning();
|
||||||
|
if (!warning.empty()) {
|
||||||
|
warning += "\n";
|
||||||
|
}
|
||||||
|
if (get_child_count() < 1) {
|
||||||
|
warning += "Composite should have at least one child task.\n";
|
||||||
|
}
|
||||||
|
return warning;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* bt_composite.h */
|
||||||
|
|
||||||
|
#ifndef BT_COMPOSITE_H
|
||||||
|
#define BT_COMPOSITE_H
|
||||||
|
|
||||||
|
#include "bt_task.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
class BTComposite : public BTTask {
|
||||||
|
GDCLASS(BTComposite, BTTask);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_COMPOSITE_H
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* bt_condition.cpp */
|
||||||
|
|
||||||
|
#include "bt_condition.h"
|
||||||
|
|
||||||
|
String BTCondition::get_configuration_warning() const {
|
||||||
|
String warning = BTTask::get_configuration_warning();
|
||||||
|
if (!warning.empty()) {
|
||||||
|
warning += "\n";
|
||||||
|
}
|
||||||
|
if (get_child_count() != 0) {
|
||||||
|
warning += "Condition can't have child tasks.\n";
|
||||||
|
}
|
||||||
|
return warning;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* bt_condition.h */
|
||||||
|
|
||||||
|
#ifndef BT_CONDITION_H
|
||||||
|
#define BT_CONDITION_H
|
||||||
|
|
||||||
|
#include "bt_task.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
class BTCondition : public BTTask {
|
||||||
|
GDCLASS(BTCondition, BTTask);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_CONDITION_H
|
|
@ -0,0 +1,14 @@
|
||||||
|
/* bt_decorator.cpp */
|
||||||
|
|
||||||
|
#include "bt_decorator.h"
|
||||||
|
|
||||||
|
String BTDecorator::get_configuration_warning() const {
|
||||||
|
String warning = BTTask::get_configuration_warning();
|
||||||
|
if (!warning.empty()) {
|
||||||
|
warning += "\n";
|
||||||
|
}
|
||||||
|
if (get_child_count() != 1) {
|
||||||
|
warning += "Decorator should have a single child task.\n";
|
||||||
|
}
|
||||||
|
return warning;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* bt_decorator.h */
|
||||||
|
|
||||||
|
#ifndef BT_DECORATOR_H
|
||||||
|
#define BT_DECORATOR_H
|
||||||
|
|
||||||
|
#include "bt_task.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
class BTDecorator : public BTTask {
|
||||||
|
GDCLASS(BTDecorator, BTTask)
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_DECORATOR_H
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* bt_parallel.cpp */
|
||||||
|
|
||||||
|
#include "bt_parallel.h"
|
||||||
|
#include "core/class_db.h"
|
||||||
|
|
||||||
|
void BTParallel::_enter() {
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
get_child(i)->cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTParallel::_tick(float p_delta) {
|
||||||
|
int num_succeeded = 0;
|
||||||
|
int num_failed = 0;
|
||||||
|
int return_status = RUNNING;
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
int status = 0;
|
||||||
|
Ref<BTTask> child = get_child(i);
|
||||||
|
if (!repeat && (child->get_status() == FAILURE or child->get_status() == SUCCESS)) {
|
||||||
|
status = child->get_status();
|
||||||
|
} else {
|
||||||
|
status = child->execute(p_delta);
|
||||||
|
}
|
||||||
|
if (status == FAILURE) {
|
||||||
|
num_failed += 1;
|
||||||
|
if (num_failed >= num_failures_required && return_status == RUNNING) {
|
||||||
|
return_status = FAILURE;
|
||||||
|
}
|
||||||
|
} else if (status == SUCCESS) {
|
||||||
|
num_succeeded += 1;
|
||||||
|
if (num_succeeded >= num_successes_required && return_status == RUNNING) {
|
||||||
|
return_status = SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return return_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTParallel::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("get_num_successes_required"), &BTParallel::get_num_successes_required);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_num_successes_required", "p_value"), &BTParallel::set_num_successes_required);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_num_failures_required"), &BTParallel::get_num_failures_required);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_num_failures_required", "p_value"), &BTParallel::set_num_failures_required);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_repeat"), &BTParallel::get_repeat);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_repeat", "p_value"), &BTParallel::set_repeat);
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "num_successes_required"), "set_num_successes_required", "get_num_successes_required");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "num_failures_required"), "set_num_failures_required", "get_num_failures_required");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "repeat"), "set_repeat", "get_repeat");
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* bt_parallel.h */
|
||||||
|
|
||||||
|
#ifndef BT_PARALLEL_H
|
||||||
|
#define BT_PARALLEL_H
|
||||||
|
|
||||||
|
#include "bt_composite.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
class BTParallel : public BTComposite {
|
||||||
|
GDCLASS(BTParallel, BTComposite);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int num_successes_required = 1;
|
||||||
|
int num_failures_required = 1;
|
||||||
|
bool repeat = false;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
virtual void _enter();
|
||||||
|
virtual int _tick(float p_delta);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int get_num_successes_required() const { return num_successes_required; };
|
||||||
|
void set_num_successes_required(int p_value) { num_successes_required = p_value; };
|
||||||
|
int get_num_failures_required() const { return num_failures_required; };
|
||||||
|
void set_num_failures_required(int p_value) { num_failures_required = p_value; };
|
||||||
|
bool get_repeat() const { return repeat; };
|
||||||
|
void set_repeat(bool p_value) { repeat = p_value; };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_PARALLEL_H
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* bt_selector.cpp */
|
||||||
|
|
||||||
|
#include "bt_selector.h"
|
||||||
|
|
||||||
|
void BTSelector::_enter() {
|
||||||
|
last_running_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTSelector::_tick(float p_delta) {
|
||||||
|
int status = FRESH;
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
status = get_child(i)->execute(p_delta);
|
||||||
|
if (status != FAILURE) {
|
||||||
|
last_running_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* bt_selector.h */
|
||||||
|
|
||||||
|
#ifndef BT_SELECTOR_H
|
||||||
|
#define BT_SELECTOR_H
|
||||||
|
|
||||||
|
#include "bt_composite.h"
|
||||||
|
|
||||||
|
class BTSelector : public BTComposite {
|
||||||
|
GDCLASS(BTSelector, BTComposite);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int last_running_idx = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void _enter();
|
||||||
|
virtual int _tick(float p_delta);
|
||||||
|
};
|
||||||
|
#endif // BT_SELECTOR_H
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* bt_sequence.cpp */
|
||||||
|
|
||||||
|
#include "bt_sequence.h"
|
||||||
|
|
||||||
|
void BTSequence::_enter() {
|
||||||
|
last_running_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTSequence::_tick(float p_delta) {
|
||||||
|
int status = FRESH;
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
status = get_child(i)->execute(p_delta);
|
||||||
|
if (status != SUCCESS) {
|
||||||
|
last_running_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/* bt_sequence.h */
|
||||||
|
|
||||||
|
#ifndef BT_SEQUENCE_H
|
||||||
|
#define BT_SEQUENCE_H
|
||||||
|
|
||||||
|
#import "bt_composite.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
|
||||||
|
class BTSequence : public BTComposite {
|
||||||
|
GDCLASS(BTSequence, BTComposite);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int last_running_idx = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void _enter();
|
||||||
|
virtual int _tick(float p_delta);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_SEQUENCE_H
|
|
@ -0,0 +1,281 @@
|
||||||
|
/* bt_task.cpp */
|
||||||
|
|
||||||
|
#include "bt_task.h"
|
||||||
|
|
||||||
|
#include "core/class_db.h"
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "core/script_language.h"
|
||||||
|
#include "core/variant.h"
|
||||||
|
#include "editor/editor_node.h"
|
||||||
|
|
||||||
|
#include "limbo_string_names.h"
|
||||||
|
#include "limbo_utility.h"
|
||||||
|
|
||||||
|
String BTTask::_generate_name() const {
|
||||||
|
if (get_script_instance()) {
|
||||||
|
if (get_script_instance()->has_method(LimboStringNames::get_singleton()->_generate_name)) {
|
||||||
|
return get_script_instance()->call(LimboStringNames::get_singleton()->_generate_name);
|
||||||
|
}
|
||||||
|
String name = get_script_instance()->get_script()->get_path();
|
||||||
|
if (!name.empty()) {
|
||||||
|
// Generate name based on script file
|
||||||
|
name = name.get_basename().get_file();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return get_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
Array BTTask::_get_children() const {
|
||||||
|
Array arr;
|
||||||
|
int num_children = get_child_count();
|
||||||
|
arr.resize(num_children);
|
||||||
|
for (int i = 0; i < num_children; i++) {
|
||||||
|
arr[i] = get_child(i).ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::_set_children(Array p_children) {
|
||||||
|
_children.clear();
|
||||||
|
const int num_children = p_children.size();
|
||||||
|
_children.resize(num_children);
|
||||||
|
for (int i = 0; i < num_children; i++) {
|
||||||
|
Variant task_var = p_children[i];
|
||||||
|
const Ref<BTTask> task_ref = task_var;
|
||||||
|
_children.set(i, task_var);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String BTTask::get_task_name() const {
|
||||||
|
if (_custom_name.empty()) {
|
||||||
|
return _generate_name();
|
||||||
|
}
|
||||||
|
return _custom_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<BTTask> BTTask::get_root() const {
|
||||||
|
const BTTask *task = this;
|
||||||
|
while (!task->is_root()) {
|
||||||
|
task = task->get_parent().ptr();
|
||||||
|
}
|
||||||
|
return Ref<BTTask>(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::set_custom_name(const String &p_name) {
|
||||||
|
if (_custom_name != p_name) {
|
||||||
|
_custom_name = p_name;
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void BTTask::initialize(Object *p_agent, Dictionary p_blackboard) {
|
||||||
|
_agent = p_agent;
|
||||||
|
_blackboard = p_blackboard;
|
||||||
|
for (int i = 0; i < _children.size(); i++) {
|
||||||
|
get_child(i)->initialize(p_agent, p_blackboard);
|
||||||
|
}
|
||||||
|
if (get_script_instance() &&
|
||||||
|
get_script_instance()->has_method(LimboStringNames::get_singleton()->_setup)) {
|
||||||
|
get_script_instance()->call(LimboStringNames::get_singleton()->_setup);
|
||||||
|
} else {
|
||||||
|
_setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<BTTask> BTTask::clone() const {
|
||||||
|
Ref<BTTask> inst = duplicate(true);
|
||||||
|
inst.ptr()->_parent.unref();
|
||||||
|
CRASH_COND(inst.ptr()->get_parent().is_valid());
|
||||||
|
for (int i = 0; i < _children.size(); i++) {
|
||||||
|
Ref<BTTask> c = get_child(i)->clone();
|
||||||
|
c->_parent = inst;
|
||||||
|
inst->_children.set(i, c);
|
||||||
|
}
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTTask::execute(float p_delta) {
|
||||||
|
if (_status == RUNNING) {
|
||||||
|
if (get_script_instance() &&
|
||||||
|
// get_script_instance()->get_script()->is_valid() &&
|
||||||
|
get_script_instance()->has_method(LimboStringNames::get_singleton()->_enter)) {
|
||||||
|
get_script_instance()->call(LimboStringNames::get_singleton()->_enter);
|
||||||
|
} else {
|
||||||
|
_enter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (get_script_instance() &&
|
||||||
|
// get_script_instance()->get_script()->is_valid() &&
|
||||||
|
get_script_instance()->has_method(LimboStringNames::get_singleton()->_tick)) {
|
||||||
|
_status = get_script_instance()->call(LimboStringNames::get_singleton()->_tick, Variant(p_delta));
|
||||||
|
} else {
|
||||||
|
_status = _tick(p_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_status != RUNNING) {
|
||||||
|
if (get_script_instance() &&
|
||||||
|
// get_script_instance()->get_script()->is_valid() &&
|
||||||
|
get_script_instance()->has_method(LimboStringNames::get_singleton()->_exit)) {
|
||||||
|
get_script_instance()->call(LimboStringNames::get_singleton()->_exit);
|
||||||
|
} else {
|
||||||
|
_exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::cancel() {
|
||||||
|
for (int i = 0; i < _children.size(); i++) {
|
||||||
|
get_child(i)->cancel();
|
||||||
|
}
|
||||||
|
if (_status == RUNNING) {
|
||||||
|
if (get_script_instance() &&
|
||||||
|
// get_script_instance()->get_script()->is_valid() &&
|
||||||
|
get_script_instance()->has_method(LimboStringNames::get_singleton()->_exit)) {
|
||||||
|
get_script_instance()->call(LimboStringNames::get_singleton()->_exit);
|
||||||
|
} else {
|
||||||
|
_exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_status = FRESH;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<BTTask> BTTask::get_child(int p_idx) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_idx, _children.size(), nullptr);
|
||||||
|
return _children.get(p_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTTask::get_child_count() const {
|
||||||
|
return _children.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::add_child(Ref<BTTask> p_child) {
|
||||||
|
ERR_FAIL_COND_MSG(p_child.ptr()->get_parent().is_valid(), "p_child already has a parent!");
|
||||||
|
p_child->_parent = Ref<BTTask>(this);
|
||||||
|
_children.push_back(p_child);
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::add_child_at_index(Ref<BTTask> p_child, int p_idx) {
|
||||||
|
ERR_FAIL_COND_MSG(p_child.ptr()->get_parent().is_valid(), "p_child already has a parent!");
|
||||||
|
if (p_idx < 0 || p_idx > _children.size()) {
|
||||||
|
p_idx = _children.size();
|
||||||
|
}
|
||||||
|
_children.insert(p_idx, p_child);
|
||||||
|
p_child->_parent = Ref<BTTask>(this);
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::remove_child(Ref<BTTask> p_child) {
|
||||||
|
int idx = _children.find(p_child);
|
||||||
|
if (idx == -1) {
|
||||||
|
ERR_FAIL_MSG("p_child not found!");
|
||||||
|
} else {
|
||||||
|
_children.remove(idx);
|
||||||
|
p_child->_parent.unref();
|
||||||
|
emit_changed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BTTask::has_child(const Ref<BTTask> &p_child) const {
|
||||||
|
return _children.find(p_child) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BTTask::get_child_index(const Ref<BTTask> &p_child) const {
|
||||||
|
return _children.find(p_child);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<BTTask> BTTask::next_sibling() const {
|
||||||
|
if (_parent.is_valid()) {
|
||||||
|
int idx = _parent->get_child_index(Ref<BTTask>(this));
|
||||||
|
if (idx != -1 && _parent->get_child_count() > (idx + 1)) {
|
||||||
|
return _parent->get_child(idx + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ref<BTTask>();
|
||||||
|
}
|
||||||
|
|
||||||
|
String BTTask::get_configuration_warning() const {
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Texture> BTTask::get_icon() const {
|
||||||
|
return EditorNode::get_singleton()->get_class_icon("BTAction", "Object");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::print_tree(int p_initial_tabs) const {
|
||||||
|
String tabs = "--";
|
||||||
|
for (int i = 0; i < p_initial_tabs; i++) {
|
||||||
|
tabs += "--";
|
||||||
|
}
|
||||||
|
print_line(vformat("%s Name: %s Instance: %s", tabs, get_task_name(), Ref<BTTask>(this)));
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
get_child(i)->print_tree(p_initial_tabs + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTTask::_bind_methods() {
|
||||||
|
// Properties.
|
||||||
|
ClassDB::bind_method(D_METHOD("get_custom_name"), &BTTask::get_custom_name);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_custom_name", "p_name"), &BTTask::set_custom_name);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::STRING, "custom_name"), "set_custom_name", "get_custom_name");
|
||||||
|
ClassDB::bind_method(D_METHOD("get_agent"), &BTTask::get_agent);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "agent", PROPERTY_HINT_NONE, "", 0, "Object"), "", "get_agent");
|
||||||
|
ClassDB::bind_method(D_METHOD("get_blackboard"), &BTTask::get_blackboard);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "blackboard", PROPERTY_HINT_NONE, "", 0, "Dictionary"), "", "get_blackboard");
|
||||||
|
ClassDB::bind_method(D_METHOD("get_parent"), &BTTask::get_parent);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_NONE, "", 0, "BTTask"), "", "get_parent");
|
||||||
|
ClassDB::bind_method(D_METHOD("get_children"), &BTTask::_get_children);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_children", "p_children"), &BTTask::_set_children);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "children", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_children", "get_children");
|
||||||
|
ClassDB::bind_method(D_METHOD("get_status"), &BTTask::get_status);
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "status"), "", "get_status");
|
||||||
|
|
||||||
|
// Virtual methods.
|
||||||
|
ClassDB::bind_method(D_METHOD("_setup"), &BTTask::_setup);
|
||||||
|
BIND_VMETHOD(MethodInfo("_setup"));
|
||||||
|
ClassDB::bind_method(D_METHOD("_enter"), &BTTask::_enter);
|
||||||
|
BIND_VMETHOD(MethodInfo("_enter"))
|
||||||
|
ClassDB::bind_method(D_METHOD("_exit"), &BTTask::_exit);
|
||||||
|
BIND_VMETHOD(MethodInfo("_exit"));
|
||||||
|
ClassDB::bind_method(D_METHOD("_tick", "p_delta"), &BTTask::_tick);
|
||||||
|
BIND_VMETHOD(MethodInfo(Variant::INT, "_tick", PropertyInfo(Variant::REAL, "p_delta")));
|
||||||
|
ClassDB::bind_method(D_METHOD("_generate_name"), &BTTask::_generate_name);
|
||||||
|
BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::STRING, ""), "_generate_name"));
|
||||||
|
ClassDB::bind_method(D_METHOD("_get_configuration_warning"), &BTTask::get_configuration_warning);
|
||||||
|
BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::STRING, ""), "_get_configuration_warning"));
|
||||||
|
ClassDB::bind_method(D_METHOD("_get_icon"), &BTTask::get_icon);
|
||||||
|
BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "_get_icon"));
|
||||||
|
|
||||||
|
// Public Methods.
|
||||||
|
ClassDB::bind_method(D_METHOD("is_root"), &BTTask::is_root);
|
||||||
|
ClassDB::bind_method(D_METHOD("initialize", "p_agent", "p_blackboard"), &BTTask::initialize);
|
||||||
|
ClassDB::bind_method(D_METHOD("clone"), &BTTask::clone);
|
||||||
|
ClassDB::bind_method(D_METHOD("execute", "p_delta"), &BTTask::execute);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_child", "p_idx"), &BTTask::get_child);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_child_count"), &BTTask::get_child_count);
|
||||||
|
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("has_child", "p_child"), &BTTask::has_child);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_child_index", "p_child"), &BTTask::get_child_index);
|
||||||
|
ClassDB::bind_method(D_METHOD("next_sibling"), &BTTask::next_sibling);
|
||||||
|
ClassDB::bind_method(D_METHOD("print_tree", "p_initial_tabs"), &BTTask::print_tree, Variant(0));
|
||||||
|
ClassDB::bind_method(D_METHOD("get_task_name"), &BTTask::get_task_name);
|
||||||
|
|
||||||
|
// Enums.
|
||||||
|
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "FRESH", FRESH);
|
||||||
|
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "RUNNING", RUNNING);
|
||||||
|
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "FAILURE", FAILURE);
|
||||||
|
ClassDB::bind_integer_constant(get_class_static(), "TaskStatus", "SUCCESS", SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
BTTask::BTTask() {
|
||||||
|
_custom_name = String();
|
||||||
|
_agent = nullptr;
|
||||||
|
_blackboard = Dictionary();
|
||||||
|
_children = Vector<Ref<BTTask>>();
|
||||||
|
_status = FRESH;
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/* bt_task.h */
|
||||||
|
|
||||||
|
#ifndef BTTASK_H
|
||||||
|
#define BTTASK_H
|
||||||
|
|
||||||
|
#include "core/array.h"
|
||||||
|
#include "core/dictionary.h"
|
||||||
|
#include "core/reference.h"
|
||||||
|
#include "core/resource.h"
|
||||||
|
#include "core/ustring.h"
|
||||||
|
#include "core/vector.h"
|
||||||
|
#include "scene/resources/texture.h"
|
||||||
|
|
||||||
|
class BTTask : public Resource {
|
||||||
|
GDCLASS(BTTask, Resource);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
FRESH,
|
||||||
|
RUNNING,
|
||||||
|
FAILURE,
|
||||||
|
SUCCESS,
|
||||||
|
};
|
||||||
|
enum TaskType {
|
||||||
|
ACTION,
|
||||||
|
CONDITION,
|
||||||
|
COMPOSITE,
|
||||||
|
DECORATOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
String _custom_name;
|
||||||
|
Object *_agent;
|
||||||
|
Dictionary _blackboard;
|
||||||
|
Ref<BTTask> _parent;
|
||||||
|
Vector<Ref<BTTask>> _children;
|
||||||
|
int _status;
|
||||||
|
|
||||||
|
Array _get_children() const;
|
||||||
|
void _set_children(Array children);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
virtual String _generate_name() const;
|
||||||
|
virtual void _setup(){};
|
||||||
|
virtual void _enter(){};
|
||||||
|
virtual void _exit(){};
|
||||||
|
virtual int _tick(float p_delta) { return FAILURE; };
|
||||||
|
|
||||||
|
public:
|
||||||
|
Object *get_agent() const { return _agent; };
|
||||||
|
Dictionary get_blackboard() const { return _blackboard; };
|
||||||
|
Ref<BTTask> get_parent() const { return _parent; };
|
||||||
|
bool is_root() const { return _parent.is_null(); };
|
||||||
|
Ref<BTTask> get_root() const;
|
||||||
|
int get_status() const { return _status; };
|
||||||
|
String get_custom_name() const { return _custom_name; };
|
||||||
|
void set_custom_name(const String &p_name);
|
||||||
|
String get_task_name() const;
|
||||||
|
|
||||||
|
void initialize(Object *p_agent, Dictionary p_blackboard);
|
||||||
|
virtual Ref<BTTask> clone() const;
|
||||||
|
int execute(float p_delta);
|
||||||
|
void cancel();
|
||||||
|
Ref<BTTask> get_child(int p_idx) const;
|
||||||
|
int get_child_count() const;
|
||||||
|
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);
|
||||||
|
bool has_child(const Ref<BTTask> &p_child) const;
|
||||||
|
int get_child_index(const Ref<BTTask> &p_child) const;
|
||||||
|
Ref<BTTask> next_sibling() const;
|
||||||
|
virtual String get_configuration_warning() const;
|
||||||
|
virtual Ref<Texture> get_icon() const;
|
||||||
|
void print_tree(int p_initial_tabs = 0) const;
|
||||||
|
|
||||||
|
BTTask();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BTTASK_H
|
|
@ -0,0 +1,9 @@
|
||||||
|
# config.py
|
||||||
|
|
||||||
|
|
||||||
|
def can_build(env, platform):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def configure(env):
|
||||||
|
pass
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* limbo_string_names.cpp */
|
||||||
|
|
||||||
|
#include "limbo_string_names.h"
|
||||||
|
|
||||||
|
LimboStringNames *LimboStringNames::singleton = nullptr;
|
||||||
|
|
||||||
|
LimboStringNames::LimboStringNames() {
|
||||||
|
_generate_name = StaticCString::create("_generate_name");
|
||||||
|
_setup = StaticCString::create("_setup");
|
||||||
|
_enter = StaticCString::create("_enter");
|
||||||
|
_exit = StaticCString::create("_exit");
|
||||||
|
_tick = StaticCString::create("_tick");
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* limbo_string_names.h */
|
||||||
|
|
||||||
|
#ifndef LIMBO_STRING_NAMES_H
|
||||||
|
#define LIMBO_STRING_NAMES_H
|
||||||
|
|
||||||
|
#include "core/string_name.h"
|
||||||
|
#include "core/typedefs.h"
|
||||||
|
|
||||||
|
class LimboStringNames {
|
||||||
|
friend void register_limboai_types();
|
||||||
|
friend void unregister_limboai_types();
|
||||||
|
|
||||||
|
static LimboStringNames *singleton;
|
||||||
|
|
||||||
|
static void create() { singleton = memnew(LimboStringNames); }
|
||||||
|
static void free() {
|
||||||
|
memdelete(singleton);
|
||||||
|
singleton = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LimboStringNames();
|
||||||
|
|
||||||
|
public:
|
||||||
|
_FORCE_INLINE_ static LimboStringNames *get_singleton() { return singleton; }
|
||||||
|
|
||||||
|
StringName _generate_name;
|
||||||
|
StringName _setup;
|
||||||
|
StringName _enter;
|
||||||
|
StringName _exit;
|
||||||
|
StringName _tick;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LIMBO_STRING_NAMES_H
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* limbo_utility.cpp */
|
||||||
|
|
||||||
|
#include "limbo_utility.h"
|
||||||
|
#include "core/class_db.h"
|
||||||
|
#include "core/dictionary.h"
|
||||||
|
#include "core/print_string.h"
|
||||||
|
#include "core/project_settings.h"
|
||||||
|
#include "core/variant.h"
|
||||||
|
|
||||||
|
String LimboUtility::get_script_class(const Ref<Script> &p_script) {
|
||||||
|
String a_name = "";
|
||||||
|
Array script_classes = GLOBAL_GET("_global_script_classes");
|
||||||
|
String task_filepath = p_script->get_path();
|
||||||
|
for (int i = 0; i < script_classes.size(); i++) {
|
||||||
|
Dictionary a_class = script_classes[i];
|
||||||
|
Variant class_path = a_class["path"];
|
||||||
|
// print_line(vformat("Type: %s Path: %s TaskPath: %s", class_path.get_type(), class_path, task_filepath));
|
||||||
|
if (a_class["path"] == task_filepath) {
|
||||||
|
a_name = a_class["class"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimboUtility::_bind_methods() {
|
||||||
|
// ClassDB::bind_method(D_METHOD("get_class_name", "p_script"), &LimboUtility::get_class_name);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* limbo_utility.h */
|
||||||
|
|
||||||
|
#ifndef LIMBO_UTILITY_H
|
||||||
|
#define LIMBO_UTILITY_H
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "core/script_language.h"
|
||||||
|
|
||||||
|
class LimboUtility : public Object {
|
||||||
|
GDCLASS(LimboUtility, Object);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static String get_script_class(const Ref<Script> &p_script);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LIMBO_UTILITY_H
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* register_types.cpp */
|
||||||
|
|
||||||
|
#include "register_types.h"
|
||||||
|
|
||||||
|
#include "core/class_db.h"
|
||||||
|
|
||||||
|
#include "bt_action.h"
|
||||||
|
#include "bt_composite.h"
|
||||||
|
#include "bt_condition.h"
|
||||||
|
#include "bt_decorator.h"
|
||||||
|
#include "bt_parallel.h"
|
||||||
|
#include "bt_selector.h"
|
||||||
|
#include "bt_sequence.h"
|
||||||
|
#include "bt_task.h"
|
||||||
|
#include "limbo_string_names.h"
|
||||||
|
#include "limbo_utility.h"
|
||||||
|
|
||||||
|
void register_limboai_types() {
|
||||||
|
ClassDB::register_class<BTTask>();
|
||||||
|
ClassDB::register_class<BTComposite>();
|
||||||
|
ClassDB::register_class<BTDecorator>();
|
||||||
|
ClassDB::register_class<BTAction>();
|
||||||
|
ClassDB::register_class<BTCondition>();
|
||||||
|
ClassDB::register_class<BTSequence>();
|
||||||
|
ClassDB::register_class<BTSelector>();
|
||||||
|
ClassDB::register_class<BTParallel>();
|
||||||
|
LimboStringNames::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void unregister_limboai_types() {
|
||||||
|
LimboStringNames::free();
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
/* register_types.h */
|
||||||
|
|
||||||
|
void register_limboai_types();
|
||||||
|
void unregister_limboai_types();
|
Loading…
Reference in New Issue