Fix drag & drop position in the same branch
Also, refactor get_child_index() into get_index().
This commit is contained in:
parent
6347311749
commit
60012d984b
|
@ -67,6 +67,7 @@ void BTTask::_set_children(Array p_children) {
|
|||
Variant task_var = p_children[i];
|
||||
Ref<BTTask> task_ref = task_var;
|
||||
task_ref->data.parent = this;
|
||||
task_ref->data.index = i;
|
||||
data.children.set(i, task_var);
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +118,7 @@ Ref<BTTask> BTTask::clone() const {
|
|||
Ref<BTTask> c = get_child(i)->clone();
|
||||
if (c.is_valid()) {
|
||||
c->data.parent = inst.ptr();
|
||||
c->data.index = i;
|
||||
inst->data.children.set(i - num_null, c);
|
||||
} else {
|
||||
num_null += 1;
|
||||
|
@ -219,6 +221,7 @@ int BTTask::get_child_count_excluding_comments() const {
|
|||
void BTTask::add_child(Ref<BTTask> p_child) {
|
||||
ERR_FAIL_COND_MSG(p_child->get_parent().is_valid(), "p_child already has a parent!");
|
||||
p_child->data.parent = this;
|
||||
p_child->data.index = data.children.size();
|
||||
data.children.push_back(p_child);
|
||||
emit_changed();
|
||||
}
|
||||
|
@ -230,23 +233,34 @@ void BTTask::add_child_at_index(Ref<BTTask> p_child, int p_idx) {
|
|||
}
|
||||
data.children.insert(p_idx, p_child);
|
||||
p_child->data.parent = this;
|
||||
p_child->data.index = p_idx;
|
||||
for (int i = p_idx + 1; i < data.children.size(); i++) {
|
||||
get_child(i)->data.index = i;
|
||||
}
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTTask::remove_child(Ref<BTTask> p_child) {
|
||||
int idx = data.children.find(p_child);
|
||||
if (idx == -1) {
|
||||
ERR_FAIL_MSG("p_child not found!");
|
||||
} else {
|
||||
ERR_FAIL_COND_MSG(idx == -1, "p_child not found!");
|
||||
data.children.remove_at(idx);
|
||||
p_child->data.parent = nullptr;
|
||||
emit_changed();
|
||||
p_child->data.index = -1;
|
||||
for (int i = idx; i < data.children.size(); i++) {
|
||||
get_child(i)->data.index = i;
|
||||
}
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
void BTTask::remove_child_at_index(int p_idx) {
|
||||
ERR_FAIL_INDEX(p_idx, get_child_count());
|
||||
data.children[p_idx]->data.parent = nullptr;
|
||||
data.children[p_idx]->data.index = -1;
|
||||
data.children.remove_at(p_idx);
|
||||
for (int i = p_idx; i < data.children.size(); i++) {
|
||||
get_child(i)->data.index = i;
|
||||
}
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
bool BTTask::has_child(const Ref<BTTask> &p_child) const {
|
||||
|
@ -264,15 +278,10 @@ bool BTTask::is_descendant_of(const Ref<BTTask> &p_task) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
int BTTask::get_child_index(const Ref<BTTask> &p_child) const {
|
||||
return data.children.find(p_child);
|
||||
}
|
||||
|
||||
Ref<BTTask> BTTask::next_sibling() const {
|
||||
if (data.parent != nullptr) {
|
||||
int idx = data.parent->get_child_index(Ref<BTTask>(this));
|
||||
if (idx != -1 && data.parent->get_child_count() > (idx + 1)) {
|
||||
return data.parent->get_child(idx + 1);
|
||||
if (get_index() != -1 && data.parent->get_child_count() > (get_index() + 1)) {
|
||||
return data.parent->get_child(get_index() + 1);
|
||||
}
|
||||
}
|
||||
return Ref<BTTask>();
|
||||
|
@ -316,7 +325,7 @@ void BTTask::_bind_methods() {
|
|||
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);
|
||||
ClassDB::bind_method(D_METHOD("get_index"), &BTTask::get_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);
|
||||
|
@ -351,12 +360,6 @@ void BTTask::_bind_methods() {
|
|||
}
|
||||
|
||||
BTTask::BTTask() {
|
||||
data.custom_name = String();
|
||||
data.agent = nullptr;
|
||||
data.parent = nullptr;
|
||||
data.children = Vector<Ref<BTTask>>();
|
||||
data.status = FRESH;
|
||||
data.elapsed = 0.0;
|
||||
}
|
||||
|
||||
BTTask::~BTTask() {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "core/object/ref_counted.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "core/typedefs.h"
|
||||
#include "core/variant/array.h"
|
||||
#include "core/variant/binder_common.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
|
@ -55,13 +56,14 @@ private:
|
|||
|
||||
// Avoid namespace pollution in derived classes.
|
||||
struct Data {
|
||||
int index = -1;
|
||||
String custom_name;
|
||||
Node *agent;
|
||||
Node *agent = nullptr;
|
||||
Ref<Blackboard> blackboard;
|
||||
BTTask *parent;
|
||||
BTTask *parent = nullptr;
|
||||
Vector<Ref<BTTask>> children;
|
||||
Status status;
|
||||
double elapsed;
|
||||
Status status = FRESH;
|
||||
double elapsed = 0.0;
|
||||
} data;
|
||||
|
||||
Array _get_children() const;
|
||||
|
@ -116,7 +118,7 @@ public:
|
|||
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;
|
||||
_FORCE_INLINE_ int get_index() const { return data.index; }
|
||||
Ref<BTTask> next_sibling() const;
|
||||
|
||||
void print_tree(int p_initial_tabs = 0) const;
|
||||
|
|
|
@ -108,11 +108,10 @@
|
|||
Returns the number of child tasks not counting [BTComment] tasks.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_child_index" qualifiers="const">
|
||||
<method name="get_index" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="p_child" type="BTTask" />
|
||||
<description>
|
||||
Returns the child task's index. If [code]p_child[/code] is not a child of the task, [code]-1[/code] is returned instead.
|
||||
Returns the task's position in the behavior tree branch. Returns [code]-1[/code] if the task doesn't belong to a task tree, i.e. doesn't have a parent.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_parent" qualifiers="const">
|
||||
|
|
|
@ -105,7 +105,7 @@ void LimboAIEditor::_remove_task(const Ref<BTTask> &p_task) {
|
|||
undo_redo->add_undo_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), task_tree->get_bt()->get_root_task());
|
||||
} else {
|
||||
undo_redo->add_do_method(p_task->get_parent().ptr(), SNAME("remove_child"), p_task);
|
||||
undo_redo->add_undo_method(p_task->get_parent().ptr(), SNAME("add_child_at_index"), p_task, p_task->get_parent()->get_child_index(p_task));
|
||||
undo_redo->add_undo_method(p_task->get_parent().ptr(), SNAME("add_child_at_index"), p_task, p_task->get_index());
|
||||
}
|
||||
undo_redo->add_do_method(task_tree, SNAME("update_tree"));
|
||||
undo_redo->add_undo_method(task_tree, SNAME("update_tree"));
|
||||
|
@ -347,7 +347,7 @@ void LimboAIEditor::_action_selected(int p_id) {
|
|||
Ref<BTTask> sel = task_tree->get_selected();
|
||||
if (sel.is_valid() && sel->get_parent().is_valid()) {
|
||||
Ref<BTTask> parent = sel->get_parent();
|
||||
int idx = parent->get_child_index(sel);
|
||||
int idx = sel->get_index();
|
||||
if (idx > 0 && idx < parent->get_child_count()) {
|
||||
undo_redo->create_action(TTR("Move BT Task"));
|
||||
undo_redo->add_do_method(parent.ptr(), SNAME("remove_child"), sel);
|
||||
|
@ -365,7 +365,7 @@ void LimboAIEditor::_action_selected(int p_id) {
|
|||
Ref<BTTask> sel = task_tree->get_selected();
|
||||
if (sel.is_valid() && sel->get_parent().is_valid()) {
|
||||
Ref<BTTask> parent = sel->get_parent();
|
||||
int idx = parent->get_child_index(sel);
|
||||
int idx = sel->get_index();
|
||||
if (idx >= 0 && idx < (parent->get_child_count() - 1)) {
|
||||
undo_redo->create_action(TTR("Move BT Task"));
|
||||
undo_redo->add_do_method(parent.ptr(), SNAME("remove_child"), sel);
|
||||
|
@ -388,7 +388,7 @@ void LimboAIEditor::_action_selected(int p_id) {
|
|||
parent = sel;
|
||||
}
|
||||
const Ref<BTTask> &sel_dup = sel->clone();
|
||||
undo_redo->add_do_method(parent.ptr(), SNAME("add_child_at_index"), sel_dup, parent->get_child_index(sel) + 1);
|
||||
undo_redo->add_do_method(parent.ptr(), SNAME("add_child_at_index"), sel_dup, sel->get_index() + 1);
|
||||
undo_redo->add_undo_method(parent.ptr(), SNAME("remove_child"), sel_dup);
|
||||
undo_redo->add_do_method(task_tree, SNAME("update_tree"));
|
||||
undo_redo->add_undo_method(task_tree, SNAME("update_tree"));
|
||||
|
@ -408,7 +408,7 @@ void LimboAIEditor::_action_selected(int p_id) {
|
|||
undo_redo->add_do_method(sel.ptr(), SNAME("add_child"), old_root);
|
||||
undo_redo->add_undo_method(sel.ptr(), SNAME("remove_child"), old_root);
|
||||
undo_redo->add_undo_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), old_root);
|
||||
undo_redo->add_undo_method(parent.ptr(), SNAME("add_child_at_index"), sel, parent->get_child_index(sel));
|
||||
undo_redo->add_undo_method(parent.ptr(), SNAME("add_child_at_index"), sel, sel->get_index());
|
||||
undo_redo->add_do_method(task_tree, SNAME("update_tree"));
|
||||
undo_redo->add_undo_method(task_tree, SNAME("update_tree"));
|
||||
undo_redo->commit_action();
|
||||
|
@ -424,7 +424,7 @@ void LimboAIEditor::_action_selected(int p_id) {
|
|||
undo_redo->add_undo_method(task_tree->get_bt().ptr(), SNAME("set_root_task"), task_tree->get_bt()->get_root_task());
|
||||
} else {
|
||||
undo_redo->add_do_method(sel->get_parent().ptr(), SNAME("remove_child"), sel);
|
||||
undo_redo->add_undo_method(sel->get_parent().ptr(), SNAME("add_child_at_index"), sel, sel->get_parent()->get_child_index(sel));
|
||||
undo_redo->add_undo_method(sel->get_parent().ptr(), SNAME("add_child_at_index"), sel, sel->get_index());
|
||||
}
|
||||
undo_redo->add_do_method(task_tree, SNAME("update_tree"));
|
||||
undo_redo->add_undo_method(task_tree, SNAME("update_tree"));
|
||||
|
@ -442,9 +442,9 @@ void LimboAIEditor::_on_probability_edited(double p_value) {
|
|||
Ref<BTProbabilitySelector> probability_selector = selected->get_parent();
|
||||
ERR_FAIL_COND(probability_selector.is_null());
|
||||
if (percent_mode->is_pressed()) {
|
||||
probability_selector->set_probability(probability_selector->get_child_index(selected), p_value * 0.01);
|
||||
probability_selector->set_probability(selected->get_index(), p_value * 0.01);
|
||||
} else {
|
||||
probability_selector->set_weight(probability_selector->get_child_index(selected), p_value);
|
||||
probability_selector->set_weight(selected->get_index(), p_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ void LimboAIEditor::_update_probability_edit() {
|
|||
ERR_FAIL_COND(selected.is_null());
|
||||
Ref<BTProbabilitySelector> prob = selected->get_parent();
|
||||
ERR_FAIL_COND(prob.is_null());
|
||||
double others_weight = prob->get_total_weight() - prob->get_weight(prob->get_child_index(selected));
|
||||
double others_weight = prob->get_total_weight() - prob->get_weight(selected->get_index());
|
||||
bool cannot_edit_percent = others_weight == 0.0;
|
||||
percent_mode->set_disabled(cannot_edit_percent);
|
||||
if (cannot_edit_percent && percent_mode->is_pressed()) {
|
||||
|
@ -611,15 +611,21 @@ void LimboAIEditor::_on_task_dragged(Ref<BTTask> p_task, Ref<BTTask> p_to_task,
|
|||
if (p_type == 0) {
|
||||
undo_redo->add_do_method(p_to_task.ptr(), SNAME("add_child"), p_task);
|
||||
undo_redo->add_undo_method(p_to_task.ptr(), SNAME("remove_child"), p_task);
|
||||
} else if (p_type == -1) {
|
||||
undo_redo->add_do_method(p_to_task->get_parent().ptr(), SNAME("add_child_at_index"), p_task, p_to_task->get_parent()->get_child_index(p_to_task));
|
||||
} else {
|
||||
int drop_idx = p_to_task->get_index();
|
||||
if (p_to_task->get_parent() == p_task->get_parent() && drop_idx > p_task->get_index()) {
|
||||
drop_idx -= 1;
|
||||
}
|
||||
if (p_type == -1) {
|
||||
undo_redo->add_do_method(p_to_task->get_parent().ptr(), SNAME("add_child_at_index"), p_task, drop_idx);
|
||||
undo_redo->add_undo_method(p_to_task->get_parent().ptr(), SNAME("remove_child"), p_task);
|
||||
} else if (p_type == 1) {
|
||||
undo_redo->add_do_method(p_to_task->get_parent().ptr(), SNAME("add_child_at_index"), p_task, p_to_task->get_parent()->get_child_index(p_to_task) + 1);
|
||||
undo_redo->add_do_method(p_to_task->get_parent().ptr(), SNAME("add_child_at_index"), p_task, drop_idx + 1);
|
||||
undo_redo->add_undo_method(p_to_task->get_parent().ptr(), SNAME("remove_child"), p_task);
|
||||
}
|
||||
}
|
||||
|
||||
undo_redo->add_undo_method(p_task->get_parent().ptr(), "add_child_at_index", p_task, p_task->get_parent()->get_child_index(p_task));
|
||||
undo_redo->add_undo_method(p_task->get_parent().ptr(), "add_child_at_index", p_task, p_task->get_index());
|
||||
|
||||
undo_redo->add_do_method(task_tree, SNAME("update_tree"));
|
||||
undo_redo->add_undo_method(task_tree, SNAME("update_tree"));
|
||||
|
|
|
@ -223,7 +223,7 @@ double TaskTree::get_selected_probability_weight() const {
|
|||
ERR_FAIL_COND_V(selected.is_null(), 0.0);
|
||||
Ref<BTProbabilitySelector> probability_selector = selected->get_parent();
|
||||
ERR_FAIL_COND_V(probability_selector.is_null(), 0.0);
|
||||
return probability_selector->get_weight(probability_selector->get_child_index(selected));
|
||||
return probability_selector->get_weight(selected->get_index());
|
||||
}
|
||||
|
||||
double TaskTree::get_selected_probability_percent() const {
|
||||
|
@ -231,7 +231,7 @@ double TaskTree::get_selected_probability_percent() const {
|
|||
ERR_FAIL_COND_V(selected.is_null(), 0.0);
|
||||
Ref<BTProbabilitySelector> probability_selector = selected->get_parent();
|
||||
ERR_FAIL_COND_V(probability_selector.is_null(), 0.0);
|
||||
return probability_selector->get_probability(probability_selector->get_child_index(selected)) * 100.0;
|
||||
return probability_selector->get_probability(selected->get_index()) * 100.0;
|
||||
}
|
||||
|
||||
bool TaskTree::selected_has_probability() const {
|
||||
|
|
|
@ -33,6 +33,8 @@ TEST_CASE("[Modules][LimboAI] BTTask") {
|
|||
REQUIRE(task->get_child_count() == 2);
|
||||
REQUIRE(task->get_child(0) == child1);
|
||||
REQUIRE(task->get_child(1) == child3);
|
||||
CHECK(child1->get_index() == 0);
|
||||
CHECK(child3->get_index() == 1);
|
||||
|
||||
// * add_child_at_index
|
||||
Ref<BTTask> child2 = memnew(BTTask);
|
||||
|
@ -57,14 +59,14 @@ TEST_CASE("[Modules][LimboAI] BTTask") {
|
|||
Ref<BTTask> other = memnew(BTTask);
|
||||
CHECK_FALSE(task->has_child(other));
|
||||
}
|
||||
SUBCASE("Test get_child_index()") {
|
||||
CHECK(task->get_child_index(child1) == 0);
|
||||
CHECK(task->get_child_index(child2) == 1);
|
||||
CHECK(task->get_child_index(child3) == 2);
|
||||
SUBCASE("Test get_index()") {
|
||||
CHECK(child1->get_index() == 0);
|
||||
CHECK(child2->get_index() == 1);
|
||||
CHECK(child3->get_index() == 2);
|
||||
}
|
||||
SUBCASE("Test get_child_index() with an out-of-hierarchy task") {
|
||||
SUBCASE("Test get_index() with an out-of-hierarchy task") {
|
||||
Ref<BTTask> other = memnew(BTTask);
|
||||
CHECK(task->get_child_index(other) == -1);
|
||||
CHECK(other->get_index() == -1);
|
||||
}
|
||||
SUBCASE("Test is_descendant_of()") {
|
||||
Ref<BTTask> grandchild = memnew(BTTask);
|
||||
|
@ -83,13 +85,22 @@ TEST_CASE("[Modules][LimboAI] BTTask") {
|
|||
REQUIRE(task->get_child_count() == 2);
|
||||
CHECK(task->get_child(0) == child1);
|
||||
CHECK(task->get_child(1) == child3);
|
||||
CHECK(child1->get_index() == 0);
|
||||
CHECK(child2->get_index() == -1);
|
||||
CHECK(child3->get_index() == 1);
|
||||
|
||||
task->remove_child(child3);
|
||||
REQUIRE(task->get_child_count() == 1);
|
||||
CHECK(task->get_child(0) == child1);
|
||||
CHECK(child1->get_index() == 0);
|
||||
CHECK(child2->get_index() == -1);
|
||||
CHECK(child3->get_index() == -1);
|
||||
|
||||
task->remove_child(child1);
|
||||
REQUIRE(task->get_child_count() == 0);
|
||||
CHECK(child1->get_index() == -1);
|
||||
CHECK(child2->get_index() == -1);
|
||||
CHECK(child3->get_index() == -1);
|
||||
}
|
||||
SUBCASE("Test remove_child() with an out-of-hierarchy task") {
|
||||
Ref<BTTask> other = memnew(BTTask);
|
||||
|
@ -98,18 +109,27 @@ TEST_CASE("[Modules][LimboAI] BTTask") {
|
|||
task->remove_child(other);
|
||||
ERR_PRINT_ON;
|
||||
}
|
||||
SUBCASE("Test remove_at_index()") {
|
||||
SUBCASE("Test remove_child_at_index()") {
|
||||
task->remove_child_at_index(1);
|
||||
REQUIRE(task->get_child_count() == 2);
|
||||
CHECK(task->get_child(0) == child1);
|
||||
CHECK(task->get_child(1) == child3);
|
||||
CHECK(child1->get_index() == 0);
|
||||
CHECK(child2->get_index() == -1);
|
||||
CHECK(child3->get_index() == 1);
|
||||
|
||||
task->remove_child_at_index(1);
|
||||
REQUIRE(task->get_child_count() == 1);
|
||||
CHECK(task->get_child(0) == child1);
|
||||
CHECK(child1->get_index() == 0);
|
||||
CHECK(child2->get_index() == -1);
|
||||
CHECK(child3->get_index() == -1);
|
||||
|
||||
task->remove_child_at_index(0);
|
||||
REQUIRE(task->get_child_count() == 0);
|
||||
CHECK(child1->get_index() == -1);
|
||||
CHECK(child2->get_index() == -1);
|
||||
CHECK(child3->get_index() == -1);
|
||||
}
|
||||
SUBCASE("Test remove_child_at_index() with an out-of-bounds index") {
|
||||
// * Must not crash.
|
||||
|
|
Loading…
Reference in New Issue