feat: implemented fire at target action

This commit is contained in:
Sara 2024-06-25 21:16:35 +02:00
parent ffafcac23a
commit 7cf5b128ff
24 changed files with 569 additions and 111 deletions

View file

@ -2,6 +2,7 @@
#define GOAP_ACTION_HPP
#include "actor_world_state.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include "state.hpp"
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/templates/vector.hpp>
@ -23,8 +24,14 @@ typedef int ActionID;
class Action {
friend class ActionDB;
public:
static gd::StringName get_static_class() { return "Action"; }
virtual gd::StringName get_class() const { return "Action"; }
static gd::StringName get_static_class() {
gd::UtilityFunctions::push_error("Action::get_static_class has been called on a class where it is not implemented");
return "Action";
}
virtual gd::StringName get_class() const {
gd::UtilityFunctions::push_error("Action::get_class has been called on a class where it is not implemented");
return "Action";
}
virtual ~Action();
virtual State *get_apply_state(ActorWorldState *context) const = 0;

View file

@ -5,6 +5,8 @@ namespace goap {
ActionDB::StaticData::~StaticData() {
if(this->hint != nullptr)
delete this->hint;
if(this->array_hint != nullptr)
delete this->array_hint;
for(Action *action : this->actions)
delete action;
}
@ -15,11 +17,18 @@ gd::String &ActionDB::StaticData::get_hint() {
return *this->hint;
}
gd::String &ActionDB::StaticData::get_array_hint() {
if(this->array_hint == nullptr)
this->array_hint = new gd::String();
return *this->array_hint;
}
ActionID ActionDB::register_action(Action *instance, gd::String name) {
instance->id = ActionDB::data.actions.size();
if(!ActionDB::data.get_hint().is_empty())
ActionDB::data.get_hint() += ",";
ActionDB::data.get_hint() += name;
ActionDB::data.get_array_hint() = gd::vformat("%s/%s:%s", gd::Variant::INT, gd::PROPERTY_HINT_ENUM, ActionDB::data.get_hint());
// defer intialization until after emplacement to avoid deleting instance
ActionDB::data.actions.push_back(instance);
gd::UtilityFunctions::print("registered action ", name);
@ -38,5 +47,9 @@ gd::String const &ActionDB::get_enum_hint() {
return ActionDB::data.get_hint();
}
gd::String const &ActionDB::get_array_hint() {
return ActionDB::data.get_array_hint();
}
ActionDB::StaticData ActionDB::data{};
}

View file

@ -24,7 +24,9 @@ class ActionDB {
StaticData() = default;
~StaticData();
gd::String &get_hint();
gd::String &get_array_hint();
gd::String *hint{nullptr};
gd::String *array_hint{nullptr};
gd::Vector<Action *> actions{};
};
static ActionID register_action(Action *instance, gd::String name);
@ -35,6 +37,7 @@ public:
/*! Get the csv godot enum hint.
*/
static gd::String const &get_enum_hint();
static gd::String const &get_array_hint();
/*! Add action to database.
*
* \returns Action's assigned ID.

View file

@ -9,6 +9,12 @@ void Goal::_bind_methods() {
GDPROPERTY(desired_state_dict, gd::Variant::DICTIONARY);
}
gd::Ref<Goal> Goal::create(gd::StringName key, gd::Variant value) {
gd::Ref<Goal> goal = memnew(Goal);
goal->desired_state.insert(key, value);
return goal;
}
void Goal::set_requirements_dict(gd::Dictionary dict) {
this->requirements = utils::dictionary_to_hashmap<gd::StringName, gd::Variant>(dict);
}

View file

@ -11,6 +11,7 @@ class Goal : public gd::Resource {
GDCLASS(Goal, gd::Resource);
static void _bind_methods();
public:
static gd::Ref<Goal> create(gd::StringName key, gd::Variant value);
void set_requirements_dict(gd::Dictionary dict);
gd::Dictionary get_requirements_dict() const;
void set_desired_state_dict(gd::Dictionary dict);

View file

@ -80,7 +80,7 @@ bool operator>=(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs
void Planner::_bind_methods() {
#define CLASSNAME Planner
GDPROPERTY_HINTED(actions, gd::Variant::ARRAY, gd::PROPERTY_HINT_ARRAY_TYPE, gd::vformat("%s/%s:%s", gd::Variant::INT, gd::PROPERTY_HINT_ENUM, ActionDB::get_enum_hint()));
GDPROPERTY_HINTED(actions_inspector, gd::Variant::ARRAY, gd::PROPERTY_HINT_ARRAY_TYPE, ActionDB::get_array_hint());
}
void Planner::_enter_tree() { GDGAMEONLY();
@ -143,7 +143,7 @@ Plan Planner::plan_for_goal(gd::Ref<Goal> goal) {
return {};
}
void Planner::set_actions(gd::Array array) {
void Planner::set_actions_inspector(gd::Array array) {
this->actions.clear();
for(size_t i = 0; i < array.size(); ++i) {
Action const *action = int(array[i]) < 0 ? nullptr : ActionDB::get_action(array[i]);
@ -155,13 +155,17 @@ void Planner::set_actions(gd::Array array) {
}
}
gd::Array Planner::get_actions() const {
gd::Array Planner::get_actions_inspector() const {
gd::Array array{};
for(Action const *action : this->actions)
array.push_back(action == nullptr ? -1 : action->get_id());
return array;
}
gd::Vector<Action const *> &Planner::get_actions() {
return this->actions;
}
gd::Vector<Action const *> Planner::get_neighbours(WorldStateNode const &from) const {
gd::Vector<Action const *> retval{};
for(Action const *action : this->actions) {

View file

@ -58,8 +58,9 @@ public:
//! Compute a plan to achieve the passed `Goal`.
Plan plan_for_goal(gd::Ref<Goal> goal);
void set_actions(gd::Array array);
gd::Array get_actions() const;
void set_actions_inspector(gd::Array array);
gd::Array get_actions_inspector() const;
gd::Vector<Action const*> &get_actions();
private:
//! \returns A vector of all actions that satisfy any of the requirements in `unsatisfied`
gd::Vector<Action const *> get_neighbours(WorldStateNode const &from) const;