fix: self preservation plan in the wrong order
This commit is contained in:
parent
4ba6869a30
commit
a2240797b8
|
@ -5,5 +5,6 @@ requirements_dict = {
|
||||||
"is_health_safe": false
|
"is_health_safe": false
|
||||||
}
|
}
|
||||||
desired_state_dict = {
|
desired_state_dict = {
|
||||||
|
"can_see_target": false,
|
||||||
"is_health_safe": true
|
"is_health_safe": true
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
[ext_resource type="AnimationLibrary" uid="uid://crkh5gahl2ci6" path="res://Animation/bean_characters.res" id="2_lrpu6"]
|
[ext_resource type="AnimationLibrary" uid="uid://crkh5gahl2ci6" path="res://Animation/bean_characters.res" id="2_lrpu6"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_5pqvg"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_5pqvg"]
|
||||||
radius = 7.38627
|
radius = 8.42531
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_drlm2"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_drlm2"]
|
||||||
radius = 1.0
|
radius = 1.0
|
||||||
|
@ -15,6 +15,8 @@ albedo_color = Color(1, 0.24, 0.24, 1)
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5r0b3"]
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5r0b3"]
|
||||||
material = SubResource("StandardMaterial3D_ss47r")
|
material = SubResource("StandardMaterial3D_ss47r")
|
||||||
|
radial_segments = 8
|
||||||
|
rings = 3
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_p8wvo"]
|
[sub_resource type="BoxMesh" id="BoxMesh_p8wvo"]
|
||||||
size = Vector3(0.2, 0.2, 0.5)
|
size = Vector3(0.2, 0.2, 0.5)
|
||||||
|
@ -29,7 +31,7 @@ editor_available_goals = [ExtResource("2_k42dl"), ExtResource("1_b1qo1")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
||||||
[node name="Planner" type="Planner" parent="."]
|
[node name="Planner" type="Planner" parent="."]
|
||||||
actions_inspector = [3, 2, 4, 5]
|
actions_inspector = [3, 2, 4, 5, 6]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
||||||
[node name="EntityHealth" type="EntityHealth" parent="."]
|
[node name="EntityHealth" type="EntityHealth" parent="."]
|
||||||
|
@ -37,6 +39,8 @@ unique_name_in_owner = true
|
||||||
|
|
||||||
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
path_desired_distance = 0.5
|
||||||
|
target_desired_distance = 0.2
|
||||||
path_height_offset = 0.5
|
path_height_offset = 0.5
|
||||||
|
|
||||||
[node name="AwarenessArea" type="Area3D" parent="."]
|
[node name="AwarenessArea" type="Area3D" parent="."]
|
||||||
|
@ -47,7 +51,7 @@ collision_mask = 2
|
||||||
input_ray_pickable = false
|
input_ray_pickable = false
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="AwarenessArea"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="AwarenessArea"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.36036)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.238092)
|
||||||
shape = SubResource("SphereShape3D_5pqvg")
|
shape = SubResource("SphereShape3D_5pqvg")
|
||||||
|
|
||||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||||
|
|
5
godot/GameObjects/nav_marker.tscn
Normal file
5
godot/GameObjects/nav_marker.tscn
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[gd_scene format=3 uid="uid://c82s8vpaethtv"]
|
||||||
|
|
||||||
|
[node name="NavMarker" type="NavMarker"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.68886, 0.383154, -2.15328)
|
||||||
|
gizmo_extents = 1.0
|
|
@ -9,7 +9,7 @@ height = 0.1
|
||||||
ground_marker_scene = ExtResource("1_t46fa")
|
ground_marker_scene = ExtResource("1_t46fa")
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="."]
|
[node name="Camera3D" type="Camera3D" parent="."]
|
||||||
transform = Transform3D(-1, 7.57104e-08, -4.37114e-08, 0, 0.5, 0.866025, 8.74228e-08, 0.866025, -0.5, 0, 8.41077, -4.42292)
|
transform = Transform3D(-1, 7.57104e-08, -4.37114e-08, 0, 0.5, 0.866025, 8.74228e-08, 0.866025, -0.5, 0, 10.1792, -3.46957)
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0494189, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0494189, 0)
|
||||||
|
|
|
@ -10,6 +10,8 @@ albedo_color = Color(0.407843, 1, 0.447059, 1)
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5r0b3"]
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5r0b3"]
|
||||||
material = SubResource("StandardMaterial3D_n4q15")
|
material = SubResource("StandardMaterial3D_n4q15")
|
||||||
|
radial_segments = 8
|
||||||
|
rings = 3
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_p8wvo"]
|
[sub_resource type="BoxMesh" id="BoxMesh_p8wvo"]
|
||||||
size = Vector3(0.2, 0.2, 0.5)
|
size = Vector3(0.2, 0.2, 0.5)
|
||||||
|
@ -31,6 +33,8 @@ unique_name_in_owner = true
|
||||||
|
|
||||||
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
path_desired_distance = 0.2
|
||||||
|
target_desired_distance = 0.5
|
||||||
path_height_offset = 0.5
|
path_height_offset = 0.5
|
||||||
debug_enabled = true
|
debug_enabled = true
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
[gd_scene load_steps=10 format=3 uid="uid://c62s1jmtgajjk"]
|
[gd_scene load_steps=11 format=3 uid="uid://c62s1jmtgajjk"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dsalxxq3xs842" path="res://rts_game_mode.tscn" id="1_4nchg"]
|
[ext_resource type="PackedScene" uid="uid://dsalxxq3xs842" path="res://rts_game_mode.tscn" id="1_4nchg"]
|
||||||
[ext_resource type="Environment" uid="uid://cnfk8yrvklysq" path="res://Environments/default_environment.tres" id="2_jq6bw"]
|
[ext_resource type="Environment" uid="uid://cnfk8yrvklysq" path="res://Environments/default_environment.tres" id="2_jq6bw"]
|
||||||
[ext_resource type="PackedScene" uid="uid://pme230qx1377" path="res://GameObjects/player_unit.tscn" id="3_wl7wm"]
|
[ext_resource type="PackedScene" uid="uid://pme230qx1377" path="res://GameObjects/player_unit.tscn" id="3_wl7wm"]
|
||||||
[ext_resource type="PackedScene" uid="uid://ba17jrcaduowj" path="res://GameObjects/enemy_unit.tscn" id="4_0o33v"]
|
[ext_resource type="PackedScene" uid="uid://ba17jrcaduowj" path="res://GameObjects/enemy_unit.tscn" id="4_0o33v"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://c82s8vpaethtv" path="res://GameObjects/nav_marker.tscn" id="5_ta2oq"]
|
||||||
|
|
||||||
[sub_resource type="NavigationMesh" id="NavigationMesh_8a2j6"]
|
[sub_resource type="NavigationMesh" id="NavigationMesh_8a2j6"]
|
||||||
vertices = PackedVector3Array(0, 0.4, -2, 1.75, 0.4, -3.25, 1.75, 0.4, -9.5, -0.75, 0.4, -0.25, 0, 0.4, -2, 1.75, 0.4, -9.5, -9.5, 0.4, -9.5, -9.5, 0.4, -0.25, 4.5, 0.4, -1.25, 4.5, 0.4, -0.5, 9.5, 0.4, -0.5, 3.25, 0.4, -2.5, 4.5, 0.4, -1.25, 9.5, 0.4, -0.5, 1.75, 0.4, -9.5, 1.75, 0.4, -3.25, 3.25, 0.4, -2.5, 9.5, 0.4, -0.5, 9.5, 0.4, -9.5, 1.75, 3.4, 1, 2.25, 3.4, 1, 3.5, 3.4, -0.5, 2.75, 3.4, -1.5, 1.5, 3.4, -2, 0.25, 3.4, -0.5, 3, 0.4, -0.5, 2.5, 0.4, -1.25, 1.5, 0.4, -1.5, 0.75, 0.4, -0.5, 1.75, 0.4, 0.5, 9.5, 0.4, -0.5, 4.5, 0.4, -0.5, 3.5, 0.4, 1.25, 9.5, 0.4, -0.5, 3.5, 0.4, 1.25, 2, 0.4, 2.25, 2, 0.4, 9.5, 9.5, 0.4, 9.5, 2, 0.4, 9.5, 2, 0.4, 2.25, 0, 0.4, 1, 0, 0.4, 1, -0.75, 0.4, -0.25, -9.5, 0.4, -0.25, -9.5, 0.4, 9.5, 2, 0.4, 9.5)
|
vertices = PackedVector3Array(0, 0.4, -2, 1.75, 0.4, -3.25, 1.75, 0.4, -9.5, -0.75, 0.4, -0.25, 0, 0.4, -2, 1.75, 0.4, -9.5, -9.5, 0.4, -9.5, -9.5, 0.4, -0.25, 4.5, 0.4, -1.25, 4.5, 0.4, -0.5, 9.5, 0.4, -0.5, 3.25, 0.4, -2.5, 4.5, 0.4, -1.25, 9.5, 0.4, -0.5, 1.75, 0.4, -9.5, 1.75, 0.4, -3.25, 3.25, 0.4, -2.5, 9.5, 0.4, -0.5, 9.5, 0.4, -9.5, 1.75, 3.4, 1, 2.25, 3.4, 1, 3.5, 3.4, -0.5, 2.75, 3.4, -1.5, 1.5, 3.4, -2, 0.25, 3.4, -0.5, 3, 0.4, -0.5, 2.5, 0.4, -1.25, 1.5, 0.4, -1.5, 0.75, 0.4, -0.5, 1.75, 0.4, 0.5, 9.5, 0.4, -0.5, 4.5, 0.4, -0.5, 3.5, 0.4, 1.25, 9.5, 0.4, -0.5, 3.5, 0.4, 1.25, 2, 0.4, 2.25, 2, 0.4, 9.5, 9.5, 0.4, 9.5, 2, 0.4, 9.5, 2, 0.4, 2.25, 0, 0.4, 1, 0, 0.4, 1, -0.75, 0.4, -0.25, -9.5, 0.4, -0.25, -9.5, 0.4, 9.5, 2, 0.4, 9.5)
|
||||||
|
@ -64,3 +65,37 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.7165, 1.8999e-07, 3.29106)
|
||||||
|
|
||||||
[node name="Unit2" parent="." instance=ExtResource("4_0o33v")]
|
[node name="Unit2" parent="." instance=ExtResource("4_0o33v")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.57207, -7.63685e-07, -6.40453)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.57207, -7.63685e-07, -6.40453)
|
||||||
|
|
||||||
|
[node name="NavRoom" type="NavRoom" parent="."]
|
||||||
|
|
||||||
|
[node name="NavMarker" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(0.80479, 0, -0.593559, 0, 1, 0, 0.593559, 0, 0.80479, 3.65141, 0.4, -2.09859)
|
||||||
|
|
||||||
|
[node name="NavMarker2" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(0.794658, 0, -0.607057, 0, 1, 0, 0.607057, 0, 0.794658, 3.07483, 0.4, -2.58758)
|
||||||
|
|
||||||
|
[node name="NavMarker3" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(-0.784766, 0, 0.619792, 0, 1, 0, -0.619792, 0, -0.784766, 0.723487, 0.4, 1.45218)
|
||||||
|
|
||||||
|
[node name="NavMarker4" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(-0.628248, 0, -0.778013, 0, 1, 0, 0.778013, 0, -0.628248, 3.51616, 0.4, 1.22172)
|
||||||
|
|
||||||
|
[node name="NavMarker8" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(-0.635135, 0, -0.772401, 0, 1, 0, 0.772401, 0, -0.635135, 3.91311, 0.4, 0.527064)
|
||||||
|
|
||||||
|
[node name="NavMarker5" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(-0.762273, 0, 0.647256, 0, 1, 0, -0.647256, 0, -0.762273, 0.0761999, 0.4, 1.04762)
|
||||||
|
|
||||||
|
[node name="NavMarker6" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(0.652363, 0, 0.757906, 0, 1, 0, -0.757906, 0, 0.652363, -0.132873, 0.4, -1.68996)
|
||||||
|
|
||||||
|
[node name="NavMarker7" parent="NavRoom" instance=ExtResource("5_ta2oq")]
|
||||||
|
marker_type = 1
|
||||||
|
transform = Transform3D(0.668508, 0, 0.743705, 0, 1, 0, -0.743705, 0, 0.668508, 0.277942, 0.4, -2.19853)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "enemy_world_state.hpp"
|
#include "enemy_world_state.hpp"
|
||||||
#include "entity_health.hpp"
|
#include "entity_health.hpp"
|
||||||
#include "goap/goal.hpp"
|
|
||||||
#include "godot_cpp/variant/utility_functions.hpp"
|
|
||||||
#include "unit.hpp"
|
#include "unit.hpp"
|
||||||
|
#include "goap/goal.hpp"
|
||||||
#include "utils/godot_macros.hpp"
|
#include "utils/godot_macros.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
@ -14,7 +13,7 @@ void EnemyWorldState::_bind_methods() {
|
||||||
GDRESOURCETYPE("Goal"));
|
GDRESOURCETYPE("Goal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnemyWorldState::_ready() {
|
void EnemyWorldState::_ready() { GDGAMEONLY();
|
||||||
this->awareness_area = this->get_node<gd::Area3D>("%AwarenessArea");
|
this->awareness_area = this->get_node<gd::Area3D>("%AwarenessArea");
|
||||||
this->awareness_area->connect("body_entered", callable_mp(this, &EnemyWorldState::on_awareness_entered));
|
this->awareness_area->connect("body_entered", callable_mp(this, &EnemyWorldState::on_awareness_entered));
|
||||||
this->awareness_area->connect("body_exited", callable_mp(this, &EnemyWorldState::on_awareness_exited));
|
this->awareness_area->connect("body_exited", callable_mp(this, &EnemyWorldState::on_awareness_exited));
|
||||||
|
@ -36,6 +35,8 @@ void EnemyWorldState::on_awareness_exited(gd::Node3D *node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnemyWorldState::on_damaged(int remaining, int delta, Unit *source) {
|
void EnemyWorldState::on_damaged(int remaining, int delta, Unit *source) {
|
||||||
|
if(this->parent_unit->has_plan())
|
||||||
|
return;
|
||||||
float highest_priority{0.f};
|
float highest_priority{0.f};
|
||||||
Unit *highest_priority_unit{this->select_target_from_known_with_priority(&highest_priority)};
|
Unit *highest_priority_unit{this->select_target_from_known_with_priority(&highest_priority)};
|
||||||
float const priority{this->calculate_priority(source)};
|
float const priority{this->calculate_priority(source)};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include "planner.hpp"
|
#include "planner.hpp"
|
||||||
#include "action_db.hpp"
|
#include "action_db.hpp"
|
||||||
#include "godot_cpp/classes/engine.hpp"
|
|
||||||
#include "godot_cpp/classes/global_constants.hpp"
|
|
||||||
#include "godot_cpp/templates/hashfuncs.hpp"
|
#include "godot_cpp/templates/hashfuncs.hpp"
|
||||||
#include "utils/godot_macros.hpp"
|
#include "utils/godot_macros.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <godot_cpp/classes/engine.hpp>
|
||||||
|
#include <godot_cpp/classes/global_constants.hpp>
|
||||||
#include <godot_cpp/variant/utility_functions.hpp>
|
#include <godot_cpp/variant/utility_functions.hpp>
|
||||||
|
|
||||||
namespace goap {
|
namespace goap {
|
||||||
|
@ -16,17 +16,19 @@ WorldStateNode::WorldStateNode(WorldStateNode const &last_state, Action const *l
|
||||||
, open_requirements{last_state.open_requirements}
|
, open_requirements{last_state.open_requirements}
|
||||||
, last_action{last_action}
|
, last_action{last_action}
|
||||||
, context{last_state.context} {
|
, context{last_state.context} {
|
||||||
for(WorldProperty const &req : last_action->get_required())
|
for(WorldProperty const &req : last_action->get_required()) {
|
||||||
this->open_requirements[req.key] = req.value;
|
this->open_requirements[req.key] = req.value;
|
||||||
|
this->state[req.key] = this->context->get_world_property(req.key);
|
||||||
|
}
|
||||||
for(WorldProperty const &effect : last_action->get_effects())
|
for(WorldProperty const &effect : last_action->get_effects())
|
||||||
if(this->open_requirements.has(effect.key))
|
|
||||||
this->state[effect.key] = effect.value;
|
this->state[effect.key] = effect.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WorldStateNode::requirements_unmet() const {
|
int WorldStateNode::requirements_unmet() const {
|
||||||
int requirements = this->open_requirements.size();
|
int requirements = this->open_requirements.size();
|
||||||
for(WorldProperty const &req : this->open_requirements) {
|
for(WorldProperty const &req : this->open_requirements) {
|
||||||
if(this->state.has(req.key) && this->state[req.key] == req.value) {
|
if(this->state.has(req.key)) {
|
||||||
|
if(this->state[req.key] == req.value)
|
||||||
--requirements;
|
--requirements;
|
||||||
} else if(this->context->check_property_match(req)) {
|
} else if(this->context->check_property_match(req)) {
|
||||||
--requirements;
|
--requirements;
|
||||||
|
@ -63,19 +65,19 @@ bool operator!=(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
bool operator<(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
||||||
return lhs.state.size() < rhs.state.size();
|
return lhs.requirements_unmet() < rhs.requirements_unmet();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<=(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
bool operator<=(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
||||||
return lhs.state.size() <= rhs.state.size();
|
return lhs.requirements_unmet() <= rhs.requirements_unmet();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator>(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
bool operator>(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
||||||
return lhs.state.size() > rhs.state.size();
|
return lhs.requirements_unmet() > rhs.requirements_unmet();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator>=(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
bool operator>=(goap::WorldStateNode const &lhs, goap::WorldStateNode const &rhs) {
|
||||||
return lhs.state.size() >= rhs.state.size();
|
return lhs.requirements_unmet() >= rhs.requirements_unmet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Planner::_bind_methods() {
|
void Planner::_bind_methods() {
|
||||||
|
|
32
src/nav_marker.cpp
Normal file
32
src/nav_marker.cpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#include "nav_marker.hpp"
|
||||||
|
#include "utils/godot_macros.hpp"
|
||||||
|
#include <godot_cpp/classes/editor_interface.hpp>
|
||||||
|
#include <godot_cpp/classes/editor_selection.hpp>
|
||||||
|
#include <godot_cpp/classes/engine.hpp>
|
||||||
|
#include <godot_cpp/classes/navigation_server3d.hpp>
|
||||||
|
#include <godot_cpp/classes/world3d.hpp>
|
||||||
|
#include <godot_cpp/variant/rid.hpp>
|
||||||
|
|
||||||
|
void NavMarker::_bind_methods() {
|
||||||
|
#define CLASSNAME NavMarker
|
||||||
|
GDPROPERTY_HINTED(marker_type, gd::Variant::INT, gd::PROPERTY_HINT_ENUM, MarkerType::get_property_hint());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavMarker::_process(double delta_time) {
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
GDEDITORONLY()
|
||||||
|
if(gd::EditorInterface::get_singleton()->get_selection()->get_selected_nodes().has(this)) {
|
||||||
|
gd::RID const map_id{this->get_world_3d()->get_navigation_map()};
|
||||||
|
gd::Vector3 const new_point{gd::NavigationServer3D::get_singleton()->map_get_closest_point(map_id, this->get_global_position())};
|
||||||
|
this->set_global_position(new_point);
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavMarker::set_marker_type(int type) {
|
||||||
|
this->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NavMarker::get_marker_type() const {
|
||||||
|
return this->type;
|
||||||
|
}
|
26
src/nav_marker.hpp
Normal file
26
src/nav_marker.hpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef NAV_MARKER_HPP
|
||||||
|
#define NAV_MARKER_HPP
|
||||||
|
|
||||||
|
#include "utils/godot_macros.hpp"
|
||||||
|
#include <godot_cpp/classes/marker3d.hpp>
|
||||||
|
|
||||||
|
namespace gd = godot;
|
||||||
|
|
||||||
|
GDENUM(MarkerType,
|
||||||
|
Generic,
|
||||||
|
Cover
|
||||||
|
);
|
||||||
|
|
||||||
|
class NavMarker : public gd::Marker3D {
|
||||||
|
GDCLASS(NavMarker, gd::Marker3D);
|
||||||
|
static void _bind_methods();
|
||||||
|
public:
|
||||||
|
virtual void _process(double delta_time) override;
|
||||||
|
|
||||||
|
void set_marker_type(int type);
|
||||||
|
int get_marker_type() const;
|
||||||
|
private:
|
||||||
|
MarkerType type{MarkerType::Generic};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !NAV_MARKER_HPP
|
60
src/nav_room.cpp
Normal file
60
src/nav_room.cpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#include "nav_room.hpp"
|
||||||
|
#include "godot_cpp/classes/global_constants.hpp"
|
||||||
|
#include "nav_marker.hpp"
|
||||||
|
#include "utils/godot_macros.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
void NavRoom::_bind_methods() {
|
||||||
|
#define CLASSNAME NavRoom
|
||||||
|
GDPROPERTY_HINTED(editor_neighbours, gd::Variant::ARRAY, gd::PROPERTY_HINT_ARRAY_TYPE, GDNODETYPE("NavRoom"));
|
||||||
|
}
|
||||||
|
|
||||||
|
NavRoom *NavRoom::get_closest_room(gd::Vector3 const &closest_to) {
|
||||||
|
NavRoom *candidate{nullptr};
|
||||||
|
float shortest_distance{INFINITY};
|
||||||
|
for(NavRoom *room : NavRoom::rooms) {
|
||||||
|
float const distance{room->get_global_position().distance_squared_to(closest_to)};
|
||||||
|
if(distance < shortest_distance) {
|
||||||
|
shortest_distance = distance;
|
||||||
|
candidate = room;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavRoom::_enter_tree() { GDGAMEONLY()
|
||||||
|
NavRoom::rooms.push_back(this);
|
||||||
|
this->connect("child_entered_tree", callable_mp(this, &NavRoom::on_child_entered));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavRoom::_exit_tree() { GDGAMEONLY()
|
||||||
|
NavRoom::rooms.erase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavRoom::on_child_entered(gd::Node *child) {
|
||||||
|
if(NavMarker *marker{gd::Object::cast_to<NavMarker>(child)})
|
||||||
|
this->markers.push_back(marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
gd::Vector<NavRoom*> const &NavRoom::get_neighbours() const {
|
||||||
|
return this->neighbours;
|
||||||
|
}
|
||||||
|
|
||||||
|
gd::Vector<NavMarker*> const &NavRoom::get_markers() const {
|
||||||
|
return this->markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
gd::Array NavRoom::get_editor_neighbours() const {
|
||||||
|
gd::Array a{};
|
||||||
|
for(NavRoom *room : this->neighbours)
|
||||||
|
a.push_back(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavRoom::set_editor_neighbours(gd::Array array) {
|
||||||
|
this->neighbours.clear();
|
||||||
|
while(!array.is_empty()) if(NavRoom *room{gd::Object::cast_to<NavRoom>(array.pop_front())})
|
||||||
|
this->neighbours.push_back(room);
|
||||||
|
}
|
||||||
|
|
||||||
|
gd::Vector<NavRoom*> NavRoom::rooms{};
|
33
src/nav_room.hpp
Normal file
33
src/nav_room.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef NAV_ROOM_HPP
|
||||||
|
#define NAV_ROOM_HPP
|
||||||
|
|
||||||
|
#include <godot_cpp/classes/node3d.hpp>
|
||||||
|
#include <godot_cpp/templates/vector.hpp>
|
||||||
|
|
||||||
|
namespace gd = godot;
|
||||||
|
|
||||||
|
class NavMarker;
|
||||||
|
|
||||||
|
class NavRoom : public gd::Node3D {
|
||||||
|
GDCLASS(NavRoom, gd::Node3D);
|
||||||
|
static void _bind_methods();
|
||||||
|
public:
|
||||||
|
static NavRoom *get_closest_room(gd::Vector3 const &closest_to);
|
||||||
|
virtual void _enter_tree() override;
|
||||||
|
virtual void _exit_tree() override;
|
||||||
|
virtual void on_child_entered(gd::Node *child);
|
||||||
|
gd::Vector<NavRoom*> const &get_neighbours() const;
|
||||||
|
gd::Vector<NavMarker*> const &get_markers() const;
|
||||||
|
private:
|
||||||
|
void set_editor_neighbours(gd::Array array);
|
||||||
|
gd::Array get_editor_neighbours() const;
|
||||||
|
private:
|
||||||
|
float radius{1.f};
|
||||||
|
gd::Vector3 centre{0.f, 0.f, 0.f};
|
||||||
|
gd::Vector<NavMarker*> markers{};
|
||||||
|
gd::Vector<NavRoom*> neighbours{};
|
||||||
|
|
||||||
|
static gd::Vector<NavRoom*> rooms;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !NAV_ROOM_HPP
|
|
@ -2,6 +2,8 @@
|
||||||
#include "enemy_world_state.hpp"
|
#include "enemy_world_state.hpp"
|
||||||
#include "entity_health.hpp"
|
#include "entity_health.hpp"
|
||||||
#include "goap/state.hpp"
|
#include "goap/state.hpp"
|
||||||
|
#include "nav_marker.hpp"
|
||||||
|
#include "nav_room.hpp"
|
||||||
#include "rts_actions.hpp"
|
#include "rts_actions.hpp"
|
||||||
#include "rts_game_mode.hpp"
|
#include "rts_game_mode.hpp"
|
||||||
#include "rts_player.hpp"
|
#include "rts_player.hpp"
|
||||||
|
@ -36,6 +38,7 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
|
||||||
goap::ActionDB::register_action<GetInMeleeRange>();
|
goap::ActionDB::register_action<GetInMeleeRange>();
|
||||||
goap::ActionDB::register_action<MeleeAttack>();
|
goap::ActionDB::register_action<MeleeAttack>();
|
||||||
goap::ActionDB::register_action<TankSelfHeal>();
|
goap::ActionDB::register_action<TankSelfHeal>();
|
||||||
|
goap::ActionDB::register_action<TakeCover>();
|
||||||
|
|
||||||
ClassDB::register_class<goap::ActorWorldState>();
|
ClassDB::register_class<goap::ActorWorldState>();
|
||||||
ClassDB::register_class<goap::Goal>();
|
ClassDB::register_class<goap::Goal>();
|
||||||
|
@ -53,6 +56,8 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
|
||||||
ClassDB::register_class<RTSGameMode>();
|
ClassDB::register_class<RTSGameMode>();
|
||||||
ClassDB::register_class<RTSPlayer>();
|
ClassDB::register_class<RTSPlayer>();
|
||||||
ClassDB::register_class<EntityHealth>();
|
ClassDB::register_class<EntityHealth>();
|
||||||
|
ClassDB::register_class<NavMarker>();
|
||||||
|
ClassDB::register_class<NavRoom>();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
#include "rts_actions.hpp"
|
#include "rts_actions.hpp"
|
||||||
|
#include "nav_marker.hpp"
|
||||||
|
#include "nav_room.hpp"
|
||||||
#include "rts_states.hpp"
|
#include "rts_states.hpp"
|
||||||
#include "goap/actor_world_state.hpp"
|
#include "goap/actor_world_state.hpp"
|
||||||
#include "goap/state.hpp"
|
#include "goap/state.hpp"
|
||||||
#include <godot_cpp/core/memory.hpp>
|
#include <godot_cpp/core/memory.hpp>
|
||||||
|
#include <godot_cpp/variant/basis.hpp>
|
||||||
#include <godot_cpp/variant/utility_functions.hpp>
|
#include <godot_cpp/variant/utility_functions.hpp>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
MoveToTarget::MoveToTarget()
|
MoveToTarget::MoveToTarget()
|
||||||
: Action() {
|
: Action() {
|
||||||
|
@ -24,8 +28,8 @@ goap::State *MoveToTarget::get_apply_state(goap::ActorWorldState *context) const
|
||||||
|
|
||||||
FireAtTarget::FireAtTarget()
|
FireAtTarget::FireAtTarget()
|
||||||
: Action() {
|
: Action() {
|
||||||
this->effects.insert("is_target_dead", true);
|
|
||||||
this->required.insert("can_see_target", true);
|
this->required.insert("can_see_target", true);
|
||||||
|
this->effects.insert("is_target_dead", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
goap::State *FireAtTarget::get_apply_state(goap::ActorWorldState *context) const {
|
goap::State *FireAtTarget::get_apply_state(goap::ActorWorldState *context) const {
|
||||||
|
@ -50,8 +54,8 @@ goap::State *FindTarget::get_apply_state(goap::ActorWorldState *context) const {
|
||||||
GetInMeleeRange::GetInMeleeRange()
|
GetInMeleeRange::GetInMeleeRange()
|
||||||
: Action() {
|
: Action() {
|
||||||
this->require_state_complete = false;
|
this->require_state_complete = false;
|
||||||
this->effects.insert("is_in_melee_range", true);
|
|
||||||
this->required.insert("can_see_target", true);
|
this->required.insert("can_see_target", true);
|
||||||
|
this->effects.insert("is_in_melee_range", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
goap::State *GetInMeleeRange::get_apply_state(goap::ActorWorldState *context) const {
|
goap::State *GetInMeleeRange::get_apply_state(goap::ActorWorldState *context) const {
|
||||||
|
@ -63,9 +67,9 @@ goap::State *GetInMeleeRange::get_apply_state(goap::ActorWorldState *context) co
|
||||||
|
|
||||||
MeleeAttack::MeleeAttack()
|
MeleeAttack::MeleeAttack()
|
||||||
: Action() {
|
: Action() {
|
||||||
this->effects.insert("is_target_dead", true);
|
|
||||||
this->required.insert("can_see_target", true);
|
this->required.insert("can_see_target", true);
|
||||||
this->required.insert("is_in_melee_range", true);
|
this->required.insert("is_in_melee_range", true);
|
||||||
|
this->effects.insert("is_target_dead", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
goap::State *MeleeAttack::get_apply_state(goap::ActorWorldState *context) const {
|
goap::State *MeleeAttack::get_apply_state(goap::ActorWorldState *context) const {
|
||||||
|
@ -76,6 +80,7 @@ goap::State *MeleeAttack::get_apply_state(goap::ActorWorldState *context) const
|
||||||
|
|
||||||
TankSelfHeal::TankSelfHeal()
|
TankSelfHeal::TankSelfHeal()
|
||||||
: Action() {
|
: Action() {
|
||||||
|
this->required.insert("can_see_target", false);
|
||||||
this->effects.insert("is_health_safe", true);
|
this->effects.insert("is_health_safe", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,3 +89,48 @@ goap::State *TankSelfHeal::get_apply_state(goap::ActorWorldState *context) const
|
||||||
state->animation = "self_heal";
|
state->animation = "self_heal";
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TakeCover::TakeCover()
|
||||||
|
: Action () {
|
||||||
|
this->require_state_complete = false;
|
||||||
|
this->effects.insert("can_see_target", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TakeCover::procedural_is_possible(goap::ActorWorldState *context) const {
|
||||||
|
gd::Vector3 const global_position{context->get_world_property("parent_global_position")};
|
||||||
|
gd::Vector3 const target_position{context->get_world_property("target_global_position")};
|
||||||
|
NavRoom *room{NavRoom::get_closest_room(global_position)};
|
||||||
|
if(room == nullptr)
|
||||||
|
return false;
|
||||||
|
for(NavMarker *marker : room->get_markers())
|
||||||
|
if(TakeCover::is_marker_cover_from(marker, target_position))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
goap::State *TakeCover::get_apply_state(goap::ActorWorldState *context) const {
|
||||||
|
MoveTo *state{this->create_state<MoveTo>()};
|
||||||
|
gd::Vector3 const global_position{context->get_world_property("parent_global_position")};
|
||||||
|
gd::Vector3 const target_position{context->get_world_property("target_global_position")};
|
||||||
|
NavRoom *room{NavRoom::get_closest_room(global_position)};
|
||||||
|
if(room == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
float best_score{-INFINITY};
|
||||||
|
for(NavMarker *marker : room->get_markers()) {
|
||||||
|
gd::Vector3 const marker_position{marker->get_global_position()};
|
||||||
|
float const score{100.f - marker_position.distance_to(global_position)};
|
||||||
|
if(score > best_score && TakeCover::is_marker_cover_from(marker, target_position)) {
|
||||||
|
best_score = score;
|
||||||
|
state->target_node = marker;
|
||||||
|
gd::UtilityFunctions::print("!!! best cover so far: ", marker->get_path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TakeCover::is_marker_cover_from(NavMarker *marker, gd::Vector3 const &target) {
|
||||||
|
return marker->get_marker_type() == MarkerType::Cover
|
||||||
|
&& marker->get_global_basis()
|
||||||
|
.get_column(2)
|
||||||
|
.dot((marker->get_global_position() - target).normalized()) < -0.7f;
|
||||||
|
}
|
||||||
|
|
|
@ -40,10 +40,20 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class TankSelfHeal : public goap::Action {
|
class TankSelfHeal : public goap::Action {
|
||||||
GOAP_ACTION(SelfHeal);
|
GOAP_ACTION(TankSelfHeal);
|
||||||
public:
|
public:
|
||||||
TankSelfHeal();
|
TankSelfHeal();
|
||||||
virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override;
|
virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TakeCover : public goap::Action {
|
||||||
|
GOAP_ACTION(TakeCover);
|
||||||
|
public:
|
||||||
|
TakeCover();
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
#endif // !RTS_ACTIONS_HPP
|
#endif // !RTS_ACTIONS_HPP
|
||||||
|
|
|
@ -7,10 +7,16 @@
|
||||||
void MoveTo::_bind_methods() {}
|
void MoveTo::_bind_methods() {}
|
||||||
|
|
||||||
void MoveTo::_ready() {
|
void MoveTo::_ready() {
|
||||||
this->agent = this->get_node<gd::NavigationAgent3D>("../NavigationAgent3D");
|
|
||||||
this->agent->set_target_position(this->target_node->get_global_position());
|
|
||||||
this->parent_node3d = Object::cast_to<gd::Node3D>(this->get_parent());
|
this->parent_node3d = Object::cast_to<gd::Node3D>(this->get_parent());
|
||||||
|
this->agent = this->get_node<gd::NavigationAgent3D>("../NavigationAgent3D");
|
||||||
|
if(this->target_node == nullptr) {
|
||||||
|
this->state_ended();
|
||||||
|
gd::UtilityFunctions::push_warning("failed to start MoveTo state due to missing target");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->agent->set_target_position(this->target_node->get_global_position());
|
||||||
this->calculate_path();
|
this->calculate_path();
|
||||||
|
gd::UtilityFunctions::print(this->parent_node3d->get_path(), " MoveTo ", this->target_node->get_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveTo::_end_state() {
|
void MoveTo::_end_state() {
|
||||||
|
@ -65,6 +71,8 @@ void Animate::_bind_methods() {}
|
||||||
void Animate::_ready() {
|
void Animate::_ready() {
|
||||||
this->anim = this->get_node<gd::AnimationPlayer>("../AnimationPlayer");
|
this->anim = this->get_node<gd::AnimationPlayer>("../AnimationPlayer");
|
||||||
this->anim->play(this->animation);
|
this->anim->play(this->animation);
|
||||||
|
if(!this->anim->has_animation(this->animation))
|
||||||
|
this->state_ended();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animate::_process(double delta_time) {
|
void Animate::_process(double delta_time) {
|
||||||
|
|
|
@ -50,7 +50,9 @@ bool UnitWorldState::get_can_see_target() const {
|
||||||
target_position,
|
target_position,
|
||||||
0x1 | 0x4, ignore_list)
|
0x1 | 0x4, ignore_list)
|
||||||
};
|
};
|
||||||
return this->parent_unit->get_world_3d()->get_direct_space_state()->intersect_ray(query).is_empty();
|
bool const can_see{this->parent_unit->get_world_3d()->get_direct_space_state()->intersect_ray(query).is_empty()};
|
||||||
|
gd::UtilityFunctions::print(this->parent_unit->get_path(), can_see ? " can see " : " can't see ", this->target_node->get_path());
|
||||||
|
return can_see;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnitWorldState::get_is_at_target() const {
|
bool UnitWorldState::get_is_at_target() const {
|
||||||
|
|
Loading…
Reference in a new issue