feat: improved take cover action node selection

This commit is contained in:
Sara 2024-08-09 15:45:55 +02:00
parent 2c21845991
commit dc60937660
2 changed files with 28 additions and 16 deletions

View file

@ -17,7 +17,7 @@ MoveToTarget::MoveToTarget()
goap::State *MoveToTarget::get_apply_state(goap::ActorWorldState *context) const {
gd::Node3D *target{gd::Object::cast_to<gd::Node3D>(context->get_world_property("target_node"))};
if(target == nullptr) {
gd::UtilityFunctions::push_warning("Failed to get target node of action ", get_static_class());
gd::UtilityFunctions::push_warning("Failed to get target node of ", context->get_path());
return nullptr;
} else {
MoveTo *state{this->create_state<MoveTo>()};
@ -97,34 +97,32 @@ TakeCover::TakeCover()
bool TakeCover::procedural_is_possible(goap::ActorWorldState *context) const {
// positions of the context and the target
gd::Vector3 const global_position{context->get_world_property("parent_global_position")};
gd::Vector3 const context_position{context->get_world_property("parent_global_position")};
gd::Vector3 const target_position{context->get_world_property("target_global_position")};
// if there is no available navigation room, it is not possible to find a cover marker
NavRoom *room{NavRoom::get_closest_room(global_position)};
NavRoom *room{NavRoom::get_closest_room(context_position)};
if(room == nullptr)
return false;
// immediately return true if there is at least one marker that counts as cover from the target
for(NavMarker *marker : room->get_markers())
if(TakeCover::is_marker_cover_from(marker, target_position))
if(TakeCover::is_marker_cover_from(marker, target_position, context_position))
return true;
return false;
}
goap::State *TakeCover::get_apply_state(goap::ActorWorldState *context) const {
// positions of the context and the target to hide from
gd::Vector3 const global_position{context->get_world_property("parent_global_position")};
gd::Vector3 const context_position{context->get_world_property("parent_global_position")};
gd::Vector3 const target_position{context->get_world_property("target_global_position")};
// find the room this entity is located in
NavRoom *room{NavRoom::get_closest_room(global_position)};
NavRoom *room{NavRoom::get_closest_room(context_position)};
if(room == nullptr)
return nullptr;
NavMarker *best_marker{nullptr}; // marker with the best score found so far
float best_score{0.f}; // best score found so far
float best_score{0.f}; // best score found so far, starts at zero because negative values should not be considered
for(NavMarker *marker : room->get_markers()) {
gd::Vector3 const marker_position{marker->get_global_position()}; // position of the marker being considered
float const score{(marker_position.distance_squared_to(target_position) * 1.2f) // score is a comparison between distances to the target and context
- (marker_position.distance_squared_to(global_position) * 0.8f)};
if(score > best_score && TakeCover::is_marker_cover_from(marker, target_position)) {
float const score{this->score_cover_marker(marker, target_position, context_position)};
if(score > best_score) {
best_score = score;
best_marker = marker;
}
@ -138,9 +136,22 @@ goap::State *TakeCover::get_apply_state(goap::ActorWorldState *context) const {
return state;
}
bool TakeCover::is_marker_cover_from(NavMarker *marker, gd::Vector3 const &target) {
bool TakeCover::is_marker_cover_from(NavMarker *marker, gd::Vector3 const &target_position, gd::Vector3 const &context_position) {
gd::Vector3 const marker_position{marker->get_global_position()};
float const distance_to_target{target_position.distance_to(context_position)};
return marker->get_marker_type() == MarkerType::Cover
&& marker->get_global_basis()
.get_column(2)
.dot(marker->get_global_position() - target) < -2.f;
&& marker->get_global_basis().get_column(2).dot(marker_position - target_position) < -2.f
&& context_position.distance_to(marker_position) < (distance_to_target * 2.f);
}
float TakeCover::score_cover_marker(class NavMarker* marker, const gd::Vector3& target_position, const gd::Vector3& context_position) const {
if(!TakeCover::is_marker_cover_from(marker, target_position, context_position))
return 0.f;
gd::Vector3 const marker_position{marker->get_global_position()}; // position of the marker being considered
float const target_distance{marker_position.distance_to(target_position)};
float const context_distance{marker_position.distance_to(context_position)};
// score is a weighted comparison between distances to the target and context
// marker distance from context grows faster than marker distance from target
return (target_distance) - (context_distance);
}

View file

@ -53,7 +53,8 @@ public:
virtual bool procedural_is_possible(goap::ActorWorldState *context) const override;
virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override;
private:
static bool is_marker_cover_from(class NavMarker *marker, gd::Vector3 const &target);
static bool is_marker_cover_from(class NavMarker *marker, gd::Vector3 const &target_position, gd::Vector3 const &context_position);
float score_cover_marker(class NavMarker *marker, gd::Vector3 const &target_position, gd::Vector3 const &context_position) const;
};
#endif // !RTS_ACTIONS_HPP