diff --git a/godot/GameObjects/enemy_unit.tscn b/godot/GameObjects/enemy_unit.tscn index 13d8c55..b1f90b1 100644 --- a/godot/GameObjects/enemy_unit.tscn +++ b/godot/GameObjects/enemy_unit.tscn @@ -7,8 +7,7 @@ [sub_resource type="SphereShape3D" id="SphereShape3D_5pqvg"] radius = 15.6018 -[sub_resource type="SphereShape3D" id="SphereShape3D_drlm2"] -radius = 1.0 +[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_wwkx3"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ss47r"] albedo_color = Color(1, 0.24, 0.24, 1) @@ -32,7 +31,7 @@ available_goals_inspector = [ExtResource("1_jwvis"), ExtResource("1_b1qo1")] unique_name_in_owner = true [node name="Planner" type="Planner" parent="."] -actions_inspector = [3, 2, 4, 5, 1] +actions_inspector = [3, 2, 4, 1] unique_name_in_owner = true [node name="EntityHealth" type="EntityHealth" parent="."] @@ -41,7 +40,7 @@ unique_name_in_owner = true [node name="NavigationAgent3D" type="NavigationAgent3D" parent="."] unique_name_in_owner = true -path_desired_distance = 0.5 +path_desired_distance = 0.1 target_desired_distance = 0.2 path_height_offset = 0.5 avoidance_enabled = true @@ -77,7 +76,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.31501, 0) [node name="CollisionShape3D" type="CollisionShape3D" parent="."] transform = Transform3D(1, 0, 0, 0, 0.999222, -0.0394342, 0, 0.0394342, 0.999222, 0, 1.013, 0) -shape = SubResource("SphereShape3D_drlm2") +shape = SubResource("CapsuleShape3D_wwkx3") [node name="MeshInstance3D" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) diff --git a/godot/GameObjects/player_unit.tscn b/godot/GameObjects/player_unit.tscn index a115082..f19f9de 100644 --- a/godot/GameObjects/player_unit.tscn +++ b/godot/GameObjects/player_unit.tscn @@ -3,7 +3,6 @@ [ext_resource type="AnimationLibrary" uid="uid://crkh5gahl2ci6" path="res://Animation/bean_characters.res" id="1_70627"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_q7mxo"] -radius = 0.586696 [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n4q15"] specular_mode = 1 @@ -40,7 +39,7 @@ unique_name_in_owner = true [node name="NavigationAgent3D" type="NavigationAgent3D" parent="."] unique_name_in_owner = true -path_desired_distance = 0.2 +path_desired_distance = 0.1 target_desired_distance = 0.5 path_height_offset = 0.5 avoidance_enabled = true diff --git a/godot/Levels/test_level.tscn b/godot/Levels/test_level.tscn index 7e50217..ecbf2cc 100644 --- a/godot/Levels/test_level.tscn +++ b/godot/Levels/test_level.tscn @@ -9,10 +9,11 @@ [ext_resource type="PackedScene" uid="uid://ulvv4o73s48a" path="res://Environments/Models/KenneyTrains/track.glb" id="7_8fuqb"] [sub_resource type="NavigationMesh" id="NavigationMesh_8a2j6"] -vertices = PackedVector3Array(-5.65381, 0.408736, -1.70065, -5.40381, 0.408736, -2.70065, -8.40381, 0.408736, -2.95065, -9.15381, 0.408736, -1.70065, -8.15381, 0.408736, -6.70065, -9.15381, 0.408736, -9.20065, 6.09619, 0.408736, -6.70065, 6.34619, 0.408736, -4.70065, 9.34619, 0.408736, -4.70065, 9.34619, 0.408736, -9.20065, -7.40381, 4.65874, -5.70065, -7.40381, 4.65874, -3.70065, -1.65381, 4.65874, -3.70065, -1.65381, 4.65874, -5.70065, -0.403809, 4.65874, -5.70065, -0.403809, 4.65874, -3.70065, 5.34619, 4.65874, -3.70065, 5.34619, 4.65874, -5.70065, -7.15381, 0.408736, -5.45065, -7.15381, 0.408736, -3.95065, -1.90381, 0.408736, -3.95065, -1.90381, 0.408736, -5.45065, -0.153809, 0.408736, -5.45065, -0.153809, 0.408736, -3.95065, 5.09619, 0.408736, -3.95065, 5.09619, 0.408736, -5.45065, 1.84619, 0.408736, -2.70065, 2.09619, 0.408736, -1.70065, 4.84619, 0.408736, -1.45065, 6.09619, 0.408736, -2.70065, 4.84619, 0.408736, 0.799349, 3.09619, 0.408736, 1.04935, 3.34619, 0.408736, 5.29935, 7.09619, 0.408736, 5.29935, 7.34619, 0.408736, 8.04935, 9.34619, 0.408736, 8.04935, -3.90381, 0.408736, -1.45065, 0.346191, 0.408736, -1.45065, -3.90381, 0.408736, 0.799349, 0.346191, 0.408736, 0.799349, -5.90381, 0.408736, 1.04935, -5.40381, 0.408736, 5.29935, -29.1538, 0.408736, 1.04935, -29.1538, 0.408736, 3.04935, -27.1538, 0.408736, 3.04935, -26.9038, 0.408736, 1.29935, -12.6538, 0.408736, 1.29935, -7.40381, 0.408736, 5.54935, -12.4038, 0.408736, 4.79935, -12.1538, 0.408736, 8.04935, -7.40381, 0.408736, 8.04935, -26.1538, 4.65874, 2.29935, -26.1538, 4.65874, 4.29935, -20.4038, 4.65874, 4.29935, -20.4038, 4.65874, 2.29935, -19.1538, 4.65874, 2.29935, -19.1538, 4.65874, 4.29935, -13.4038, 4.65874, 4.29935, -13.4038, 4.65874, 2.29935, -25.9038, 0.408736, 2.54935, -25.9038, 0.408736, 4.04935, -20.6538, 0.408736, 4.04935, -20.6538, 0.408736, 2.54935, -18.9038, 0.408736, 2.54935, -18.9038, 0.408736, 4.04935, -13.6538, 0.408736, 4.04935, -13.6538, 0.408736, 2.54935, -12.6538, 0.408736, 5.29935, -26.9038, 0.408736, 5.29935, -29.1538, 0.408736, 8.04935, -6.40381, 4.65874, 6.29935, -6.40381, 4.65874, 8.04935, -0.653809, 4.65874, 8.04935, -0.653809, 4.65874, 6.29935, 0.596191, 4.65874, 6.29935, 0.596191, 4.65874, 8.04935, 6.34619, 4.65874, 8.04935, 6.34619, 4.65874, 6.29935, -6.15381, 0.408736, 6.54935, -6.15381, 0.408736, 8.04935, -0.903809, 0.408736, 8.04935, -0.903809, 0.408736, 6.54935, 0.846191, 0.408736, 6.54935, 0.846191, 0.408736, 8.04935, 6.09619, 0.408736, 8.04935, 6.09619, 0.408736, 6.54935) -polygons = [PackedInt32Array(1, 0, 2), PackedInt32Array(2, 0, 3), PackedInt32Array(2, 3, 4), PackedInt32Array(4, 3, 5), PackedInt32Array(7, 6, 8), PackedInt32Array(8, 6, 9), PackedInt32Array(4, 5, 6), PackedInt32Array(6, 5, 9), PackedInt32Array(13, 12, 10), PackedInt32Array(10, 12, 11), PackedInt32Array(17, 16, 14), PackedInt32Array(14, 16, 15), PackedInt32Array(21, 20, 18), PackedInt32Array(18, 20, 19), PackedInt32Array(25, 24, 22), PackedInt32Array(22, 24, 23), PackedInt32Array(27, 26, 28), PackedInt32Array(28, 26, 29), PackedInt32Array(31, 30, 32), PackedInt32Array(32, 30, 33), PackedInt32Array(35, 34, 33), PackedInt32Array(28, 29, 30), PackedInt32Array(30, 29, 8), PackedInt32Array(30, 8, 33), PackedInt32Array(33, 8, 35), PackedInt32Array(29, 7, 8), PackedInt32Array(0, 1, 36), PackedInt32Array(36, 1, 37), PackedInt32Array(37, 1, 26), PackedInt32Array(37, 26, 27), PackedInt32Array(37, 39, 36), PackedInt32Array(36, 39, 38), PackedInt32Array(40, 38, 41), PackedInt32Array(41, 38, 39), PackedInt32Array(41, 39, 31), PackedInt32Array(41, 31, 32), PackedInt32Array(44, 43, 45), PackedInt32Array(45, 43, 42), PackedInt32Array(45, 42, 46), PackedInt32Array(46, 42, 40), PackedInt32Array(41, 47, 40), PackedInt32Array(40, 47, 48), PackedInt32Array(40, 48, 46), PackedInt32Array(50, 49, 47), PackedInt32Array(47, 49, 48), PackedInt32Array(54, 53, 51), PackedInt32Array(51, 53, 52), PackedInt32Array(58, 57, 55), PackedInt32Array(55, 57, 56), PackedInt32Array(62, 61, 59), PackedInt32Array(59, 61, 60), PackedInt32Array(66, 65, 63), PackedInt32Array(63, 65, 64), PackedInt32Array(67, 48, 49), PackedInt32Array(44, 68, 43), PackedInt32Array(43, 68, 69), PackedInt32Array(67, 49, 68), PackedInt32Array(68, 49, 69), PackedInt32Array(73, 72, 70), PackedInt32Array(70, 72, 71), PackedInt32Array(77, 76, 74), PackedInt32Array(74, 76, 75), PackedInt32Array(81, 80, 78), PackedInt32Array(78, 80, 79), PackedInt32Array(85, 84, 82), PackedInt32Array(82, 84, 83)] +vertices = PackedVector3Array(-49.9439, 6.15874, -50.0795, -48.4439, 6.15874, -50.0795, -48.6939, 6.15874, -65.8295, -71.1939, 6.15874, -48.8295, -49.9439, 6.15874, -48.5795, -71.1939, 6.15874, -65.8295, 50.0561, 6.15874, -50.0795, 50.0561, 6.15874, -48.3295, 51.8061, 6.15874, -48.5795, 51.8061, 6.15874, -65.8295, -71.1939, 6.15874, 48.6705, -49.9439, 6.15874, 48.4205, 50.0561, 6.15874, 48.1705, 51.8061, 6.15874, 48.4205, 8.05612, 0.408735, -6.32945, 8.05612, 0.408735, -4.57945, 9.05612, 0.408735, -4.57945, 9.05612, 0.408735, -9.07945, -8.69388, 0.408735, -6.07945, -7.19388, 0.408735, -6.07945, -6.69388, 0.408735, -6.82945, -8.69388, 0.408735, -9.07945, 7.55612, 0.408735, -6.82945, 0.0561218, 0.408735, -1.32945, 1.55612, 0.408735, -1.82945, 1.55612, 0.408735, -2.57945, -6.69388, 0.408735, -2.57945, -4.19388, 0.408735, -1.82945, -7.19388, 0.408735, -3.07945, -8.69388, 0.408735, -1.82945, -3.69388, 0.408735, -1.32945, -3.69388, 0.408735, 0.920547, 0.0561218, 0.408735, 0.920547, 2.55612, 0.408735, 4.92055, 2.55612, 0.408735, 1.42055, 0.556122, 0.408735, 1.42055, -5.19388, 0.408735, 1.42055, -5.19388, 0.408735, 4.92055, -5.69388, 4.65874, -5.32945, -5.69388, 4.65874, -4.07945, -0.443878, 4.65874, -4.07945, -0.443878, 4.65874, -5.32945, 1.30612, 4.65874, -5.32945, 1.30612, 4.65874, -4.07945, 6.55612, 4.65874, -4.07945, 6.55612, 4.65874, -5.32945, -5.44388, 0.408735, -5.07945, -5.44388, 0.408735, -4.32945, -0.693878, 0.408735, -4.32945, -0.693878, 0.408735, -5.07945, 1.55612, 0.408735, -5.07945, 1.55612, 0.408735, -4.32945, 6.30612, 0.408735, -4.32945, 6.30612, 0.408735, -5.07945, 8.05612, 0.408735, -3.07945, 9.05612, 0.408735, 7.92055, 7.55612, 0.408735, 5.42055, 7.55612, 0.408735, 7.92055, 4.55612, 0.408735, -1.82945, 7.55612, 0.408735, -2.57945, 5.05612, 0.408735, 0.920547, 5.05612, 0.408735, -1.32945, 4.55612, 0.408735, 1.42055, 7.05612, 0.408735, 4.92055, -27.4439, 0.408735, 4.92055, -27.1939, 0.408735, 1.42055, -28.9439, 0.408735, 1.42055, -28.9439, 0.408735, 7.92055, -12.9439, 0.408735, 7.92055, -12.9439, 0.408735, 5.42055, -26.9439, 0.408735, 5.42055, -7.69388, 0.408735, 7.92055, -7.69388, 0.408735, 6.67055, -8.44388, 0.408735, 6.17055, -12.1939, 0.408735, 4.92055, -8.44388, 0.408735, 1.42055, -12.4439, 0.408735, 1.42055, -25.9439, 4.65874, 2.67055, -25.9439, 4.65874, 3.92055, -20.6939, 4.65874, 3.92055, -20.6939, 4.65874, 2.67055, -18.9439, 4.65874, 2.67055, -18.9439, 4.65874, 3.92055, -13.6939, 4.65874, 3.92055, -13.6939, 4.65874, 2.67055, -25.6939, 0.408735, 2.92055, -25.6939, 0.408735, 3.67055, -20.9439, 0.408735, 3.67055, -20.9439, 0.408735, 2.92055, -18.6939, 0.408735, 2.92055, -18.6939, 0.408735, 3.67055, -13.9439, 0.408735, 3.67055, -13.9439, 0.408735, 2.92055, -6.19388, 4.65874, 6.42055, -6.19388, 4.65874, 7.92055, -0.943878, 4.65874, 7.92055, -0.943878, 4.65874, 6.42055, 0.806122, 4.65874, 6.42055, 0.806122, 4.65874, 7.92055, 6.05612, 4.65874, 7.92055, 6.05612, 4.65874, 6.42055, -5.94388, 0.408735, 6.92055, -5.94388, 0.408735, 7.67055, -1.19388, 0.408735, 7.67055, -1.19388, 0.408735, 6.67055, 1.05612, 0.408735, 6.67055, 1.05612, 0.408735, 7.67055, 5.80612, 0.408735, 7.67055, 5.80612, 0.408735, 6.67055, 50.0561, 6.15874, 49.9205, 51.8061, 6.15874, 67.6705, -48.6939, 6.15874, 67.6705, -48.4439, 6.15874, 49.9205, -49.9439, 6.15874, 49.9205, -71.1939, 6.15874, 67.6705) +polygons = [PackedInt32Array(2, 1, 0), PackedInt32Array(0, 4, 3), PackedInt32Array(3, 5, 0), PackedInt32Array(0, 5, 2), PackedInt32Array(7, 6, 8), PackedInt32Array(8, 6, 9), PackedInt32Array(1, 2, 6), PackedInt32Array(6, 2, 9), PackedInt32Array(11, 10, 4), PackedInt32Array(4, 10, 3), PackedInt32Array(7, 8, 12), PackedInt32Array(12, 8, 13), PackedInt32Array(15, 14, 16), PackedInt32Array(16, 14, 17), PackedInt32Array(19, 18, 20), PackedInt32Array(20, 18, 21), PackedInt32Array(22, 20, 17), PackedInt32Array(17, 20, 21), PackedInt32Array(17, 14, 22), PackedInt32Array(24, 23, 25), PackedInt32Array(25, 23, 27), PackedInt32Array(25, 27, 26), PackedInt32Array(19, 28, 18), PackedInt32Array(18, 28, 29), PackedInt32Array(23, 32, 30), PackedInt32Array(30, 32, 31), PackedInt32Array(29, 28, 26), PackedInt32Array(27, 29, 26), PackedInt32Array(35, 34, 33), PackedInt32Array(32, 35, 31), PackedInt32Array(31, 35, 36), PackedInt32Array(36, 35, 37), PackedInt32Array(37, 35, 33), PackedInt32Array(23, 30, 27), PackedInt32Array(41, 40, 38), PackedInt32Array(38, 40, 39), PackedInt32Array(45, 44, 42), PackedInt32Array(42, 44, 43), PackedInt32Array(49, 48, 46), PackedInt32Array(46, 48, 47), PackedInt32Array(53, 52, 50), PackedInt32Array(50, 52, 51), PackedInt32Array(15, 16, 54), PackedInt32Array(54, 16, 55), PackedInt32Array(55, 57, 56), PackedInt32Array(24, 25, 58), PackedInt32Array(58, 25, 59), PackedInt32Array(59, 54, 60), PackedInt32Array(60, 54, 56), PackedInt32Array(56, 54, 55), PackedInt32Array(59, 61, 58), PackedInt32Array(34, 62, 33), PackedInt32Array(33, 62, 63), PackedInt32Array(62, 60, 63), PackedInt32Array(63, 60, 56), PackedInt32Array(60, 61, 59), PackedInt32Array(65, 64, 66), PackedInt32Array(66, 64, 67), PackedInt32Array(69, 68, 70), PackedInt32Array(70, 68, 67), PackedInt32Array(67, 64, 70), PackedInt32Array(72, 71, 73), PackedInt32Array(73, 71, 74), PackedInt32Array(74, 71, 69), PackedInt32Array(69, 71, 68), PackedInt32Array(76, 75, 74), PackedInt32Array(74, 75, 73), PackedInt32Array(80, 79, 77), PackedInt32Array(77, 79, 78), PackedInt32Array(84, 83, 81), PackedInt32Array(81, 83, 82), PackedInt32Array(88, 87, 85), PackedInt32Array(85, 87, 86), PackedInt32Array(92, 91, 89), PackedInt32Array(89, 91, 90), PackedInt32Array(96, 95, 93), PackedInt32Array(93, 95, 94), PackedInt32Array(100, 99, 97), PackedInt32Array(97, 99, 98), PackedInt32Array(102, 101, 103), PackedInt32Array(103, 101, 104), PackedInt32Array(108, 107, 105), PackedInt32Array(105, 107, 106), PackedInt32Array(12, 13, 109), PackedInt32Array(109, 13, 110), PackedInt32Array(112, 109, 111), PackedInt32Array(111, 109, 110), PackedInt32Array(113, 112, 111), PackedInt32Array(10, 11, 113), PackedInt32Array(10, 113, 114), PackedInt32Array(114, 113, 111)] geometry_parsed_geometry_type = 1 geometry_collision_mask = 4294967289 +agent_radius = 0.6 [sub_resource type="Goal" id="Goal_yju55"] desired_state_dict = { @@ -54,47 +55,47 @@ game_mode_prototype = ExtResource("1_4nchg") [node name="CoverMarker" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.999999, 0, -0.00101254, 0, 1, 0, 0.00101254, 0, 0.999999, 3.57243, 0.408736, -1.56782) +transform = Transform3D(0.999999, 0, -0.00101254, 0, 1, 0, 0.00101254, 0, 0.999999, 3.16586, 0.408736, -1.60341) [node name="CoverMarker3" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.00101258, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101258, 4.84619, 0.408736, -0.211887) +transform = Transform3D(-0.00101258, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101258, 5.05612, 0.408735, -0.198195) [node name="CoverMarker4" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, 3.55349, 0.408736, 0.984021) +transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, 3.21966, 0.408735, 1.42055) [node name="CoverMarker5" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, 1.75757, 0.408736, 0.927656) +transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, 1.32541, 0.408735, 1.42055) [node name="CoverMarker6" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, 0.346191, 0.408736, -0.0968238) +transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, 0.0561218, 0.408735, -0.256456) [node name="CoverMarker7" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.999999, 0, -0.00101271, 0, 1, 0, 0.00101271, 0, 0.999999, -5.38549, 0.408736, -1.66232) +transform = Transform3D(0.999999, 0, -0.00101271, 0, 1, 0, 0.00101271, 0, 0.999999, -6.17118, 0.408735, -1.82945) [node name="CoverMarker8" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, -5.39349, 0.408736, 0.98556) +transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, -4.91025, 0.408735, 1.32601) [node name="CoverMarker9" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.00101258, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101258, 7.2385, 0.408736, 6.86474) +transform = Transform3D(-0.00101258, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101258, 7.55612, 0.408735, 7.19658) [node name="CoverMarker16" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, -7.40381, 0.408736, 6.88524) +transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, -7.69388, 0.408735, 7.45576) [node name="CoverMarker17" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, -27.1371, 0.408736, 3.19975) +transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, -27.3177, 0.408735, 3.15346) [node name="CoverMarker18" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.00101258, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101258, -12.5116, 0.408736, 3.28973) +transform = Transform3D(-0.00101258, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101258, -13.9439, 0.408735, 3.27543) [node name="CoverMarker19" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 @@ -102,7 +103,7 @@ transform = Transform3D(0.999999, 4.37114e-08, -0.00101254, -4.36671e-08, 1, 4.3 [node name="CoverMarker20" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.999999, 4.37114e-08, 0.00101245, 4.36671e-08, 1, -4.37556e-08, -0.00101245, -4.37114e-08, -0.999999, -15.033, 0.408736, 5.29935) +transform = Transform3D(-0.999999, 4.37114e-08, 0.00101245, 4.36671e-08, 1, -4.37556e-08, -0.00101245, -4.37114e-08, -0.999999, -15.033, 0.408735, 5.42055) [node name="CoverMarker21" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 @@ -110,35 +111,31 @@ transform = Transform3D(0.999999, 4.37114e-08, -0.00101254, -4.36671e-08, 1, 4.3 [node name="CoverMarker22" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.999999, 4.37114e-08, 0.00101245, 4.36671e-08, 1, -4.37556e-08, -0.00101245, -4.37114e-08, -0.999999, -24.9126, 0.408736, 5.29935) +transform = Transform3D(-0.999999, 4.37114e-08, 0.00101245, 4.36671e-08, 1, -4.37556e-08, -0.00101245, -4.37114e-08, -0.999999, -24.9126, 0.408735, 5.42055) [node name="CoverMarker2" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.999999, 0, -0.00101254, 0, 1, 0, 0.00101254, 0, 0.999999, 1.73439, 0.408736, -1.68834) +transform = Transform3D(0.999999, 0, -0.00101254, 0, 1, 0, 0.00101254, 0, 0.999999, 1.95486, 0.408736, -1.68046) [node name="CoverMarker10" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.999999, 0, -0.00101254, 0, 1, 0, 0.00101254, 0, 0.999999, 4.21452, 0.408736, -6.70065) +transform = Transform3D(0.999999, 0, -0.00101254, 0, 1, 0, 0.00101254, 0, 0.999999, 4.1476, 0.408735, -6.82945) [node name="CoverMarker11" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, 4.66545, 0.408736, -2.70065) - -[node name="CoverMarker12" parent="NavRoom" instance=ExtResource("5_ta2oq")] -marker_type = 1 -transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, -6.83875, 0.408736, -2.82023) +transform = Transform3D(-0.999999, 0, 0.00101263, 0, 1, 0, -0.00101263, 0, -0.999999, 4.47796, 0.408735, -2.57945) [node name="CoverMarker13" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.999999, 0, -0.00101271, 0, 1, 0, 0.00101271, 0, 0.999999, -6.67478, 0.408736, -6.70065) +transform = Transform3D(0.999999, 0, -0.00101271, 0, 1, 0, 0.00101271, 0, 0.999999, -6.57121, 0.408735, -6.82945) [node name="CoverMarker14" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, -8.28839, 0.408736, -4.682) +transform = Transform3D(0.00101267, 0, 0.999999, 0, 1, 0, -0.999999, 0, 0.00101267, -7.19388, 0.408735, -4.682) [node name="CoverMarker15" parent="NavRoom" instance=ExtResource("5_ta2oq")] marker_type = 1 -transform = Transform3D(-0.00101276, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101276, 6.32876, 0.408736, -4.56123) +transform = Transform3D(-0.00101276, 0, -0.999999, 0, 1, 0, 0.999999, 0, -0.00101276, 8.05612, 0.408735, -4.59507) [node name="GenericMarker" parent="NavRoom" instance=ExtResource("5_ta2oq")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.44669, 0.408736, 3.42186) @@ -147,10 +144,10 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.44669, 0.408736, 3.42186) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.55474, 0.408736, 3.32429) [node name="GenericMarker3" parent="NavRoom" instance=ExtResource("5_ta2oq")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.82326, 0.408736, -2.82315) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.13664, 0.408735, -1.06315) [node name="GenericMarker4" parent="NavRoom" instance=ExtResource("5_ta2oq")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.17274, 0.408736, -7.57197) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7.17274, 0.408735, -7.57197) [node name="GenericMarker5" parent="NavRoom" instance=ExtResource("5_ta2oq")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.210692, 0.408736, -7.8647) @@ -165,13 +162,13 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -9.41558, 0.408736, 3.0966) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.4156, 0.408736, 7.0966) [node name="GenericMarker9" parent="NavRoom" instance=ExtResource("5_ta2oq")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.3762, 0.408736, 7.35681) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -19.2634, 0.408735, 7.18221) [node name="GenericMarker10" parent="NavRoom" instance=ExtResource("5_ta2oq")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -27.5728, 0.408736, 6.3485) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -27.5644, 0.408735, 6.49595) [node name="GenericMarker11" parent="NavRoom" instance=ExtResource("5_ta2oq")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -28.1582, 0.408736, 2.25021) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -28.3032, 0.408735, 2.73795) [node name="WorldEnvironment" type="WorldEnvironment" parent="."] environment = ExtResource("2_jq6bw") @@ -187,10 +184,10 @@ shadow_blur = 0.1 navigation_mesh = SubResource("NavigationMesh_8a2j6") [node name="ModernTrain" parent="WorldEnvironment/NavigationRegion3D" instance=ExtResource("6_favl6")] -transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -4.39772, 0.268182, -4.7114) +transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -2.84418, 0.268182, -4.7114) [node name="ModernTrain2" parent="WorldEnvironment/NavigationRegion3D" instance=ExtResource("6_favl6")] -transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 2.30532, 0.268182, -4.7114) +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.85886, 0.268182, -4.7114) [node name="ModernTrain3" parent="WorldEnvironment/NavigationRegion3D" instance=ExtResource("6_favl6")] transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -3.38777, 0.268182, 7.24505) @@ -210,7 +207,7 @@ collision_layer = 7 [node name="CSGBox3D2" type="CSGBox3D" parent="WorldEnvironment/NavigationRegion3D/brushwork"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -9.70088, 2.69981, 0.976042) -size = Vector3(52.4059, 6.08215, 28.8534) +size = Vector3(124.486, 6.08215, 135.111) [node name="CSGBox3D" type="CSGBox3D" parent="WorldEnvironment/NavigationRegion3D/brushwork"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.17791, 5.23133, -5.44301) @@ -271,6 +268,8 @@ shape = SubResource("BoxShape3D_3h2p0") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0515832, 0.0826392, -2.12334) height = 4.0 vertices = PackedVector3Array(-1, 0, 3, -1, 0, -3, 1, 0, -3, 1, 0, 3) +affect_navigation_mesh = true +carve_navigation_mesh = true [node name="MeshInstance3D" type="MeshInstance3D" parent="WorldEnvironment/NavigationRegion3D/UtilityLock"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.136569, 0) @@ -420,10 +419,10 @@ transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 8.7278 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.12793, 1.8999e-07, -8.60757) [node name="Player2" parent="." instance=ExtResource("3_wl7wm")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.7762, 1.8999e-07, -9.13169) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.74312, 1.8999e-07, -8.7408) [node name="Tank" parent="." instance=ExtResource("4_0o33v")] -transform = Transform3D(-1, 0, 8.9407e-08, 0, 1, 0, -8.9407e-08, 0, -1, 7.84599, -7.63685e-07, 8.12034) +transform = Transform3D(-1, 0, 8.9407e-08, 0, 1, 0, -8.9407e-08, 0, -1, 7.88995, -7.63685e-07, 7.79155) [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) diff --git a/src/character_unit.cpp b/src/character_unit.cpp index 0e3004a..c8e27cc 100644 --- a/src/character_unit.cpp +++ b/src/character_unit.cpp @@ -18,4 +18,3 @@ void CharacterUnit::use_weapon() { this->inventory->get_weapon()->try_use_on(this, target); } } - diff --git a/src/character_unit.hpp b/src/character_unit.hpp index fad79f9..fb448a1 100644 --- a/src/character_unit.hpp +++ b/src/character_unit.hpp @@ -1,15 +1,17 @@ #ifndef CHARACTER_UNIT_HPP #define CHARACTER_UNIT_HPP -#include "unit.hpp" #include "inventory.hpp" +#include "unit.hpp" class CharacterUnit : public Unit { GDCLASS(CharacterUnit, Unit); static void _bind_methods(); + public: virtual void _ready() override; virtual void use_weapon() override; + private: Inventory *inventory{nullptr}; }; diff --git a/src/character_world_state.hpp b/src/character_world_state.hpp index c8f8164..dd8cb28 100644 --- a/src/character_world_state.hpp +++ b/src/character_world_state.hpp @@ -7,10 +7,12 @@ class CharacterWorldState : public UnitWorldState { GDCLASS(CharacterWorldState, UnitWorldState); static void _bind_methods(); + public: virtual void _enter_tree() override; virtual gd::String get_weapon_animation() const override; virtual bool get_is_in_range() const override; + private: Inventory *inventory{nullptr}; }; diff --git a/src/enemy_world_state.cpp b/src/enemy_world_state.cpp index d7c585a..f40abbb 100644 --- a/src/enemy_world_state.cpp +++ b/src/enemy_world_state.cpp @@ -1,10 +1,10 @@ #include "enemy_world_state.hpp" #include "entity_health.hpp" -#include "unit.hpp" #include "goap/goal.hpp" +#include "unit.hpp" #include "utils/godot_macros.hpp" -#include #include +#include void EnemyWorldState::_bind_methods() { #define CLASSNAME EnemyWorldState @@ -20,33 +20,45 @@ void EnemyWorldState::_ready() { } void EnemyWorldState::_process(double) { + if(!this->health->is_conscious()) + return; if(this->select_and_set_target_on_process) { + gd::UtilityFunctions::print("!!! ", this->get_path(), " requested, select_and_set_target"); this->select_and_set_target_on_process = false; this->select_and_set_target(); + } else if(!this->parent_unit->has_plan()) { + gd::UtilityFunctions::print("!!! ", this->get_path(), " no plan, select_and_set_target"); + this->select_and_set_target(); } } void EnemyWorldState::on_awareness_entered(gd::Node3D *node) { - if(Unit *unit{gd::Object::cast_to(node)}) { + if(Unit * unit{gd::Object::cast_to(node)}) { this->add_aware_unit(unit); } } void EnemyWorldState::on_awareness_exited(gd::Node3D *node) { - if(Unit *unit{gd::Object::cast_to(node)}) + if(Unit * unit{gd::Object::cast_to(node)}) this->remove_aware_unit(unit); } void EnemyWorldState::on_damaged(EntityHealth *, int, Unit *source) { if(source != nullptr && !this->known_enemies.has(source)) this->add_aware_unit(source); - else if(!this->parent_unit->has_plan()) + if(!this->parent_unit->has_plan()) this->select_and_set_target(); } Unit *EnemyWorldState::select_target_from_known_with_priority(float *out_priority) { - Unit *out{nullptr}; - *out_priority = -INFINITY; + Unit *out{gd::Object::cast_to(target_node)}; + // prioritze current target if it is still valid + if(out != nullptr && this->known_enemies.has(out)) { + *out_priority = INFINITY; + return out; + } else { + *out_priority = -INFINITY; + } for(Unit *unit : this->known_enemies) { if(!this->get_can_see_node(unit)) continue; @@ -101,6 +113,7 @@ void EnemyWorldState::on_aware_unit_death(Unit *, Unit *dead_entity) { } void EnemyWorldState::select_and_set_target() { + gd::UtilityFunctions::print("!!! ", this->get_path(), " select_and_set_target"); this->try_set_target(this->select_target_from_known()); } @@ -130,14 +143,11 @@ gd::Ref EnemyWorldState::get_goal_for_target(Unit *unit) { } void EnemyWorldState::try_set_target(Unit *unit) { - if(unit == nullptr) { - this->target_node = nullptr; - this->parent_unit->stop_plan(); + if(unit == nullptr) return; - } gd::Ref goal{this->get_goal_for_target(unit)}; this->last_goal = goal; - if(goal.is_valid()) + if(goal.is_valid() && goal != this->parent_unit->get_current_goal()) this->parent_unit->set_target_goal(unit, goal); } diff --git a/src/enemy_world_state.hpp b/src/enemy_world_state.hpp index 710e9c7..e676a46 100644 --- a/src/enemy_world_state.hpp +++ b/src/enemy_world_state.hpp @@ -1,8 +1,8 @@ #ifndef ENEMY_WORLD_STATE_HPP #define ENEMY_WORLD_STATE_HPP -#include "unit_world_state.hpp" #include "goap/goal.hpp" +#include "unit_world_state.hpp" #include #include #include @@ -14,6 +14,7 @@ class EntityHealth; class EnemyWorldState : public UnitWorldState { GDCLASS(EnemyWorldState, UnitWorldState); static void _bind_methods(); + public: virtual void _ready() override; virtual void _process(double) override; @@ -23,10 +24,11 @@ public: /*! Select the target with the highest priority and return it. * Assigns the priority of found target to out_priority. * \param out_priority Assigned to highest found priority, cannot be nullptr. - */ + */ Unit *select_target_from_known_with_priority(float *out_priority); //! Shorthand for select_target_from_known_with_priority(nullptr) Unit *select_target_from_known(); + private: void queue_select_and_set_target(); void add_aware_unit(Unit *unit); @@ -38,6 +40,7 @@ private: void try_set_target(Unit *target); void set_available_goals_inspector(gd::Array array); gd::Array get_available_goals_inspector() const; + private: gd::Callable aware_unit_death{callable_mp(this, &EnemyWorldState::on_aware_unit_death)}; gd::Vector> available_goals{}; diff --git a/src/entity_health.cpp b/src/entity_health.cpp index 47a6fd6..0fd7026 100644 --- a/src/entity_health.cpp +++ b/src/entity_health.cpp @@ -10,22 +10,22 @@ void EntityHealth::_bind_methods() { GDPROPERTY(wounds_max, gd::Variant::INT); GDSIGNAL("damage", - gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "EntityHealth"), - gd::PropertyInfo(gd::Variant::INT, "change"), - gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); + gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "EntityHealth"), + gd::PropertyInfo(gd::Variant::INT, "change"), + gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); GDSIGNAL("heal", - gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "EntityHealth"), - gd::PropertyInfo(gd::Variant::INT, "change"), - gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); + gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "EntityHealth"), + gd::PropertyInfo(gd::Variant::INT, "change"), + gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); GDSIGNAL("health_changed", - gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "EntityHealth"), - gd::PropertyInfo(gd::Variant::INT, "change")); + gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "EntityHealth"), + gd::PropertyInfo(gd::Variant::INT, "change")); GDSIGNAL("death", gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); GDSIGNAL("unconscious", gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); GDSIGNAL("revived", - gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "Unit"), - gd::PropertyInfo(gd::Variant::INT, "healed"), - gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); + gd::PropertyInfo(gd::Variant::OBJECT, "health_entity", gd::PROPERTY_HINT_NODE_TYPE, "Unit"), + gd::PropertyInfo(gd::Variant::INT, "healed"), + gd::PropertyInfo(gd::Variant::OBJECT, "source", gd::PROPERTY_HINT_NODE_TYPE, "Unit")); } void EntityHealth::_enter_tree() { @@ -71,24 +71,20 @@ void EntityHealth::receive_injury(int incoming_amount, Unit *source) { float EntityHealth::get_wounds_damage_factor() const { return this->injury_max == 0 - ? 1.f - : float(this->injury_current) / float(this->injury_max); + ? 1.f + : float(this->injury_current) / float(this->injury_max); } bool EntityHealth::is_conscious() const { - return !this->is_dead() - && (this->wounds_current > 0 || this->wounds_max <= 0); + return !this->is_dead() && (this->wounds_current > 0 || this->wounds_max <= 0); } bool EntityHealth::can_be_revived() const { - return this->wounds_current <= 0 - && this->injury_current > 0; + return this->wounds_current <= 0 && this->injury_current > 0; } bool EntityHealth::can_be_healed() const { - return this->injury_current > 0 - && this->wounds_current > 0 - && this->wounds_current < this->wounds_max; + return this->injury_current > 0 && this->wounds_current > 0 && this->wounds_current < this->wounds_max; } bool EntityHealth::is_dead() const { diff --git a/src/entity_health.hpp b/src/entity_health.hpp index cd664a7..409df6f 100644 --- a/src/entity_health.hpp +++ b/src/entity_health.hpp @@ -11,15 +11,18 @@ class Unit; class EntityHealth : public gd::Node { GDCLASS(EntityHealth, gd::Node); static void _bind_methods(); + public: virtual void _enter_tree() override; void damaged_by(int amount, Unit *source); void healed_by(int amount, Unit *source); void heal_and_revive(int heal_amount, Unit *source); + private: void receive_wounds(int incoming_amount, Unit *source); void receive_injury(int incoming_amount, Unit *source); float get_wounds_damage_factor() const; + public: bool is_conscious() const; bool can_be_revived() const; @@ -34,6 +37,7 @@ public: void set_wounds_max(int max_health); int get_wounds_max() const; int get_wounds_current() const; + private: Stats const *stats; // long term health diff --git a/src/goal_marker.hpp b/src/goal_marker.hpp index 13870e9..ea12b5c 100644 --- a/src/goal_marker.hpp +++ b/src/goal_marker.hpp @@ -10,10 +10,12 @@ namespace gd = godot; class GoalMarker : public gd::StaticBody3D { GDCLASS(GoalMarker, gd::StaticBody3D); static void _bind_methods(); + public: void destroy_on_forgotten(); void set_goal(gd::Ref goal); gd::Ref get_goal() const; + private: gd::Ref goal{}; }; diff --git a/src/goap/state.cpp b/src/goap/state.cpp index 29b2a32..cd17eda 100644 --- a/src/goap/state.cpp +++ b/src/goap/state.cpp @@ -2,6 +2,7 @@ #include "../goap/action.hpp" #include "../goap/actor_world_state.hpp" #include "../utils/godot_macros.hpp" +#include "godot_cpp/variant/utility_functions.hpp" namespace goap { void State::_bind_methods() { @@ -21,11 +22,13 @@ void State::_process(double) { } void State::interrupt_state() { + gd::UtilityFunctions::print("!!! ", this->get_path(), " interrupt_state"); this->_end_state(); this->queue_free(); } void State::end_state() { + gd::UtilityFunctions::print("!!! ", this->get_path(), " end_state"); this->interrupt_state(); this->emit_signal(this->is_action_done() ? "state_finished" : "state_failed"); this->emit_signal("end_state"); diff --git a/src/inventory.cpp b/src/inventory.cpp index 607ba4a..d16ce9b 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -19,10 +19,14 @@ void Inventory::_ready() { Stats Inventory::get_stats() const { Stats stats{}; - if(this->weapon != nullptr) this->weapon->apply_stats(stats); - if(this->utility != nullptr) this->utility->apply_stats(stats); - if(this->armour != nullptr) this->armour->apply_stats(stats); - if(this->helmet != nullptr) this->helmet->apply_stats(stats); + if(this->weapon != nullptr) + this->weapon->apply_stats(stats); + if(this->utility != nullptr) + this->utility->apply_stats(stats); + if(this->armour != nullptr) + this->armour->apply_stats(stats); + if(this->helmet != nullptr) + this->helmet->apply_stats(stats); return stats; } diff --git a/src/inventory.hpp b/src/inventory.hpp index 2ead65c..8315d5c 100644 --- a/src/inventory.hpp +++ b/src/inventory.hpp @@ -6,8 +6,8 @@ #include "utils/godot_macros.hpp" #include #include -#include #include +#include namespace gd = godot; class Unit; @@ -15,6 +15,7 @@ class Unit; class Inventory : public gd::Node { GDCLASS(Inventory, gd::Node); static void _bind_methods(); + public: virtual void _ready() override; Stats get_stats() const; @@ -38,6 +39,7 @@ public: int get_utility_id() const; void set_inventory_inspector(gd::Dictionary dict); gd::Dictionary get_inventory_inspector() const; + private: Item const *weapon{nullptr}; Item const *utility{nullptr}; diff --git a/src/item.hpp b/src/item.hpp index 338a0c7..b619300 100644 --- a/src/item.hpp +++ b/src/item.hpp @@ -1,8 +1,8 @@ #ifndef ITEM_HPP #define ITEM_HPP -#include "stats.hpp" #include "goap/action.hpp" +#include "stats.hpp" #include "utils/godot_macros.hpp" #include #include @@ -10,22 +10,22 @@ namespace gd = godot; GDENUM(ItemCapability, - Heal, - Revive, - WeaponEquip, - WeaponRanged, - WeaponMelee, - ArmourEquip, - HeadEquip, - UtilityEquip, - Consume -); + Heal, + Revive, + WeaponEquip, + WeaponRanged, + WeaponMelee, + ArmourEquip, + HeadEquip, + UtilityEquip, + Consume); typedef int ItemID; class Unit; class Item { -friend class ItemDB; + friend class ItemDB; + public: static gd::StringName get_static_class() { gd::UtilityFunctions::push_error("Calling Item::get_static_class() on an Item class that does not implement it. Use ITEM_CLASS(*) macro."); @@ -45,6 +45,7 @@ public: } Item() = default; virtual ~Item(); + public: virtual bool can_use_on(Unit *used_by, gd::Object *used_on) const; bool try_use_on(Unit *used_by, gd::Object *used_on) const; @@ -52,22 +53,27 @@ public: bool has_capability(ItemCapability const &capability) const; gd::StringName const &get_animation() const; ItemID get_id() const; + protected: virtual void use_on(Unit *used_by, gd::Object *used_on) const; + protected: gd::StringName animation{"RESET"}; gd::HashSet capabilities{}; + private: ItemID id{-1}; }; -#define ITEM_CLASS(Class_, DisplayName_, Description_)\ -friend class ItemDB;\ -public: \ - _FORCE_INLINE_ static godot::StringName get_static_class() { return #Class_; }\ - _FORCE_INLINE_ virtual godot::StringName get_class() const override { return #Class_; }\ - _FORCE_INLINE_ virtual godot::String get_display_name() const override { return DisplayName_; }\ - _FORCE_INLINE_ virtual godot::String get_description() const override { return Description_; }\ +#define ITEM_CLASS(Class_, DisplayName_, Description_) \ + friend class ItemDB; \ + \ +public: \ + _FORCE_INLINE_ static godot::StringName get_static_class() { return #Class_; } \ + _FORCE_INLINE_ virtual godot::StringName get_class() const override { return #Class_; } \ + _FORCE_INLINE_ virtual godot::String get_display_name() const override { return DisplayName_; } \ + _FORCE_INLINE_ virtual godot::String get_description() const override { return Description_; } \ + \ private: #endif // !ITEM_HPP diff --git a/src/item_db.cpp b/src/item_db.cpp index 6ac78fd..052afa8 100644 --- a/src/item_db.cpp +++ b/src/item_db.cpp @@ -22,7 +22,7 @@ gd::String &ItemDB::StaticData::get_array_hint() { } ItemID ItemDB::register_item(Item *item, gd::String item_name) { - item->id = ItemDB::data.items.size()+1; + item->id = ItemDB::data.items.size() + 1; ItemDB::data.get_hint() += ","; ItemDB::data.get_hint() += item_name; ItemDB::data.get_array_hint() = gd::vformat("%s/%s:%s", gd::Variant::INT, gd::PROPERTY_HINT_ENUM, ItemDB::data.get_hint()); diff --git a/src/item_db.hpp b/src/item_db.hpp index 8d8b1f4..4bc439c 100644 --- a/src/item_db.hpp +++ b/src/item_db.hpp @@ -14,9 +14,10 @@ class ItemDB { gd::String &get_array_hint(); gd::String *array_hint{}; gd::String *hint{}; - gd::Vector items{}; + gd::Vector items{}; }; static ItemID register_item(Item *item, gd::String item_name); + public: static Item const *get_item(ItemID id); static gd::String const &get_enum_hint(); @@ -27,6 +28,7 @@ public: _FORCE_INLINE_ static ItemID register_item() { return ItemDB::register_item(new TItem(), TItem::get_static_class()); } + private: static StaticData data; }; diff --git a/src/nav_marker.hpp b/src/nav_marker.hpp index ca5a6fa..313c804 100644 --- a/src/nav_marker.hpp +++ b/src/nav_marker.hpp @@ -7,19 +7,20 @@ namespace gd = godot; GDENUM(MarkerType, - Generic, - Cover, - HalfCover -); + Generic, + Cover, + HalfCover); class NavMarker : public gd::Marker3D { GDCLASS(NavMarker, gd::Marker3D); static void _bind_methods(); + public: virtual void _process(double) override; void set_marker_type(int type); int get_marker_type() const; + private: MarkerType type{MarkerType::Generic}; }; diff --git a/src/nav_room.cpp b/src/nav_room.cpp index 090fa3b..eb133e1 100644 --- a/src/nav_room.cpp +++ b/src/nav_room.cpp @@ -1,8 +1,8 @@ #include "nav_room.hpp" #include "nav_marker.hpp" #include "utils/godot_macros.hpp" -#include #include +#include void NavRoom::_bind_methods() { #define CLASSNAME NavRoom @@ -32,15 +32,15 @@ void NavRoom::_exit_tree() { } void NavRoom::on_child_entered(gd::Node *child) { - if(NavMarker *marker{gd::Object::cast_to(child)}) + if(NavMarker * marker{gd::Object::cast_to(child)}) this->markers.push_back(marker); } -gd::Vector const &NavRoom::get_neighbours() const { +gd::Vector const &NavRoom::get_neighbours() const { return this->neighbours; } -gd::Vector const &NavRoom::get_markers() const { +gd::Vector const &NavRoom::get_markers() const { return this->markers; } @@ -53,8 +53,9 @@ gd::Array NavRoom::get_neighbours_inspector() const { void NavRoom::set_neighbours_inspector(gd::Array array) { this->neighbours.clear(); - while(!array.is_empty()) if(NavRoom *room{gd::Object::cast_to(array.pop_front())}) - this->neighbours.push_back(room); + while(!array.is_empty()) + if(NavRoom * room{gd::Object::cast_to(array.pop_front())}) + this->neighbours.push_back(room); } -gd::Vector NavRoom::rooms{}; +gd::Vector NavRoom::rooms{}; diff --git a/src/nav_room.hpp b/src/nav_room.hpp index eb5ef19..fe4b55a 100644 --- a/src/nav_room.hpp +++ b/src/nav_room.hpp @@ -11,23 +11,26 @@ 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 const &get_neighbours() const; - gd::Vector const &get_markers() const; + gd::Vector const &get_neighbours() const; + gd::Vector const &get_markers() const; + private: void set_neighbours_inspector(gd::Array array); gd::Array get_neighbours_inspector() const; + private: float radius{1.f}; gd::Vector3 centre{0.f, 0.f, 0.f}; - gd::Vector markers{}; - gd::Vector neighbours{}; + gd::Vector markers{}; + gd::Vector neighbours{}; - static gd::Vector rooms; + static gd::Vector rooms; }; #endif // !NAV_ROOM_HPP diff --git a/src/register_types.cpp b/src/register_types.cpp index b5dd65f..9221d74 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -3,6 +3,12 @@ #include "character_world_state.hpp" #include "enemy_world_state.hpp" #include "entity_health.hpp" +#include "goap/action.hpp" +#include "goap/action_db.hpp" +#include "goap/actor_world_state.hpp" +#include "goap/goal.hpp" +#include "goap/planner.hpp" +#include "goap/state.hpp" #include "inventory.hpp" #include "item_db.hpp" #include "nav_marker.hpp" @@ -16,12 +22,6 @@ #include "unit.hpp" #include "unit_world_state.hpp" #include "utility_lock.hpp" -#include "goap/action.hpp" -#include "goap/action_db.hpp" -#include "goap/actor_world_state.hpp" -#include "goap/goal.hpp" -#include "goap/planner.hpp" -#include "goap/state.hpp" #include "utils/register_types.hpp" #include #include @@ -30,9 +30,8 @@ namespace gd = godot; -void initialize_gdextension_types(gd::ModuleInitializationLevel p_level) -{ - if (p_level != gd::MODULE_INITIALIZATION_LEVEL_SCENE) { +void initialize_gdextension_types(gd::ModuleInitializationLevel p_level) { + if(p_level != gd::MODULE_INITIALIZATION_LEVEL_SCENE) { return; } utils::godot_cpp_utils_register_types(); @@ -78,15 +77,13 @@ void initialize_gdextension_types(gd::ModuleInitializationLevel p_level) GDREGISTER_RUNTIME_CLASS(RTSPlayer); } -extern "C" -{ - // Initialization - GDExtensionBool GDE_EXPORT metro_rts_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) - { - gd::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); - init_obj.register_initializer(initialize_gdextension_types); - init_obj.set_minimum_library_initialization_level(gd::MODULE_INITIALIZATION_LEVEL_SCENE); +extern "C" { +// Initialization +GDExtensionBool GDE_EXPORT metro_rts_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) { + gd::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); + init_obj.register_initializer(initialize_gdextension_types); + init_obj.set_minimum_library_initialization_level(gd::MODULE_INITIALIZATION_LEVEL_SCENE); - return init_obj.init(); - } + return init_obj.init(); +} } diff --git a/src/rts_actions.cpp b/src/rts_actions.cpp index d5371bb..58ec5e2 100644 --- a/src/rts_actions.cpp +++ b/src/rts_actions.cpp @@ -1,17 +1,21 @@ -#include "rts_actions.hpp" -#include "nav_marker.hpp" -#include "nav_room.hpp" -#include "rts_states.hpp" -#include "utility_lock.hpp" #include "goap/actor_world_state.hpp" #include "goap/state.hpp" +#include "godot_cpp/classes/object.hpp" +#include "nav_marker.hpp" +#include "nav_room.hpp" +#include "rts_actions.hpp" +#include "rts_states.hpp" +#include "unit.hpp" +#include "unit_world_state.hpp" +#include "utility_lock.hpp" +#include #include #include #include -#include -MoveToTarget::MoveToTarget() -: Action() { +MoveToTarget::MoveToTarget() : + Action() { + this->required.insert("can_reach_target", true); this->effects.insert("is_at_target", true); } @@ -26,8 +30,8 @@ goap::State *MoveToTarget::get_apply_state(goap::ActorWorldState *context) const return state; } -UseWeapon::UseWeapon() -: Action() { +UseWeapon::UseWeapon() : + Action() { this->required.insert("can_see_target", true); this->required.insert("is_in_range", true); this->effects.insert("is_target_unconscious", true); @@ -39,8 +43,8 @@ goap::State *UseWeapon::get_apply_state(goap::ActorWorldState *context) const { return state; } -FindTarget::FindTarget() -: Action() { +FindTarget::FindTarget() : + Action() { this->require_state_complete = false; this->effects.insert("can_see_target", true); } @@ -52,10 +56,10 @@ goap::State *FindTarget::get_apply_state(goap::ActorWorldState *context) const { return state; } -GetInRange::GetInRange() -: Action() { +GetInRange::GetInRange() : + Action() { this->require_state_complete = false; - this->required.insert("can_see_target", true); + this->effects.insert("can_see_target", true); this->effects.insert("is_in_range", true); } @@ -66,9 +70,8 @@ goap::State *GetInRange::get_apply_state(goap::ActorWorldState *context) const { return state; } -TankSelfHeal::TankSelfHeal() -: Action() { - this->required.insert("can_see_target", false); +TankSelfHeal::TankSelfHeal() : + Action() { this->effects.insert("is_health_safe", true); } @@ -78,8 +81,8 @@ goap::State *TankSelfHeal::get_apply_state(goap::ActorWorldState *) const { return state; } -TakeCover::TakeCover() -: Action () { +TakeCover::TakeCover() : + Action() { this->effects.insert("can_see_target", false); } @@ -100,6 +103,7 @@ bool TakeCover::procedural_is_possible(goap::ActorWorldState *context) const { } goap::State *TakeCover::get_apply_state(goap::ActorWorldState *context) const { + UnitWorldState *unit_state{gd::Object::cast_to(context)}; // positions of the context and the target to hide from gd::Vector3 const context_position{context->get_world_property("parent_global_position")}; gd::Vector3 const target_position{context->get_world_property("target_global_position")}; @@ -110,6 +114,10 @@ goap::State *TakeCover::get_apply_state(goap::ActorWorldState *context) const { NavMarker *best_marker{nullptr}; // marker with the 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()) { + bool can_reach{unit_state->can_reach_point(marker->get_global_position())}; + if(!can_reach) { + continue; // skip if unreachable + } float const score{this->score_cover_marker(marker, target_position, context_position)}; if(score > best_score) { best_score = score; @@ -128,11 +136,10 @@ goap::State *TakeCover::get_apply_state(goap::ActorWorldState *context) const { 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_position - target_position) < -2.f; + return marker->get_marker_type() == MarkerType::Cover && marker->get_global_basis().get_column(2).dot(marker_position - target_position) < -2.f; } -float TakeCover::score_cover_marker(class NavMarker* marker, const gd::Vector3& target_position, const gd::Vector3& context_position) const { +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 @@ -173,7 +180,7 @@ goap::State *ActivateLock::get_apply_state(goap::ActorWorldState *context) const } Activate *activate = this->create_state(); activate->lock = lock; - if(Inventory *inventory{unit_context->get_node("%Inventory")}) + if(Inventory * inventory{unit_context->get_node("%Inventory")}) activate->using_item = inventory->get_utility(); return activate; } diff --git a/src/rts_actions.hpp b/src/rts_actions.hpp index 23b8640..540a9f2 100644 --- a/src/rts_actions.hpp +++ b/src/rts_actions.hpp @@ -6,6 +6,7 @@ class MoveToTarget : public goap::Action { GOAP_ACTION(MoveToTarget); + public: MoveToTarget(); virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override; @@ -13,6 +14,7 @@ public: class UseWeapon : public goap::Action { GOAP_ACTION(UseWeapon); + public: UseWeapon(); virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override; @@ -20,6 +22,7 @@ public: class FindTarget : public goap::Action { GOAP_ACTION(FindTarget); + public: FindTarget(); virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override; @@ -27,6 +30,7 @@ public: class GetInRange : public goap::Action { GOAP_ACTION(GetInRange); + public: GetInRange(); virtual goap::State *get_apply_state(goap::ActorWorldState *context) const override; @@ -34,6 +38,7 @@ public: class TankSelfHeal : public goap::Action { GOAP_ACTION(TankSelfHeal); + public: TankSelfHeal(); virtual goap::State *get_apply_state(goap::ActorWorldState *) const override; @@ -41,10 +46,12 @@ public: 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_position, gd::Vector3 const &context_position); float score_cover_marker(class NavMarker *marker, gd::Vector3 const &target_position, gd::Vector3 const &context_position) const; @@ -52,6 +59,7 @@ private: class ActivateLock : public goap::Action { GOAP_ACTION(ActivateLock); + public: ActivateLock(); virtual bool procedural_is_possible(goap::ActorWorldState *context) const override; diff --git a/src/rts_game_mode.hpp b/src/rts_game_mode.hpp index e37fafb..f8a09ab 100644 --- a/src/rts_game_mode.hpp +++ b/src/rts_game_mode.hpp @@ -6,6 +6,7 @@ class RTSGameMode : public utils::GameMode { GDCLASS(RTSGameMode, utils::GameMode); static void _bind_methods(); + public: virtual void _ready() override; }; diff --git a/src/rts_items.cpp b/src/rts_items.cpp index c69bc7f..a90cabe 100644 --- a/src/rts_items.cpp +++ b/src/rts_items.cpp @@ -1,9 +1,9 @@ #include "rts_items.hpp" -#include "unit.hpp" #include "entity_health.hpp" +#include "unit.hpp" -Medkit::Medkit() -: Item() { +Medkit::Medkit() : + Item() { this->capabilities.insert(ItemCapability::Consume); this->capabilities.insert(ItemCapability::Heal); this->capabilities.insert(ItemCapability::Revive); @@ -17,38 +17,38 @@ void Medkit::use_on(Unit *used_by, gd::Object *used_on) const { gd::Object::cast_to(used_on)->get_entity_health()->healed_by(3, used_by); } -Handgun::Handgun() -: Item() { +Handgun::Handgun() : + Item() { this->animation = "fire_weapon"; this->capabilities.insert(ItemCapability::WeaponEquip); this->capabilities.insert(ItemCapability::WeaponRanged); } bool Handgun::can_use_on(Unit *used_by, gd::Object *used_on) const { - return gd::Object::cast_to(used_on) != nullptr - && used_by->get_world_state()->get_can_see_target(); + return gd::Object::cast_to(used_on) != nullptr && used_by->get_world_state()->get_can_see_target(); } void Handgun::apply_stats(Stats &stats) const { stats.weapon_range = 10.f; } -void Handgun::use_on(Unit* used_by, gd::Object* used_on) const { +void Handgun::use_on(Unit *used_by, gd::Object *used_on) const { Unit *target{gd::Object::cast_to(used_on)}; used_by->aim_at(target); EntityHealth *health{target->get_entity_health()}; health->damaged_by(4, used_by); gd::Vector3 const owner_position{used_by->get_global_position()}; gd::Vector3 const target_position{target->get_global_position()}; - used_by->look_at(owner_position-(target_position-owner_position)); + if(owner_position != target_position) + used_by->look_at(owner_position - (target_position - owner_position)); } -Lasercutter::Lasercutter() -: Item() { +Lasercutter::Lasercutter() : + Item() { this->capabilities.insert(ItemCapability::UtilityEquip); } -Welder::Welder() -: Item() { +Welder::Welder() : + Item() { this->capabilities.insert(ItemCapability::UtilityEquip); } diff --git a/src/rts_items.hpp b/src/rts_items.hpp index d06150c..b6d318e 100644 --- a/src/rts_items.hpp +++ b/src/rts_items.hpp @@ -5,32 +5,40 @@ class Medkit : public Item { ITEM_CLASS(Medkit, "Medkit", - "Standard emergency home medical kit. Use to manage wounds and stabilize a person."); + "Standard emergency home medical kit. Use to manage wounds and stabilize a person."); + private: Medkit(); + public: virtual bool can_use_on(Unit *used_by, gd::Object *used_on) const override; + protected: virtual void use_on(Unit *used_by, gd::Object *used_on) const override; }; class Handgun : public Item { ITEM_CLASS(Handgun, "9mm handgun.", - "A standard issue police firearm."); + "A standard issue police firearm."); + private: Handgun(); + public: virtual bool can_use_on(Unit *used_by, gd::Object *used_on) const override; virtual void apply_stats(Stats &stats) const override; + protected: virtual void use_on(Unit *used_by, gd::Object *used_on) const override; }; class Lasercutter : public Item { ITEM_CLASS(Lasercutter, "Lasercutter", - "A laser cutter, use to clear metal obstacles."); + "A laser cutter, use to clear metal obstacles."); + private: Lasercutter(); + public: // virtual bool can_use_on(Unit *used_by, gd::Object *object) const override; protected: @@ -39,9 +47,11 @@ protected: class Welder : public Item { ITEM_CLASS(Welder, "Welder", - "A welder with tanks intended to be carried on a person's back. Use to repair broken metal parts."); + "A welder with tanks intended to be carried on a person's back. Use to repair broken metal parts."); + private: Welder(); + public: // virtual bool can_use_on(Unit *used_by, gd::Object *object) const override; protected: diff --git a/src/rts_player.cpp b/src/rts_player.cpp index afbc2cd..ed48267 100644 --- a/src/rts_player.cpp +++ b/src/rts_player.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -127,7 +126,6 @@ bool RTSPlayer::order_activate_object(gd::Node3D *node) { return true; } return unit != nullptr; - } void RTSPlayer::clear_selected_unit() { @@ -236,4 +234,3 @@ void RTSPlayer::DEBUG_enable_debug(gd::Ref, float value) { } } #endif - diff --git a/src/rts_player.hpp b/src/rts_player.hpp index 4c699a0..ffef208 100644 --- a/src/rts_player.hpp +++ b/src/rts_player.hpp @@ -17,6 +17,7 @@ class RTSPlayer : public gd::Node3D, public utils::IPlayer { GDCLASS(RTSPlayer, godot::Node3D); static void _bind_methods(); + public: virtual void _ready() override; virtual void _process(double delta_time) override; @@ -24,6 +25,7 @@ public: virtual void setup_player_input(utils::PlayerInput *input) override; virtual Node *to_node() override; virtual void spawn_at_position(gd::Transform3D const &at) override; + private: //! process any changes to mouse position void process_mouse(); @@ -61,10 +63,12 @@ private: gd::Ref get_ground_marker_scene() const; void set_zoom_curve(gd::Ref curve); gd::Ref get_zoom_curve() const; + private: gd::Callable const on_selected_unit_destroyed{callable_mp(this, &RTSPlayer::clear_selected_unit)}; + private: - Unit* selected_unit{nullptr}; + Unit *selected_unit{nullptr}; bool mmb_down{false}; bool lmb_down{false}; diff --git a/src/rts_states.cpp b/src/rts_states.cpp index 139b61b..dbc2a13 100644 --- a/src/rts_states.cpp +++ b/src/rts_states.cpp @@ -2,9 +2,9 @@ #include "unit.hpp" #include "utility_lock.hpp" #include "utils/util_functions.hpp" +#include #include #include -#include void MoveTo::_bind_methods() {} @@ -114,18 +114,34 @@ void Activate::_end_state() { void Animate::_bind_methods() {} void Animate::_ready() { + gd::UtilityFunctions::print("!!! ", this->get_path(), ": attempting to play animation ", this->animation); this->anim = this->get_parent()->get_node("%AnimationPlayer"); - if(!this->anim->has_animation(this->animation)) + if(!this->anim->has_animation(this->animation)) { this->end_state(); - else this->anim->play(this->animation); + gd::UtilityFunctions::print("!!! ", this->get_path(), ": failed to play animation ", this->animation); + } else { + this->anim->play(this->animation); + this->anim->advance(0); + this->anim->connect("animation_finished", callable_mp(this, &self_type::_on_animation_finished)); + gd::UtilityFunctions::print("!!! ", this->get_path(), ": succeeded playing animation ", this->animation); + } } void Animate::_process(double) { - bool const animation_finished{!this->anim->is_playing() || this->anim->get_current_animation() != this->animation}; - if(this->is_action_done_interrupt() || animation_finished) + if(this->is_action_done_interrupt() || this->is_finished) { + gd::UtilityFunctions::print("!!! animation " , this->animation, + " is done in ", this->get_path(), + " animation finished: ", this->is_finished, + " interrupted: ", this->is_action_done_interrupt()); this->end_state(); + } } void Animate::_end_state() { this->anim->stop(); + gd::UtilityFunctions::print("!!! ", this->get_path(), " animation ", this->animation, " stopped"); +} + +void Animate::_on_animation_finished(gd::String new_anim) { + this->is_finished = true; } diff --git a/src/rts_states.hpp b/src/rts_states.hpp index 88d50cc..48922c7 100644 --- a/src/rts_states.hpp +++ b/src/rts_states.hpp @@ -1,8 +1,8 @@ #ifndef RTS_STATES_HPP #define RTS_STATES_HPP -#include "unit.hpp" #include "goap/state.hpp" +#include "unit.hpp" #include #include @@ -13,6 +13,7 @@ class UtilityLock; class MoveTo : public goap::State { GDCLASS(MoveTo, goap::State); static void _bind_methods(); + public: virtual void _ready() override; virtual void _end_state() override; @@ -22,8 +23,10 @@ public: float target_delta_position() const; float distance_to_target() const; double get_repath_interval() const; + public: gd::Node3D *target_node{nullptr}; + private: gd::Callable nav_velocity_computed{callable_mp(this, &MoveTo::on_velocity_computed)}; Unit *parent_unit{nullptr}; @@ -35,12 +38,14 @@ private: class Activate : public goap::State { GDCLASS(Activate, goap::State); static void _bind_methods(); + public: virtual void _ready() override; virtual void _process(double) override; virtual void _end_state() override; UtilityLock *lock{nullptr}; Item const *using_item{nullptr}; + private: gd::String animation{}; gd::AnimationPlayer *anim{nullptr}; @@ -50,12 +55,16 @@ private: class Animate : public goap::State { GDCLASS(Animate, goap::State); static void _bind_methods(); + public: virtual void _ready() override; virtual void _process(double delta_time) override; virtual void _end_state() override; + void _on_animation_finished(gd::String new_anim); gd::StringName animation{}; + private: + bool is_finished{false}; gd::AnimationPlayer *anim{nullptr}; }; diff --git a/src/tank_unit.hpp b/src/tank_unit.hpp index dd4e037..9865428 100644 --- a/src/tank_unit.hpp +++ b/src/tank_unit.hpp @@ -6,6 +6,7 @@ class TankUnit : public Unit { GDCLASS(TankUnit, Unit); static void _bind_methods(); + public: virtual void use_weapon() override; }; diff --git a/src/unit.cpp b/src/unit.cpp index 1b70c38..bf706d4 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -45,6 +45,7 @@ void Unit::_physics_process(double) { } void Unit::stop_plan() { + gd::UtilityFunctions::print("!!! ", this->get_path(), " stop_plan"); this->current_goal.unref(); this->current_plan.clear(); this->destroy_state(); @@ -71,6 +72,7 @@ void Unit::begin_marker_temporary(GoalMarker *marker) { } void Unit::set_target_goal(gd::Node3D *target, gd::Ref goal) { + gd::UtilityFunctions::print("!!! ", this->get_path(), " set_target_goal"); this->destroy_state(); this->world_state->set_target_node(target); this->begin_goal(goal); @@ -96,6 +98,7 @@ void Unit::aim_at(gd::Node3D *target) { } void Unit::on_unconscious(Unit *damage_source) { + gd::UtilityFunctions::print("!!! ", this->get_path(), " on_unconscious"); this->destroy_state(); this->emit_signal("plan_failed"); this->anim_player->stop(); @@ -103,6 +106,7 @@ void Unit::on_unconscious(Unit *damage_source) { } void Unit::on_death(Unit *damage_source) { + gd::UtilityFunctions::print("!!! ", this->get_path(), " on_death"); this->destroy_state(); this->emit_signal("plan_failed"); if(this->anim_player->get_current_animation() != gd::StringName("death")) { @@ -113,13 +117,16 @@ void Unit::on_death(Unit *damage_source) { void Unit::on_velocity_computed(gd::Vector3 vel) { gd::Vector3 const pos{this->get_global_position()}; - if(vel.x == 0 && vel.z == 0) + if(vel.x == 0 && vel.z == 0) { + this->set_velocity({0.f, 0.f, 0.f}); return; + } this->set_velocity(vel.normalized() * this->movement_speed); this->look_at(pos - gd::Vector3{vel.x, 0.f, vel.z}); } void Unit::destroy_state() { + gd::UtilityFunctions::print("!!! ", this->get_path(), " destroy_state"); if(this->state == nullptr) return; if(!this->state->is_queued_for_deletion()) @@ -143,8 +150,14 @@ void Unit::next_action() { if(this->current_plan.is_empty()) return; goap::Action const *action{this->current_plan.get(0)}; - if(action == nullptr || !action->is_possible(this->world_state)) { + if(action == nullptr) { + gd::UtilityFunctions::push_error("Plan interrupted by invalid action in queue"); + this->emit_signal("plan_interrupted"); + return; + } + if(!action->is_possible(this->world_state)) { this->emit_signal("plan_interrupted"); + gd::UtilityFunctions::push_error("Plan interrupted because action ", action->get_class(), " is impossible"); return; } // get next action and apply state @@ -193,10 +206,14 @@ int Unit::get_configure_team() const { } bool Unit::has_plan() const { - return !this->current_plan.is_empty(); + return !this->current_plan.is_empty() || this->state != nullptr; } -EntityHealth *Unit::get_entity_health() { +gd::Ref Unit::get_current_goal() const { + return this->current_goal; +} + +EntityHealth *Unit::get_entity_health() const { return this->health; } @@ -211,7 +228,8 @@ float Unit::get_movement_speed() const { #ifdef DEBUG_ENABLED gd::String Unit::DEBUG_print_debug_info() { gd::String debug_info{}; - debug_info += gd::String("health: ") + gd::vformat("%d", this->get_entity_health()->get_wounds_current()); + debug_info += gd::String("wounds: ") + gd::vformat("%d", this->get_entity_health()->get_wounds_current()); + debug_info += gd::String("\ninjury: ") + gd::vformat("%d", this->get_entity_health()->get_injury_current()); debug_info += "\ngoal: "; if(!this->current_goal.is_valid()) { debug_info += "No goal assigned"; diff --git a/src/unit.hpp b/src/unit.hpp index fee712a..b0c5a87 100644 --- a/src/unit.hpp +++ b/src/unit.hpp @@ -2,9 +2,9 @@ #define RTS_UNIT_HPP #include "goal_marker.hpp" -#include "unit_world_state.hpp" #include "goap/goal.hpp" #include "goap/planner.hpp" +#include "unit_world_state.hpp" #include "utils/godot_macros.hpp" #include #include @@ -15,15 +15,15 @@ namespace gd = godot; GDENUM(UnitTeam, - Neutral, - Player, - Ally, - Enemy -); + Neutral, + Player, + Ally, + Enemy); class Unit : public gd::CharacterBody3D { GDCLASS(Unit, gd::CharacterBody3D); static void _bind_methods(); + public: virtual void _enter_tree() override; virtual void _physics_process(double) override; @@ -36,6 +36,7 @@ public: void aim_at(gd::Node3D *node); void on_unconscious(Unit *damage_source); void on_death(Unit *damage_source); + private: void on_velocity_computed(gd::Vector3 vel); void destroy_state(); @@ -43,18 +44,22 @@ private: void next_action(); void replan_goal(); void set_goal_and_plan(gd::Ref goal); + public: // getter-setters UnitWorldState *get_world_state() const; UnitTeam get_team() const; void set_configure_team(int value); int get_configure_team() const; bool has_plan() const; - EntityHealth *get_entity_health(); + gd::Ref get_current_goal() const; + EntityHealth *get_entity_health() const; void set_movement_speed(float speed); float get_movement_speed() const; + private: gd::Callable on_state_finished{callable_mp(this, &Unit::state_finished)}; gd::Callable on_plan_failed{callable_mp(this, &Unit::replan_goal)}; + protected: goap::Plan current_plan{}; gd::Ref current_goal{}; diff --git a/src/unit_world_state.cpp b/src/unit_world_state.cpp index 2f7fb5a..4a0ba17 100644 --- a/src/unit_world_state.cpp +++ b/src/unit_world_state.cpp @@ -1,12 +1,14 @@ #include "unit_world_state.hpp" #include "entity_health.hpp" +#include "godot_cpp/classes/navigation_server3d.hpp" +#include "godot_cpp/variant/packed_vector3_array.hpp" #include "unit.hpp" #include "utility_lock.hpp" #include "utils/godot_macros.hpp" #include "utils/util_functions.hpp" +#include #include #include -#include #include #include @@ -22,6 +24,7 @@ void UnitWorldState::_bind_methods() { GDFUNCTION(get_is_target_enemy); GDFUNCTION(get_is_target_activated); GDFUNCTION(get_is_in_range); + GDFUNCTION(get_can_reach_target); GDFUNCTION(get_is_health_safe); GDFUNCTION(get_parent_global_position); GDFUNCTION(get_target_global_position); @@ -61,19 +64,19 @@ bool UnitWorldState::get_can_see_node(gd::Node3D *node) const { // construct list for ignored objects including target node and parent unit gd::TypedArray ignore_list{this->parent_unit->get_rid()}; // ignore target if it is a collision object that might obstruct it's own collision test - if(gd::CollisionObject3D *as_collision_object{gd::Object::cast_to(node)}) + if(gd::CollisionObject3D * as_collision_object{gd::Object::cast_to(node)}) ignore_list.push_back(as_collision_object->get_rid()); // construct raycast query from unit's eye node to vision target. Ignoring parent unit and target if applicable gd::Ref const query{gd::PhysicsRayQueryParameters3D::create( - eyes.origin, - target_position, - 0x1 | 0x4, ignore_list - )}; + eyes.origin, + target_position, + 0x1 | 0x4, ignore_list)}; return this->parent_unit->get_world_3d()->get_direct_space_state()->intersect_ray(query).is_empty(); } bool UnitWorldState::get_is_at_target() const { - if(this->target_node == nullptr) return true; + if(this->target_node == nullptr) + return true; gd::Vector3 const target = this->target_node->get_global_position(); gd::Vector3 const current = this->parent_unit->get_global_position(); float const min_dist = this->agent->get_target_desired_distance(); @@ -85,7 +88,7 @@ bool UnitWorldState::get_has_target() const { } bool UnitWorldState::get_is_target_unconscious() const { - if(EntityHealth *health{this->target_node->get_node("%EntityHealth")}) + if(EntityHealth * health{this->target_node->get_node("%EntityHealth")}) return !health->is_conscious(); return false; } @@ -100,9 +103,7 @@ bool UnitWorldState::get_is_target_enemy() const { } bool UnitWorldState::get_is_unit_enemy(Unit *unit) const { - return unit != nullptr - && unit->get_team() != UnitTeam::Neutral - && unit->get_team() != this->parent_unit->get_team(); + return unit != nullptr && unit->get_team() != UnitTeam::Neutral && unit->get_team() != this->parent_unit->get_team(); } bool UnitWorldState::get_is_target_activated() const { @@ -111,8 +112,21 @@ bool UnitWorldState::get_is_target_activated() const { } bool UnitWorldState::get_is_in_range() const { - return this->target_node != nullptr - && this->target_node->get_global_position().distance_squared_to(this->parent_unit->get_global_position()) <= 2.f * 2.f; + return this->target_node != nullptr && this->target_node->get_global_position().distance_squared_to(this->parent_unit->get_global_position()) <= 2.f * 2.f; +} + +bool UnitWorldState::can_reach_point(gd::Vector3 point) const { + gd::NavigationServer3D *server{gd::NavigationServer3D::get_singleton()}; + godot::PackedVector3Array path{server->map_get_path(this->agent->get_navigation_map(), + this->parent_unit->get_global_position(), point, false, 0xF)}; + gd::Vector3 const endpoint{path[path.size() - 1]}; + bool const can_reach{!path.is_empty() && gd::Vector2{endpoint.x, endpoint.z}.is_equal_approx({point.x, point.z})}; + gd::UtilityFunctions::print("target ", point, " reachable from ", this->get_parent_global_position(), ": ", can_reach, ", endpoint ", path[path.size()-1]); + return can_reach; +} + +bool UnitWorldState::get_can_reach_target() const { + return this->can_reach_point(this->get_target_global_position()); } bool UnitWorldState::get_is_health_safe() const { @@ -142,7 +156,7 @@ gd::Node3D *UnitWorldState::get_target_node() const { } void UnitWorldState::cache_property(gd::String property, gd::Variant value, double auto_invalidate_time) { - this->cache[property] = {.value=value, .auto_invalidate_time=auto_invalidate_time}; + this->cache[property] = {.value = value, .auto_invalidate_time = auto_invalidate_time}; } void UnitWorldState::target_destroyed(gd::Node3D *target) { diff --git a/src/unit_world_state.hpp b/src/unit_world_state.hpp index 937ccf2..6b13584 100644 --- a/src/unit_world_state.hpp +++ b/src/unit_world_state.hpp @@ -2,8 +2,8 @@ #define UNIT_WORLD_STATE_HPP #include "entity_health.hpp" -#include "inventory.hpp" #include "goap/actor_world_state.hpp" +#include "inventory.hpp" #include #include @@ -19,6 +19,7 @@ struct CachedWorldProperty { class UnitWorldState : public goap::ActorWorldState { GDCLASS(UnitWorldState, goap::ActorWorldState); static void _bind_methods(); + public: virtual void _enter_tree() override; virtual gd::Variant get_world_property(gd::String property) override; @@ -34,16 +35,21 @@ public: bool get_is_unit_enemy(Unit *unit) const; bool get_is_target_activated() const; virtual bool get_is_in_range() const; + bool can_reach_point(gd::Vector3 point) const; + bool get_can_reach_target() const; bool get_is_health_safe() const; gd::Vector3 get_parent_global_position() const; gd::Vector3 get_target_global_position() const; void set_target_node(gd::Node3D *node); gd::Node3D *get_target_node() const; + private: void cache_property(gd::String property, gd::Variant value, double auto_invalidate_time); void target_destroyed(gd::Node3D *target); + private: gd::Callable const target_node_exited_tree{callable_mp(this, &UnitWorldState::target_destroyed)}; + protected: Unit *parent_unit{nullptr}; EntityHealth *health{nullptr}; diff --git a/src/utility_lock.cpp b/src/utility_lock.cpp index b971794..a7ef69e 100644 --- a/src/utility_lock.cpp +++ b/src/utility_lock.cpp @@ -23,7 +23,8 @@ bool UtilityLock::begin_activate(Item const *with, Unit *by) { this->_begin_activate(with, by); this->emit_signal("begin_activate", with->get_id(), by); return true; - } else return false; + } else + return false; } bool UtilityLock::finish_activate(Item const *with, Unit *by) { @@ -33,7 +34,8 @@ bool UtilityLock::finish_activate(Item const *with, Unit *by) { this->_finish_activate(with, by); this->emit_signal("finish_activate", with->get_id(), by); return true; - } else return false; + } else + return false; } void UtilityLock::interrupt_activate() { diff --git a/src/utility_lock.hpp b/src/utility_lock.hpp index 4d62acf..8a14f4e 100644 --- a/src/utility_lock.hpp +++ b/src/utility_lock.hpp @@ -3,14 +3,15 @@ #include "goal_marker.hpp" #include "item.hpp" -#include #include +#include namespace gd = godot; class UtilityLock : public GoalMarker { GDCLASS(UtilityLock, GoalMarker) static void _bind_methods(); + public: enum ActivationState { Inactive, @@ -31,6 +32,7 @@ public: gd::Array get_allowed_items() const; void set_animation_name(gd::String animation); gd::String get_animation_name() const; + private: gd::HashSet allowed_items{}; Unit *user{nullptr};