feat: units use navigation obstacle avoidance

This commit is contained in:
Sara 2024-08-04 16:27:46 +02:00
parent f883d7d67e
commit 0e8bcf4442
14 changed files with 196 additions and 129 deletions

View file

@ -4,12 +4,15 @@
[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="Goal" id="Goal_1c3rq"] [sub_resource type="Goal" id="Goal_1c3rq"]
requirements_dict = {
"has_target": false
}
desired_state_dict = { desired_state_dict = {
"is_health_safe": true "is_health_safe": true
} }
[sub_resource type="SphereShape3D" id="SphereShape3D_5pqvg"] [sub_resource type="SphereShape3D" id="SphereShape3D_5pqvg"]
radius = 8.42531 radius = 15.6018
[sub_resource type="SphereShape3D" id="SphereShape3D_drlm2"] [sub_resource type="SphereShape3D" id="SphereShape3D_drlm2"]
radius = 1.0 radius = 1.0
@ -25,7 +28,7 @@ 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)
[node name="Unit" type="Unit"] [node name="Tank" type="Unit"]
configure_team = 3 configure_team = 3
collision_layer = 6 collision_layer = 6
collision_mask = 0 collision_mask = 0
@ -48,6 +51,10 @@ unique_name_in_owner = true
path_desired_distance = 0.5 path_desired_distance = 0.5
target_desired_distance = 0.2 target_desired_distance = 0.2
path_height_offset = 0.5 path_height_offset = 0.5
avoidance_enabled = true
radius = 0.75
time_horizon_agents = 4.0
time_horizon_obstacles = 4.0
[node name="AwarenessArea" type="Area3D" parent="."] [node name="AwarenessArea" type="Area3D" parent="."]
unique_name_in_owner = true unique_name_in_owner = true
@ -55,9 +62,10 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1216, 3.55442)
collision_layer = 0 collision_layer = 0
collision_mask = 2 collision_mask = 2
input_ray_pickable = false input_ray_pickable = false
monitorable = 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, -0.238092) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.735143)
shape = SubResource("SphereShape3D_5pqvg") shape = SubResource("SphereShape3D_5pqvg")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."] [node name="AnimationPlayer" type="AnimationPlayer" parent="."]

View file

@ -2,11 +2,13 @@
[ext_resource type="AnimationLibrary" uid="uid://crkh5gahl2ci6" path="res://Animation/bean_characters.res" id="1_70627"] [ext_resource type="AnimationLibrary" uid="uid://crkh5gahl2ci6" path="res://Animation/bean_characters.res" id="1_70627"]
[sub_resource type="SphereShape3D" id="SphereShape3D_drlm2"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_q7mxo"]
radius = 1.0 radius = 0.586696
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n4q15"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n4q15"]
specular_mode = 1
albedo_color = Color(0.407843, 1, 0.447059, 1) albedo_color = Color(0.407843, 1, 0.447059, 1)
roughness = 0.0
[sub_resource type="CapsuleMesh" id="CapsuleMesh_5r0b3"] [sub_resource type="CapsuleMesh" id="CapsuleMesh_5r0b3"]
material = SubResource("StandardMaterial3D_n4q15") material = SubResource("StandardMaterial3D_n4q15")
@ -16,7 +18,7 @@ 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)
[node name="Unit" type="Unit"] [node name="Player" type="Unit"]
configure_team = 1 configure_team = 1
collision_layer = 6 collision_layer = 6
collision_mask = 0 collision_mask = 0
@ -36,7 +38,12 @@ unique_name_in_owner = true
path_desired_distance = 0.2 path_desired_distance = 0.2
target_desired_distance = 0.5 target_desired_distance = 0.5
path_height_offset = 0.5 path_height_offset = 0.5
avoidance_enabled = true
radius = 0.75
time_horizon_agents = 4.0
time_horizon_obstacles = 4.0
debug_enabled = true debug_enabled = true
debug_path_custom_point_size = 7.0
[node name="AnimationPlayer" type="AnimationPlayer" parent="."] [node name="AnimationPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true unique_name_in_owner = true
@ -53,7 +60,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.39151, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="."] [node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
shape = SubResource("SphereShape3D_drlm2") shape = SubResource("CapsuleShape3D_q7mxo")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."] [node name="MeshInstance3D" type="MeshInstance3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)

View file

@ -151,7 +151,7 @@ mesh = SubResource("PlaneMesh_hohcb")
skeleton = NodePath("../../../..") skeleton = NodePath("../../../..")
[node name="Floor2" type="StaticBody3D" parent="WorldEnvironment/NavigationRegion3D"] [node name="Floor2" type="StaticBody3D" parent="WorldEnvironment/NavigationRegion3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.901, 0, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.9976, 0, 0)
collision_layer = 5 collision_layer = 5
[node name="CollisionShape3D" type="CollisionShape3D" parent="WorldEnvironment/NavigationRegion3D/Floor2"] [node name="CollisionShape3D" type="CollisionShape3D" parent="WorldEnvironment/NavigationRegion3D/Floor2"]
@ -219,139 +219,139 @@ transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -23.14
[node name="ModernTrain6" parent="WorldEnvironment/NavigationRegion3D" instance=ExtResource("6_favl6")] [node name="ModernTrain6" parent="WorldEnvironment/NavigationRegion3D" instance=ExtResource("6_favl6")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -16.443, 0.268182, 3.2886) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -16.443, 0.268182, 3.2886)
[node name="Node3D" type="Node3D" parent="WorldEnvironment"] [node name="Tracks" type="Node3D" parent="WorldEnvironment"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 7.25984) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 7.25984)
[node name="track2" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track2" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0)
[node name="track3" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track3" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0)
[node name="track4" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track4" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0)
[node name="track5" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track5" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0)
[node name="track6" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track6" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0)
[node name="track7" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track7" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0)
[node name="track8" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track8" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0)
[node name="track9" parent="WorldEnvironment/Node3D" instance=ExtResource("7_8fuqb")] [node name="track9" parent="WorldEnvironment/Tracks" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0)
[node name="Node3D2" type="Node3D" parent="WorldEnvironment"] [node name="Tracks2" type="Node3D" parent="WorldEnvironment"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3.17094) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 3.17094)
[node name="track2" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track2" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0)
[node name="track3" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track3" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0)
[node name="track4" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track4" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0)
[node name="track5" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track5" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0)
[node name="track6" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track6" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0)
[node name="track7" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track7" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0)
[node name="track8" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track8" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0)
[node name="track9" parent="WorldEnvironment/Node3D2" instance=ExtResource("7_8fuqb")] [node name="track9" parent="WorldEnvironment/Tracks2" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0)
[node name="Node3D3" type="Node3D" parent="WorldEnvironment"] [node name="Tracks3" type="Node3D" parent="WorldEnvironment"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4.67443) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4.67443)
[node name="track2" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track2" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0)
[node name="track3" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track3" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0)
[node name="track4" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track4" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0)
[node name="track5" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track5" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0)
[node name="track6" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track6" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0)
[node name="track7" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track7" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0)
[node name="track8" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track8" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0)
[node name="track9" parent="WorldEnvironment/Node3D3" instance=ExtResource("7_8fuqb")] [node name="track9" parent="WorldEnvironment/Tracks3" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0)
[node name="Node3D4" type="Node3D" parent="WorldEnvironment"] [node name="Tracks4" type="Node3D" parent="WorldEnvironment"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.8802, 0, 7.25984) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.8802, 0, 7.25984)
[node name="track2" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track2" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0)
[node name="track3" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track3" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0)
[node name="track4" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track4" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0)
[node name="track5" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track5" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0)
[node name="track6" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track6" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0)
[node name="track7" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track7" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0)
[node name="track8" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track8" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0)
[node name="track9" parent="WorldEnvironment/Node3D4" instance=ExtResource("7_8fuqb")] [node name="track9" parent="WorldEnvironment/Tracks4" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0)
[node name="Node3D5" type="Node3D" parent="WorldEnvironment"] [node name="Tracks5" type="Node3D" parent="WorldEnvironment"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.8802, 0, 3.17094) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.8802, 0, 3.17094)
[node name="track2" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track2" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -8.66062, 1.8999e-07, 0)
[node name="track3" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track3" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -6.18288, 1.8999e-07, 0)
[node name="track4" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track4" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.69507, 1.8999e-07, 0)
[node name="track5" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track5" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -1.21011, 1.8999e-07, 0)
[node name="track6" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track6" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.27448, 1.8999e-07, 0)
[node name="track7" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track7" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.75945, 1.8999e-07, 0)
[node name="track8" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track8" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 6.24283, 1.8999e-07, 0)
[node name="track9" parent="WorldEnvironment/Node3D5" instance=ExtResource("7_8fuqb")] [node name="track9" parent="WorldEnvironment/Tracks5" instance=ExtResource("7_8fuqb")]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278, 1.8999e-07, 0)
[node name="Player" parent="." instance=ExtResource("3_wl7wm")] [node name="Player" parent="." instance=ExtResource("3_wl7wm")]
@ -360,9 +360,6 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.16025, 1.8999e-07, -2.07711
[node name="Player2" parent="." instance=ExtResource("3_wl7wm")] [node name="Player2" parent="." instance=ExtResource("3_wl7wm")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.28022, 1.8999e-07, -4.279) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.28022, 1.8999e-07, -4.279)
[node name="Tank" parent="." instance=ExtResource("4_0o33v")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.70922, -7.63685e-07, 3.72251)
[node name="Tank2" parent="." instance=ExtResource("4_0o33v")] [node name="Tank2" parent="." instance=ExtResource("4_0o33v")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.4143, -7.63685e-07, 5.91707) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.4143, -7.63685e-07, 5.91707)

View file

@ -1,5 +1,6 @@
#include "enemy_world_state.hpp" #include "enemy_world_state.hpp"
#include "entity_health.hpp" #include "entity_health.hpp"
#include "godot_cpp/variant/utility_functions.hpp"
#include "unit.hpp" #include "unit.hpp"
#include "goap/goal.hpp" #include "goap/goal.hpp"
#include "utils/godot_macros.hpp" #include "utils/godot_macros.hpp"
@ -23,38 +24,19 @@ void EnemyWorldState::_ready() { GDGAMEONLY();
} }
void EnemyWorldState::on_awareness_entered(gd::Node3D *node) { void EnemyWorldState::on_awareness_entered(gd::Node3D *node) {
Unit *unit{gd::Object::cast_to<Unit>(node)}; if(Unit *unit{gd::Object::cast_to<Unit>(node)}) {
if(unit == nullptr) gd::UtilityFunctions::print("!!! ", this->get_path(), ": ", node->get_path(), " entered awareness");
return; this->add_aware_unit(unit);
if(unit == this->parent_unit) }
return;
if(unit->get_entity_health()->get_is_dead())
return;
unit->get_entity_health()->connect("death", this->aware_unit_death.bind(unit));
this->known_enemies.push_back(unit);
this->try_set_target(this->select_target_from_known());
} }
void EnemyWorldState::on_awareness_exited(gd::Node3D *node) { void EnemyWorldState::on_awareness_exited(gd::Node3D *node) {
Unit *unit{gd::Object::cast_to<Unit>(node)}; Unit *unit{gd::Object::cast_to<Unit>(node)};
if(unit == nullptr) this->remove_aware_unit(unit);
return;
if(this->known_enemies.has(unit)) {
unit->get_entity_health()->disconnect("death", this->aware_unit_death.bind(unit));
this->known_enemies.erase(unit);
}
if(unit == this->target_node) {
this->select_and_set_target();
}
} }
void EnemyWorldState::on_damaged(int remaining, int delta, Unit *source) { void EnemyWorldState::on_damaged(int remaining, int delta, Unit *source) {
if(!this->known_enemies.has(source)) { this->add_aware_unit(source);
source->get_entity_health()->connect("death", this->aware_unit_death.bind(source));
this->known_enemies.push_back(source);
}
if(!this->parent_unit->has_plan())
this->try_set_target(this->select_target_from_known());
} }
Unit *EnemyWorldState::select_target_from_known_with_priority(float *out_priority) { Unit *EnemyWorldState::select_target_from_known_with_priority(float *out_priority) {
@ -75,6 +57,37 @@ Unit *EnemyWorldState::select_target_from_known() {
return this->select_target_from_known_with_priority(&dummy); return this->select_target_from_known_with_priority(&dummy);
} }
void EnemyWorldState::add_aware_unit(Unit *unit) {
if(unit == nullptr)
return;
if(unit == this->parent_unit)
return;
if(this->known_enemies.has(unit))
return;
if(unit->get_entity_health()->get_is_dead())
return;
if(!this->get_is_unit_enemy(unit))
return;
unit->get_entity_health()->connect("death", this->aware_unit_death.bind(unit));
this->known_enemies.insert(0, unit);
if(!this->parent_unit->has_plan())
this->try_set_target(this->select_target_from_known());
else
gd::UtilityFunctions::print("!!! ", this->get_path(), " not replanning because a plan is already in motion");
gd::UtilityFunctions::print("!!! ", this->get_path(), " found ", unit->get_path());
}
void EnemyWorldState::remove_aware_unit(Unit *unit) {
if(unit == nullptr)
return;
if(!this->known_enemies.has(unit))
return;
unit->get_entity_health()->disconnect("death", this->aware_unit_death.bind(unit));
this->known_enemies.erase(unit);
if(unit == this->target_node)
this->select_and_set_target();
}
void EnemyWorldState::on_aware_unit_death(Unit *_, Unit *dead_entity) { void EnemyWorldState::on_aware_unit_death(Unit *_, Unit *dead_entity) {
this->on_awareness_exited(dead_entity); this->on_awareness_exited(dead_entity);
} }

View file

@ -28,6 +28,8 @@ public:
//! Shorthand for select_target_from_known_with_priority(nullptr) //! Shorthand for select_target_from_known_with_priority(nullptr)
Unit *select_target_from_known(); Unit *select_target_from_known();
private: private:
void add_aware_unit(Unit *unit);
void remove_aware_unit(Unit *unit);
void select_and_set_target(); void select_and_set_target();
void on_aware_unit_death(Unit *_, Unit *dead_entity); void on_aware_unit_death(Unit *_, Unit *dead_entity);
float calculate_priority(Unit *target); float calculate_priority(Unit *target);

View file

@ -1,10 +1,10 @@
#include "planner.hpp" #include "planner.hpp"
#include "action_db.hpp" #include "action_db.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/engine.hpp>
#include <godot_cpp/classes/global_constants.hpp> #include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/templates/hashfuncs.hpp>
#include <godot_cpp/variant/utility_functions.hpp> #include <godot_cpp/variant/utility_functions.hpp>
namespace goap { namespace goap {
@ -85,8 +85,8 @@ void Planner::_bind_methods() {
GDPROPERTY_HINTED(actions_inspector, gd::Variant::ARRAY, gd::PROPERTY_HINT_ARRAY_TYPE, ActionDB::get_array_hint()); GDPROPERTY_HINTED(actions_inspector, gd::Variant::ARRAY, gd::PROPERTY_HINT_ARRAY_TYPE, ActionDB::get_array_hint());
} }
void Planner::_enter_tree() { GDGAMEONLY(); void Planner::_ready() { GDGAMEONLY();
this->world_state = this->get_node<ActorWorldState>("../ActorWorldState"); this->world_state = this->get_node<ActorWorldState>("%ActorWorldState");
} }
Plan Planner::plan_for_goal(gd::Ref<Goal> goal) { Plan Planner::plan_for_goal(gd::Ref<Goal> goal) {

View file

@ -53,7 +53,7 @@ class Planner : public gd::Node {
GDCLASS(Planner, gd::Node); GDCLASS(Planner, gd::Node);
static void _bind_methods(); static void _bind_methods();
public: public:
virtual void _enter_tree() override; virtual void _ready() override;
//! Compute a plan to achieve the passed `Goal`. //! Compute a plan to achieve the passed `Goal`.
Plan plan_for_goal(gd::Ref<Goal> goal); Plan plan_for_goal(gd::Ref<Goal> goal);

View file

@ -21,11 +21,11 @@
#include <godot_cpp/core/defs.hpp> #include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp> #include <godot_cpp/godot.hpp>
using namespace godot; namespace gd = godot;
void initialize_gdextension_types(ModuleInitializationLevel p_level) void initialize_gdextension_types(gd::ModuleInitializationLevel p_level)
{ {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { if (p_level != gd::MODULE_INITIALIZATION_LEVEL_SCENE) {
return; return;
} }
utils::godot_cpp_utils_register_types(); utils::godot_cpp_utils_register_types();
@ -40,24 +40,24 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
goap::ActionDB::register_action<TankSelfHeal>(); goap::ActionDB::register_action<TankSelfHeal>();
goap::ActionDB::register_action<TakeCover>(); goap::ActionDB::register_action<TakeCover>();
ClassDB::register_class<goap::ActorWorldState>(); gd::ClassDB::register_class<goap::ActorWorldState>();
ClassDB::register_class<goap::Goal>(); gd::ClassDB::register_class<goap::Goal>();
ClassDB::register_class<goap::Planner>(); gd::ClassDB::register_class<goap::Planner>();
ClassDB::register_class<goap::State>(); gd::ClassDB::register_class<goap::State>();
ClassDB::register_class<MoveTo>(); gd::ClassDB::register_class<MoveTo>();
ClassDB::register_class<Animate>(); gd::ClassDB::register_class<Animate>();
ClassDB::register_class<Activate>(); gd::ClassDB::register_class<Activate>();
ClassDB::register_class<UnitWorldState>(); gd::ClassDB::register_class<UnitWorldState>();
ClassDB::register_class<EnemyWorldState>(); gd::ClassDB::register_class<EnemyWorldState>();
ClassDB::register_class<GoalMarker>(); gd::ClassDB::register_class<GoalMarker>();
ClassDB::register_class<Unit>(); gd::ClassDB::register_class<Unit>();
ClassDB::register_class<RTSGameMode>(); gd::ClassDB::register_class<RTSGameMode>();
ClassDB::register_class<RTSPlayer>(); gd::ClassDB::register_class<RTSPlayer>();
ClassDB::register_class<EntityHealth>(); gd::ClassDB::register_class<EntityHealth>();
ClassDB::register_class<NavMarker>(); gd::ClassDB::register_class<NavMarker>();
ClassDB::register_class<NavRoom>(); gd::ClassDB::register_class<NavRoom>();
} }
extern "C" extern "C"
@ -65,9 +65,9 @@ extern "C"
// Initialization // Initialization
GDExtensionBool GDE_EXPORT metro_rts_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) GDExtensionBool GDE_EXPORT metro_rts_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
{ {
GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); gd::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_gdextension_types); init_obj.register_initializer(initialize_gdextension_types);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); init_obj.set_minimum_library_initialization_level(gd::MODULE_INITIALIZATION_LEVEL_SCENE);
return init_obj.init(); return init_obj.init();
} }

View file

@ -7,37 +7,39 @@
void MoveTo::_bind_methods() {} void MoveTo::_bind_methods() {}
void MoveTo::_ready() { void MoveTo::_ready() {
this->parent_node3d = Object::cast_to<gd::Node3D>(this->get_parent()); this->parent_unit = Object::cast_to<Unit>(this->get_parent());
this->agent = this->get_node<gd::NavigationAgent3D>("../NavigationAgent3D"); this->agent = this->get_node<gd::NavigationAgent3D>("../NavigationAgent3D");
if(this->target_node == nullptr) { if(this->target_node == nullptr) {
this->state_ended(); this->state_ended();
gd::UtilityFunctions::push_warning("failed to start MoveTo state due to missing target"); gd::UtilityFunctions::push_warning("failed to start MoveTo state due to missing target");
return; return;
} }
this->agent->set_target_position(this->target_node->get_global_position()); this->agent->connect("velocity_computed", this->nav_velocity_computed);
this->calculate_path(); this->calculate_path();
gd::UtilityFunctions::print(this->parent_node3d->get_path(), " MoveTo ", this->target_node->get_path()); gd::UtilityFunctions::print(this->parent_unit->get_path(), " MoveTo ", this->target_node->get_path());
} }
void MoveTo::_end_state() { void MoveTo::_end_state() {
this->agent->set_target_position(this->parent_node3d->get_global_position()); this->agent->disconnect("velocity_computed", this->nav_velocity_computed);
this->agent->set_target_position(this->parent_unit->get_global_position());
} }
void MoveTo::_process(double delta_time) { void MoveTo::_process(double delta_time) {
gd::Vector3 const pos = this->parent_node3d->get_global_position(); gd::Vector3 const pos = this->parent_unit->get_global_position();
gd::Vector3 const target = this->agent->get_next_path_position(); gd::Vector3 const target = this->agent->get_next_path_position();
gd::Vector3 const direction = (target - pos).normalized(); gd::Vector3 const direction = (target - pos).normalized();
this->parent_node3d->set_global_position(pos + direction * delta_time); this->agent->set_velocity(direction);
this->parent_node3d->look_at(pos - gd::Vector3{direction.x, 0.f, direction.z});
bool const navigation_finished{this->agent->is_navigation_finished()}; bool const navigation_finished{this->agent->is_navigation_finished()};
if(this->is_action_done_interrupt() || navigation_finished) if(this->is_action_done_interrupt() || navigation_finished)
this->state_ended(); this->state_ended();
if((utils::time_seconds() - this->last_repath) > this->get_repath_interval()) if((utils::time_seconds() - this->last_repath) > this->get_repath_interval())
this->calculate_path(); this->calculate_path();
} }
void MoveTo::_physics_process(double delta) {
this->parent_unit->move_and_slide();
}
void MoveTo::calculate_path() { void MoveTo::calculate_path() {
gd::Vector3 const target_pos{this->target_node->get_global_position()}; gd::Vector3 const target_pos{this->target_node->get_global_position()};
this->agent->set_target_position(target_pos); this->agent->set_target_position(target_pos);
@ -45,6 +47,14 @@ void MoveTo::calculate_path() {
this->target_position_at_last = target_pos; this->target_position_at_last = target_pos;
} }
void MoveTo::on_velocity_computed(gd::Vector3 vel) {
gd::Vector3 const pos{this->parent_unit->get_global_position()};
gd::Vector3 const target_dir{(this->agent->get_next_path_position() - pos).normalized()};
// recalculate if avoidance is causing the motion to lock up
if(target_dir.dot(vel.normalized()) < 0.25f)
this->calculate_path();
}
float MoveTo::target_delta_position() const { float MoveTo::target_delta_position() const {
return this->target_position_at_last return this->target_position_at_last
.distance_to(this->target_node->get_global_position()); .distance_to(this->target_node->get_global_position());
@ -52,7 +62,7 @@ float MoveTo::target_delta_position() const {
float MoveTo::distance_to_target() const { float MoveTo::distance_to_target() const {
return this->target_position_at_last return this->target_position_at_last
.distance_to(this->parent_node3d->get_global_position()); .distance_to(this->parent_unit->get_global_position());
} }
double MoveTo::get_repath_interval() const { double MoveTo::get_repath_interval() const {

View file

@ -1,6 +1,7 @@
#ifndef RTS_STATES_HPP #ifndef RTS_STATES_HPP
#define RTS_STATES_HPP #define RTS_STATES_HPP
#include "unit.hpp"
#include "goap/state.hpp" #include "goap/state.hpp"
#include <godot_cpp/classes/animation_player.hpp> #include <godot_cpp/classes/animation_player.hpp>
#include <godot_cpp/classes/navigation_agent3d.hpp> #include <godot_cpp/classes/navigation_agent3d.hpp>
@ -14,14 +15,17 @@ public:
virtual void _ready() override; virtual void _ready() override;
virtual void _end_state() override; virtual void _end_state() override;
virtual void _process(double delta_time) override; virtual void _process(double delta_time) override;
virtual void _physics_process(double delta_time) override;
void calculate_path(); void calculate_path();
void on_velocity_computed(gd::Vector3 vel);
float target_delta_position() const; float target_delta_position() const;
float distance_to_target() const; float distance_to_target() const;
double get_repath_interval() const; double get_repath_interval() const;
public: public:
gd::Node3D *target_node{nullptr}; gd::Node3D *target_node{nullptr};
private: private:
gd::Node3D *parent_node3d{nullptr}; gd::Callable nav_velocity_computed{callable_mp(this, &MoveTo::on_velocity_computed)};
Unit *parent_unit{nullptr};
gd::NavigationAgent3D *agent{nullptr}; gd::NavigationAgent3D *agent{nullptr};
gd::Vector3 target_position_at_last{}; gd::Vector3 target_position_at_last{};
double last_repath{0.0}; double last_repath{0.0};

View file

@ -2,6 +2,7 @@
#include "entity_health.hpp" #include "entity_health.hpp"
#include "goap/action.hpp" #include "goap/action.hpp"
#include "goap/goal.hpp" #include "goap/goal.hpp"
#include "rts_states.hpp"
#include "utils/godot_macros.hpp" #include "utils/godot_macros.hpp"
#include <godot_cpp/classes/navigation_agent3d.hpp> #include <godot_cpp/classes/navigation_agent3d.hpp>
#include <godot_cpp/variant/callable_method_pointer.hpp> #include <godot_cpp/variant/callable_method_pointer.hpp>
@ -18,6 +19,7 @@ void Unit::_bind_methods() {
void Unit::_enter_tree() { GDGAMEONLY(); void Unit::_enter_tree() { GDGAMEONLY();
this->agent = this->get_node<gd::NavigationAgent3D>("%NavigationAgent3D"); this->agent = this->get_node<gd::NavigationAgent3D>("%NavigationAgent3D");
this->agent->connect("velocity_computed", callable_mp(this, &Unit::on_velocity_computed));
this->planner = this->get_node<goap::Planner>("%Planner"); this->planner = this->get_node<goap::Planner>("%Planner");
this->world_state = this->get_node<UnitWorldState>("%ActorWorldState"); this->world_state = this->get_node<UnitWorldState>("%ActorWorldState");
this->world_state->connect("attention_changed", callable_mp(this, &Unit::stop_plan)); this->world_state->connect("attention_changed", callable_mp(this, &Unit::stop_plan));
@ -111,16 +113,15 @@ EntityHealth *Unit::get_entity_health() {
return this->health; return this->health;
} }
void Unit::set_goal_and_plan(gd::Ref<goap::Goal> goal) { void Unit::on_velocity_computed(gd::Vector3 vel) {
this->current_goal = goal; gd::Vector3 const pos{this->get_global_position()};
if(goal.is_null()) { gd::Vector3 const target_dir{(this->agent->get_next_path_position() - pos).normalized()};
this->current_plan.clear(); if(vel.x == 0 && vel.z == 0)
} else { return;
this->current_plan = this->planner->plan_for_goal(goal); if(gd::Object::cast_to<MoveTo>(this->state) == nullptr)
if(this->current_plan.is_empty()) { return;
this->current_goal.unref(); this->set_velocity(vel);
} this->look_at(pos - gd::Vector3{vel.x, 0.f, vel.z});
}
} }
void Unit::destroy_state() { void Unit::destroy_state() {
@ -166,3 +167,15 @@ void Unit::next_action() {
void Unit::replan_goal() { void Unit::replan_goal() {
this->begin_goal(this->current_goal); this->begin_goal(this->current_goal);
} }
void Unit::set_goal_and_plan(gd::Ref<goap::Goal> goal) {
this->current_goal = goal;
if(goal.is_null()) {
this->current_plan.clear();
} else {
this->current_plan = this->planner->plan_for_goal(goal);
if(this->current_plan.is_empty()) {
this->current_goal.unref();
}
}
}

View file

@ -44,11 +44,12 @@ public:
bool has_plan() const; bool has_plan() const;
EntityHealth *get_entity_health(); EntityHealth *get_entity_health();
private: private:
void set_goal_and_plan(gd::Ref<goap::Goal> goal); void on_velocity_computed(gd::Vector3 vel);
void destroy_state(); void destroy_state();
void state_finished(); void state_finished();
void next_action(); void next_action();
void replan_goal(); void replan_goal();
void set_goal_and_plan(gd::Ref<goap::Goal> goal);
private: private:
gd::Callable on_state_finished{callable_mp(this, &Unit::state_finished)}; gd::Callable on_state_finished{callable_mp(this, &Unit::state_finished)};
gd::Callable on_plan_failed{callable_mp(this, &Unit::replan_goal)}; gd::Callable on_plan_failed{callable_mp(this, &Unit::replan_goal)};

View file

@ -14,6 +14,7 @@ void UnitWorldState::_bind_methods() {
GDFUNCTION(get_can_see_target); GDFUNCTION(get_can_see_target);
GDFUNCTION(get_is_target_dead); GDFUNCTION(get_is_target_dead);
GDFUNCTION(get_is_at_target); GDFUNCTION(get_is_at_target);
GDFUNCTION(get_has_target);
GDFUNCTION(get_target_node); GDFUNCTION(get_target_node);
GDFUNCTION(get_is_target_enemy); GDFUNCTION(get_is_target_enemy);
GDFUNCTION(get_is_in_melee_range); GDFUNCTION(get_is_in_melee_range);
@ -24,6 +25,7 @@ void UnitWorldState::_bind_methods() {
void UnitWorldState::_enter_tree() { GDGAMEONLY(); void UnitWorldState::_enter_tree() { GDGAMEONLY();
this->parent_unit = gd::Object::cast_to<Unit>(this->get_parent()); this->parent_unit = gd::Object::cast_to<Unit>(this->get_parent());
gd::UtilityFunctions::print("!!! ", this->get_path(), ": is part of ", this->parent_unit->get_path());
this->agent = this->get_node<gd::NavigationAgent3D>("%NavigationAgent3D"); this->agent = this->get_node<gd::NavigationAgent3D>("%NavigationAgent3D");
this->eye_location = this->get_node<gd::Node3D>("%Eyes"); this->eye_location = this->get_node<gd::Node3D>("%Eyes");
this->health = this->get_node<EntityHealth>("%EntityHealth"); this->health = this->get_node<EntityHealth>("%EntityHealth");
@ -61,8 +63,12 @@ bool UnitWorldState::get_is_at_target() const {
return (target - current).length_squared() <= min_dist * min_dist; return (target - current).length_squared() <= min_dist * min_dist;
} }
bool UnitWorldState::get_has_target() const {
return this->target_node != nullptr;
}
bool UnitWorldState::get_is_target_dead() const { bool UnitWorldState::get_is_target_dead() const {
if(EntityHealth *health{this->target_node->get_node<EntityHealth>("EntityHealth")}) if(EntityHealth *health{this->target_node->get_node<EntityHealth>("%EntityHealth")})
return health->get_injury_current() <= 0.f; return health->get_injury_current() <= 0.f;
return false; return false;
} }
@ -73,6 +79,10 @@ bool UnitWorldState::get_is_target_unit() const {
bool UnitWorldState::get_is_target_enemy() const { bool UnitWorldState::get_is_target_enemy() const {
Unit *unit{gd::Object::cast_to<Unit>(this->target_node)}; Unit *unit{gd::Object::cast_to<Unit>(this->target_node)};
return unit != nullptr && this->get_is_unit_enemy(unit);
}
bool UnitWorldState::get_is_unit_enemy(Unit *unit) const {
return unit != nullptr return unit != nullptr
&& unit->get_team() != UnitTeam::Neutral && unit->get_team() != UnitTeam::Neutral
&& unit->get_team() != this->parent_unit->get_team(); && unit->get_team() != this->parent_unit->get_team();

View file

@ -15,9 +15,11 @@ public:
virtual void _enter_tree() override; virtual void _enter_tree() override;
bool get_can_see_target() const; bool get_can_see_target() const;
bool get_is_at_target() const; bool get_is_at_target() const;
bool get_has_target() const;
bool get_is_target_dead() const; bool get_is_target_dead() const;
bool get_is_target_unit() const; bool get_is_target_unit() const;
bool get_is_target_enemy() const; bool get_is_target_enemy() const;
bool get_is_unit_enemy(Unit *unit) const;
bool get_is_in_melee_range() const; bool get_is_in_melee_range() const;
bool get_is_health_safe() const; bool get_is_health_safe() const;
gd::Vector3 get_parent_global_position() const; gd::Vector3 get_parent_global_position() const;