Compare commits
5 Commits
f1af947060
...
0f9c566a63
Author | SHA1 | Date |
---|---|---|
Serhii Snitsaruk | 0f9c566a63 | |
Serhii Snitsaruk | 86d31f5f00 | |
Serhii Snitsaruk | 5f40d38f8d | |
Serhii Snitsaruk | 800bc8f16d | |
Serhii Snitsaruk | 40acd04eb9 |
|
@ -10,9 +10,9 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## ArrivePos: Arrive to a position, with a bias to horizontal movement.
|
## Moves the agent to the specified position, favoring horizontal movement. [br]
|
||||||
## Returns SUCCESS when close to the target position (see tolerance);
|
## Returns [code]SUCCESS[/code] when close to the target position (see [member tolerance]);
|
||||||
## otherwise returns RUNNING.
|
## otherwise returns [code]RUNNING[/code].
|
||||||
|
|
||||||
## Blackboard variable that stores the target position (Vector2)
|
## Blackboard variable that stores the target position (Vector2)
|
||||||
@export var target_position_var := &"pos"
|
@export var target_position_var := &"pos"
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## BackAway
|
## Moves the agent in the opposite direction of its current facing. [br]
|
||||||
## Returns RUNNING always.
|
## Returns [code]RUNNING[/code] always.
|
||||||
|
|
||||||
## Blackboard variable that stores desired speed.
|
## Blackboard variable that stores desired speed.
|
||||||
@export var speed_var: StringName = &"speed"
|
@export var speed_var: StringName = &"speed"
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## FaceTarget and return SUCCESS.
|
## Flips the agent to face the target, returning [code]SUCCESS[/code]. [br]
|
||||||
## Returns FAILURE if target is not a valid Node2D instance.
|
## Returns [code]FAILURE[/code] if [member target_var] is not a valid [Node2D] instance.
|
||||||
|
|
||||||
## Blackboard variable that stores our target (expecting Node2D).
|
## Blackboard variable that stores our target (expecting Node2D).
|
||||||
@export var target_var: StringName = &"target"
|
@export var target_var: StringName = &"target"
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## Get first node in group and save it to the blackboard.
|
## Stores the first node in the [member group] on the blackboard, returning [code]SUCCESS[/code]. [br]
|
||||||
## Returns FAILURE if group contains 0 nodes.
|
## Returns [code]FAILURE[/code] if the group contains 0 nodes.
|
||||||
|
|
||||||
## Name of the SceneTree group.
|
## Name of the SceneTree group.
|
||||||
@export var group: StringName
|
@export var group: StringName
|
||||||
|
|
|
@ -10,11 +10,10 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTCondition
|
extends BTCondition
|
||||||
|
|
||||||
## InRange condition checks if the agent is within a range of target,
|
## InRange condition checks if the agent is within a range of target,
|
||||||
## defined by distance_min and distance_max.
|
## defined by [member distance_min] and [member distance_max]. [br]
|
||||||
## Returns SUCCESS if the agent is within the defined range;
|
## Returns [code]SUCCESS[/code] if the agent is within the given range;
|
||||||
## otherwise, returns FAILURE.
|
## otherwise, returns [code]FAILURE[/code].
|
||||||
|
|
||||||
## Minimum distance to target.
|
## Minimum distance to target.
|
||||||
@export var distance_min: float
|
@export var distance_min: float
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTCondition
|
extends BTCondition
|
||||||
## IsAlignedWithTarget
|
## Checks if the agent is horizontally aligned with the target. [br]
|
||||||
## Returns SUCCESS if the agent is horizontally aligned with the target.
|
## Returns [code]SUCCESS[/code] if the agent is horizontally aligned with the target.
|
||||||
## Returns FAILURE if not aligned or if target is not a valid node instance.
|
## Returns [code]FAILURE[/code] if not aligned or if target is not a valid node instance.
|
||||||
|
|
||||||
|
|
||||||
@export var target_var: StringName = &"target"
|
@export var target_var: StringName = &"target"
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## MoveForward: Applies velocity each tick until duration is exceeded.
|
## Applies velocity in the direction the agent is facing on each tick
|
||||||
## Returns SUCCESS if elapsed time exceeded duration.
|
## until the [member duration] is exceeded. [br]
|
||||||
## Returns RUNNING if elapsed time didn't exceed duration.
|
## Returns [code]SUCCESS[/code] if the elapsed time exceeds [member duration]. [br]
|
||||||
|
## Returns [code]RUNNING[/code] if the elapsed time does not exceed [member duration]. [br]
|
||||||
|
|
||||||
## Blackboard variable that stores desired speed.
|
## Blackboard variable that stores desired speed.
|
||||||
@export var speed_var: StringName = &"speed"
|
@export var speed_var: StringName = &"speed"
|
||||||
|
|
|
@ -10,11 +10,10 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## Pursue: Move towards target until agent is flanking it.
|
## Move towards the target until the agent is flanking it. [br]
|
||||||
##
|
## Returns [code]RUNNING[/code] while moving towards the target but not yet at the desired position. [br]
|
||||||
## Returns RUNNING, while moving towards target but not yet at the desired position.
|
## Returns [code]SUCCESS[/code] when at the desired position relative to the target (flanking it). [br]
|
||||||
## Returns SUCCESS, when at the desired position from target (flanking it).
|
## Returns [code]FAILURE[/code] if the target is not a valid [Node2D] instance. [br]
|
||||||
## Returns FAILURE, if target is not a valid Node2D instance.
|
|
||||||
|
|
||||||
## How close should the agent be to the desired position to return SUCCESS.
|
## How close should the agent be to the desired position to return SUCCESS.
|
||||||
const TOLERANCE := 30.0
|
const TOLERANCE := 30.0
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
#*
|
#*
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## SelectFlankingPos on the side of a target, and return SUCCESS.
|
## Selects a position on the target's side and stores it on the
|
||||||
## Returns FAILURE, if the target is not valid.
|
## blackboard, returning [code]SUCCESS[/code]. [br]
|
||||||
|
## Returns [code]FAILURE[/code] if the target is not valid.
|
||||||
|
|
||||||
enum AgentSide {
|
enum AgentSide {
|
||||||
CLOSEST,
|
CLOSEST,
|
||||||
|
@ -71,4 +72,3 @@ func _tick(_delta: float) -> Status:
|
||||||
flank_pos = target.global_position - offset
|
flank_pos = target.global_position - offset
|
||||||
blackboard.set_var(position_var, flank_pos)
|
blackboard.set_var(position_var, flank_pos)
|
||||||
return SUCCESS
|
return SUCCESS
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@tool
|
@tool
|
||||||
extends BTAction
|
extends BTAction
|
||||||
## SelectRandomNearbyPos: Select a position nearby within specified range.
|
## Selects a random position nearby within the specified range and stores it on the blackboard. [br]
|
||||||
## Returns SUCCESS.
|
## Returns [code]SUCCESS[/code].
|
||||||
|
|
||||||
## Minimum distance to the desired position.
|
## Minimum distance to the desired position.
|
||||||
@export var range_min: float = 300.0
|
@export var range_min: float = 300.0
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#include "editor/editor_help.h"
|
#include "editor/editor_help.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_paths.h"
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
|
#include "editor/themes/editor_scale.h"
|
||||||
#include "scene/gui/check_box.h"
|
#include "scene/gui/check_box.h"
|
||||||
#endif // LIMBO_MODULE
|
#endif // LIMBO_MODULE
|
||||||
|
|
||||||
|
@ -57,30 +57,86 @@ using namespace godot;
|
||||||
void TaskButton::_bind_methods() {
|
void TaskButton::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Control *TaskButton::_do_make_tooltip(const String &p_text) const {
|
Control *TaskButton::_do_make_tooltip() const {
|
||||||
#ifdef LIMBOAI_MODULE
|
#ifdef LIMBOAI_MODULE
|
||||||
EditorHelpBit *help_bit = memnew(EditorHelpBit);
|
String help_symbol;
|
||||||
help_bit->set_content_height_limits(1, 360 * EDSCALE);
|
bool is_resource = task_meta.begins_with("res://");
|
||||||
|
|
||||||
String help_text;
|
if (is_resource) {
|
||||||
if (!p_text.is_empty()) {
|
help_symbol = "class|\"" + task_meta.lstrip("res://") + "\"|";
|
||||||
help_text = p_text;
|
|
||||||
} else {
|
} else {
|
||||||
help_text = "[i]" + TTR("No description.") + "[/i]";
|
help_symbol = "class|" + task_meta + "|";
|
||||||
}
|
}
|
||||||
|
|
||||||
help_bit->set_custom_text(String(), String(), help_text);
|
EditorHelpBit *help_bit = memnew(EditorHelpBit(help_symbol));
|
||||||
|
help_bit->set_content_height_limits(1, 360 * EDSCALE);
|
||||||
|
|
||||||
return help_bit;
|
String desc = _module_get_help_description(task_meta);
|
||||||
|
if (desc.is_empty() && is_resource) {
|
||||||
|
// ! HACK: Force documentation parsing.
|
||||||
|
Ref<Script> s = ResourceLoader::load(task_meta);
|
||||||
|
if (s.is_valid()) {
|
||||||
|
Vector<DocData::ClassDoc> docs = s->get_documentation();
|
||||||
|
for (int i = 0; i < docs.size(); i++) {
|
||||||
|
const DocData::ClassDoc &doc = docs.get(i);
|
||||||
|
EditorHelp::get_doc_data()->add_doc(doc);
|
||||||
|
}
|
||||||
|
desc = _module_get_help_description(task_meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (desc.is_empty() && help_bit->get_description().is_empty()) {
|
||||||
|
desc = "[i]" + TTR("No description.") + "[/i]";
|
||||||
|
}
|
||||||
|
if (!desc.is_empty()) {
|
||||||
|
help_bit->set_description(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<TaskButton *>(this));
|
||||||
#endif // LIMBOAI_MODULE
|
#endif // LIMBOAI_MODULE
|
||||||
|
|
||||||
#ifdef LIMBOAI_GDEXTENSION
|
#ifdef LIMBOAI_GDEXTENSION
|
||||||
// TODO: When we figure out how to retrieve documentation in GDEXTENSION, should add a tooltip control here.
|
// TODO: When we figure out how to retrieve documentation in GDEXTENSION, should add a tooltip control here.
|
||||||
#endif // LIMBOAI_GDEXTENSION
|
#endif // LIMBOAI_GDEXTENSION
|
||||||
|
|
||||||
return nullptr;
|
return memnew(Control); // Make the standard tooltip invisible.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIMBOAI_MODULE
|
||||||
|
|
||||||
|
String TaskButton::_module_get_help_description(const String &p_class_or_script_path) const {
|
||||||
|
String descr;
|
||||||
|
|
||||||
|
DocTools *dd = EditorHelp::get_doc_data();
|
||||||
|
HashMap<String, DocData::ClassDoc>::Iterator E;
|
||||||
|
|
||||||
|
if (p_class_or_script_path.begins_with("res://")) {
|
||||||
|
// Try to find by script path.
|
||||||
|
E = dd->class_list.find(vformat("\"%s\"", p_class_or_script_path.trim_prefix("res://")));
|
||||||
|
if (!E) {
|
||||||
|
// Try to guess global script class from filename.
|
||||||
|
String maybe_class_name = p_class_or_script_path.get_file().get_basename().to_pascal_case();
|
||||||
|
E = dd->class_list.find(maybe_class_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to find core class or global class.
|
||||||
|
E = dd->class_list.find(p_class_or_script_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (E) {
|
||||||
|
if (E->value.description.is_empty()) {
|
||||||
|
descr = DTR(E->value.brief_description);
|
||||||
|
} else {
|
||||||
|
descr = DTR(E->value.description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Documentation tooltips are only available in the module variant. Find a way to show em in GDExtension.
|
||||||
|
|
||||||
|
return descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LIMBOAI_MODULE
|
||||||
|
|
||||||
TaskButton::TaskButton() {
|
TaskButton::TaskButton() {
|
||||||
set_focus_mode(FOCUS_NONE);
|
set_focus_mode(FOCUS_NONE);
|
||||||
}
|
}
|
||||||
|
@ -125,11 +181,12 @@ void TaskPaletteSection::set_filter(String p_filter_text) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskPaletteSection::add_task_button(const String &p_name, const Ref<Texture> &icon, const String &p_tooltip, Variant p_meta) {
|
void TaskPaletteSection::add_task_button(const String &p_name, const Ref<Texture> &icon, const String &p_meta) {
|
||||||
TaskButton *btn = memnew(TaskButton);
|
TaskButton *btn = memnew(TaskButton);
|
||||||
btn->set_text(p_name);
|
btn->set_text(p_name);
|
||||||
BUTTON_SET_ICON(btn, icon);
|
BUTTON_SET_ICON(btn, icon);
|
||||||
btn->set_tooltip_text(p_tooltip);
|
btn->set_tooltip_text("dummy_text"); // Force tooltip to be shown.
|
||||||
|
btn->set_task_meta(p_meta);
|
||||||
btn->add_theme_constant_override(LW_NAME(icon_max_width), 16 * EDSCALE); // Force user icons to be of the proper size.
|
btn->add_theme_constant_override(LW_NAME(icon_max_width), 16 * EDSCALE); // Force user icons to be of the proper size.
|
||||||
btn->connect(LW_NAME(pressed), callable_mp(this, &TaskPaletteSection::_on_task_button_pressed).bind(p_meta));
|
btn->connect(LW_NAME(pressed), callable_mp(this, &TaskPaletteSection::_on_task_button_pressed).bind(p_meta));
|
||||||
btn->connect(LW_NAME(gui_input), callable_mp(this, &TaskPaletteSection::_on_task_button_gui_input).bind(p_meta));
|
btn->connect(LW_NAME(gui_input), callable_mp(this, &TaskPaletteSection::_on_task_button_gui_input).bind(p_meta));
|
||||||
|
@ -422,11 +479,10 @@ void TaskPalette::refresh() {
|
||||||
|
|
||||||
TaskPaletteSection *sec = memnew(TaskPaletteSection());
|
TaskPaletteSection *sec = memnew(TaskPaletteSection());
|
||||||
sec->set_category_name(cat);
|
sec->set_category_name(cat);
|
||||||
for (String task_meta : tasks) {
|
for (const String &task_meta : tasks) {
|
||||||
Ref<Texture2D> icon = LimboUtility::get_singleton()->get_task_icon(task_meta);
|
Ref<Texture2D> icon = LimboUtility::get_singleton()->get_task_icon(task_meta);
|
||||||
|
|
||||||
String tname;
|
String tname;
|
||||||
String descr;
|
|
||||||
|
|
||||||
if (task_meta.begins_with("res:")) {
|
if (task_meta.begins_with("res:")) {
|
||||||
if (filter_settings.type_filter == FilterSettings::TYPE_CORE) {
|
if (filter_settings.type_filter == FilterSettings::TYPE_CORE) {
|
||||||
|
@ -440,34 +496,7 @@ void TaskPalette::refresh() {
|
||||||
tname = task_meta.trim_prefix("BT");
|
tname = task_meta.trim_prefix("BT");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LIMBOAI_MODULE
|
sec->add_task_button(tname, icon, task_meta);
|
||||||
// Get documentation.
|
|
||||||
DocTools *dd = EditorHelp::get_doc_data();
|
|
||||||
HashMap<String, DocData::ClassDoc>::Iterator E;
|
|
||||||
// Try-find core class.
|
|
||||||
E = dd->class_list.find(task_meta);
|
|
||||||
if (!E) {
|
|
||||||
// Try to find by script filename.
|
|
||||||
E = dd->class_list.find(vformat("\"%s\"", task_meta.trim_prefix("res://")));
|
|
||||||
}
|
|
||||||
if (!E) {
|
|
||||||
// Try-find global script class.
|
|
||||||
String maybe_class_name = task_meta.get_file().get_basename().to_pascal_case();
|
|
||||||
E = dd->class_list.find(maybe_class_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (E) {
|
|
||||||
if (E->value.description.is_empty() || E->value.description.length() > 1400) {
|
|
||||||
descr = DTR(E->value.brief_description);
|
|
||||||
} else {
|
|
||||||
descr = DTR(E->value.description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // LIMBOAI_MODULE
|
|
||||||
|
|
||||||
// TODO: Documentation tooltips are only available in the module. Find a way to show em in GDExtension.
|
|
||||||
|
|
||||||
sec->add_task_button(tname, icon, descr, task_meta);
|
|
||||||
}
|
}
|
||||||
sec->set_filter("");
|
sec->set_filter("");
|
||||||
sec->connect(LW_NAME(task_button_pressed), callable_mp(this, &TaskPalette::_on_task_button_pressed));
|
sec->connect(LW_NAME(task_button_pressed), callable_mp(this, &TaskPalette::_on_task_button_pressed));
|
||||||
|
|
|
@ -42,18 +42,27 @@ class TaskButton : public Button {
|
||||||
GDCLASS(TaskButton, Button);
|
GDCLASS(TaskButton, Button);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Control *_do_make_tooltip(const String &p_text) const;
|
String task_meta;
|
||||||
|
|
||||||
|
Control *_do_make_tooltip() const;
|
||||||
|
|
||||||
|
#ifdef LIMBOAI_MODULE
|
||||||
|
String _module_get_help_description(const String &p_class_or_script_path) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef LIMBOAI_MODULE
|
#ifdef LIMBOAI_MODULE
|
||||||
virtual Control *make_custom_tooltip(const String &p_text) const override { return _do_make_tooltip(p_text); }
|
virtual Control *make_custom_tooltip(const String &p_text) const override { return _do_make_tooltip(); }
|
||||||
#elif LIMBOAI_GDEXTENSION
|
#elif LIMBOAI_GDEXTENSION
|
||||||
virtual Object *_make_custom_tooltip(const String &p_text) const override { return _do_make_tooltip(p_text); }
|
virtual Object *_make_custom_tooltip(const String &p_text) const override { return _do_make_tooltip(); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
String get_task_meta() const { return task_meta; }
|
||||||
|
void set_task_meta(const String &p_task_meta) { task_meta = p_task_meta; }
|
||||||
|
|
||||||
TaskButton();
|
TaskButton();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,7 +91,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_filter(String p_filter);
|
void set_filter(String p_filter);
|
||||||
void add_task_button(const String &p_name, const Ref<Texture> &icon, const String &p_tooltip, Variant p_meta);
|
void add_task_button(const String &p_name, const Ref<Texture> &icon, const String &p_meta);
|
||||||
|
|
||||||
void set_collapsed(bool p_collapsed);
|
void set_collapsed(bool p_collapsed);
|
||||||
bool is_collapsed() const;
|
bool is_collapsed() const;
|
||||||
|
|
Loading…
Reference in New Issue