Add BTProbabilitySelector class
This commit is contained in:
parent
c94073fb39
commit
55e0b7404c
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* bt_probability_selector.cpp
|
||||||
|
* =============================================================================
|
||||||
|
* Copyright 2021-2023 Serhii Snitsaruk
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
* =============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bt_probability_selector.h"
|
||||||
|
|
||||||
|
#include "modules/limboai/bt/tasks/bt_task.h"
|
||||||
|
|
||||||
|
#include "core/error/error_macros.h"
|
||||||
|
|
||||||
|
double BTProbabilitySelector::get_weight(int p_index) const {
|
||||||
|
return _get_weight(p_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTProbabilitySelector::set_weight(int p_index, double p_weight) {
|
||||||
|
_set_weight(p_index, p_weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
double BTProbabilitySelector::get_probability(int p_index) const {
|
||||||
|
ERR_FAIL_INDEX_V(p_index, get_child_count(), 0.0);
|
||||||
|
return _get_weight(p_index) / _get_total_weight();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTProbabilitySelector::set_probability(int p_index, double p_probability) {
|
||||||
|
ERR_FAIL_INDEX(p_index, get_child_count());
|
||||||
|
ERR_FAIL_COND(p_probability < 0.0);
|
||||||
|
ERR_FAIL_COND(p_probability > 1.0);
|
||||||
|
ERR_FAIL_COND(p_probability > 0.99 && get_child_count() > 1);
|
||||||
|
|
||||||
|
double others_total = _get_total_weight() - _get_weight(p_index);
|
||||||
|
double others_probability = 1.0 - p_probability;
|
||||||
|
double new_total = others_total / others_probability;
|
||||||
|
_set_weight(p_index, new_total - others_total);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTProbabilitySelector::_enter() {
|
||||||
|
_select_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTProbabilitySelector::_exit() {
|
||||||
|
failed_tasks.clear();
|
||||||
|
selected_task.unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
BT::Status BTProbabilitySelector::_tick(double p_delta) {
|
||||||
|
while (selected_task.is_valid()) {
|
||||||
|
Status status = selected_task->execute(p_delta);
|
||||||
|
if (status == FAILURE) {
|
||||||
|
failed_tasks.insert(selected_task);
|
||||||
|
_select_task();
|
||||||
|
} else { // RUNNING or SUCCESS
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTProbabilitySelector::_select_task() {
|
||||||
|
selected_task.unref();
|
||||||
|
|
||||||
|
double remaining_tasks_weight = _get_total_weight();
|
||||||
|
for (const Ref<BTTask> &task : failed_tasks) {
|
||||||
|
remaining_tasks_weight -= _get_weight(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
double roll = Math::random(0.0, remaining_tasks_weight);
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
Ref<BTTask> task = get_child(i);
|
||||||
|
if (failed_tasks.has(task)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double weight = _get_weight(i);
|
||||||
|
if (weight == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (roll > weight) {
|
||||||
|
roll -= weight;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
selected_task = task;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//***** Godot
|
||||||
|
|
||||||
|
void BTProbabilitySelector::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("get_weight", "p_index"), &BTProbabilitySelector::get_weight);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_weight", "p_index", "p_weight"), &BTProbabilitySelector::set_weight);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_probability", "p_index"), &BTProbabilitySelector::get_probability);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_probability", "p_index", "p_probability"), &BTProbabilitySelector::set_probability);
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/**
|
||||||
|
* bt_probability_selector.h
|
||||||
|
* =============================================================================
|
||||||
|
* Copyright 2021-2023 Serhii Snitsaruk
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
* =============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BT_PROBABILITY_SELECTOR_H
|
||||||
|
#define BT_PROBABILITY_SELECTOR_H
|
||||||
|
|
||||||
|
#include "modules/limboai/bt/tasks/bt_composite.h"
|
||||||
|
|
||||||
|
#include "core/typedefs.h"
|
||||||
|
|
||||||
|
class BTProbabilitySelector : public BTComposite {
|
||||||
|
GDCLASS(BTProbabilitySelector, BTComposite);
|
||||||
|
TASK_CATEGORY(Composites);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HashSet<Ref<BTTask>> failed_tasks;
|
||||||
|
Ref<BTTask> selected_task;
|
||||||
|
|
||||||
|
void _select_task();
|
||||||
|
|
||||||
|
_FORCE_INLINE_ double _get_weight(int p_index) const { return get_child(p_index)->get_meta(SNAME("_weight_"), 1.0); }
|
||||||
|
_FORCE_INLINE_ double _get_weight(Ref<BTTask> p_task) const { return p_task->get_meta(SNAME("_weight_"), 1.0); }
|
||||||
|
_FORCE_INLINE_ void _set_weight(int p_index, double p_weight) { get_child(p_index)->set_meta(SNAME("_weight_"), Variant(p_weight)); }
|
||||||
|
_FORCE_INLINE_ double _get_total_weight() const {
|
||||||
|
double total = 0.0;
|
||||||
|
for (int i = 0; i < get_child_count(); i++) {
|
||||||
|
total += _get_weight(i);
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
virtual void _enter() override;
|
||||||
|
virtual void _exit() override;
|
||||||
|
virtual Status _tick(double p_delta) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
double get_weight(int p_index) const;
|
||||||
|
void set_weight(int p_index, double p_weight);
|
||||||
|
|
||||||
|
double get_probability(int p_index) const;
|
||||||
|
void set_probability(int p_index, double p_probability);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BT_PROBABILITY_SELECTOR_H
|
|
@ -84,6 +84,7 @@ def get_doc_classes():
|
||||||
"BTPlayAnimation",
|
"BTPlayAnimation",
|
||||||
"BTPlayer",
|
"BTPlayer",
|
||||||
"BTProbability",
|
"BTProbability",
|
||||||
|
"BTProbabilitySelector",
|
||||||
"BTRandomSelector",
|
"BTRandomSelector",
|
||||||
"BTRandomSequence",
|
"BTRandomSequence",
|
||||||
"BTRandomWait",
|
"BTRandomWait",
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "bt/tasks/composites/bt_dynamic_selector.h"
|
#include "bt/tasks/composites/bt_dynamic_selector.h"
|
||||||
#include "bt/tasks/composites/bt_dynamic_sequence.h"
|
#include "bt/tasks/composites/bt_dynamic_sequence.h"
|
||||||
#include "bt/tasks/composites/bt_parallel.h"
|
#include "bt/tasks/composites/bt_parallel.h"
|
||||||
|
#include "bt/tasks/composites/bt_probability_selector.h"
|
||||||
#include "bt/tasks/composites/bt_random_selector.h"
|
#include "bt/tasks/composites/bt_random_selector.h"
|
||||||
#include "bt/tasks/composites/bt_random_sequence.h"
|
#include "bt/tasks/composites/bt_random_sequence.h"
|
||||||
#include "bt/tasks/composites/bt_selector.h"
|
#include "bt/tasks/composites/bt_selector.h"
|
||||||
|
@ -131,6 +132,7 @@ void initialize_limboai_module(ModuleInitializationLevel p_level) {
|
||||||
LIMBO_REGISTER_TASK(BTParallel);
|
LIMBO_REGISTER_TASK(BTParallel);
|
||||||
LIMBO_REGISTER_TASK(BTDynamicSequence);
|
LIMBO_REGISTER_TASK(BTDynamicSequence);
|
||||||
LIMBO_REGISTER_TASK(BTDynamicSelector);
|
LIMBO_REGISTER_TASK(BTDynamicSelector);
|
||||||
|
LIMBO_REGISTER_TASK(BTProbabilitySelector);
|
||||||
LIMBO_REGISTER_TASK(BTRandomSequence);
|
LIMBO_REGISTER_TASK(BTRandomSequence);
|
||||||
LIMBO_REGISTER_TASK(BTRandomSelector);
|
LIMBO_REGISTER_TASK(BTRandomSelector);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue