diff --git a/godot/objects/character_model_base.tscn b/godot/objects/character_model_base.tscn index caaad74..48d1597 100644 --- a/godot/objects/character_model_base.tscn +++ b/godot/objects/character_model_base.tscn @@ -112,7 +112,7 @@ bone_idx = 44 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.84754e-09, 0.268834, 0.0479187) enabled = false target_position = Vector3(0, 15, 0) -collision_mask = 3 +collision_mask = 7 [node name="MuzzleAudio" type="AudioStreamPlayer3D" parent="skeleton_character/Skeleton3D/BoneAttachment3D" index="1"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.11411e-08, 0.275409, 0.0357741) @@ -128,7 +128,7 @@ panning_strength = 0.82 transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.91257e-05, -0.0191353, -0.00675189) enabled = false target_position = Vector3(0, 2.468, 0) -collision_mask = 3 +collision_mask = 7 debug_shape_thickness = 3 [node name="AnimationPlayer" parent="." index="1"] diff --git a/godot/objects/enemy.tscn b/godot/objects/enemy.tscn index 420df04..593b1f0 100644 --- a/godot/objects/enemy.tscn +++ b/godot/objects/enemy.tscn @@ -9,8 +9,7 @@ height = 2.38725 [node name="Enemy" type="Enemy"] update_interval = 0.25 -collision_layer = 3 -collision_mask = 3 +collision_layer = 6 [node name="CharacterModel" parent="." instance=ExtResource("1_i7aop")] unique_name_in_owner = true @@ -18,9 +17,6 @@ unique_name_in_owner = true [node name="mesh_helmet_a" parent="CharacterModel/skeleton_character/Skeleton3D" index="1"] visible = false -[node name="BoneAttachment3D" parent="CharacterModel/skeleton_character/Skeleton3D" index="3"] -transform = Transform3D(-0.937186, 0.347435, 0.0311762, 0.0973187, 0.17459, 0.97982, 0.33498, 0.921308, -0.197435, -0.16719, 1.02003, 0.0528419) - [node name="AnimationTree" parent="CharacterModel" index="2"] parameters/Actions/Run/Speed/blend_amount = 0.0 "parameters/Actions/Walk [turn]/Speed/blend_amount" = 0.0 @@ -33,6 +29,7 @@ shape = SubResource("CapsuleShape3D_3tduq") unique_name_in_owner = true path_desired_distance = 0.5 simplify_path = true +avoidance_enabled = true debug_enabled = true [node name="DroneSound" type="AudioStreamPlayer3D" parent="."] diff --git a/godot/objects/player.tscn b/godot/objects/player.tscn index b24ed2d..752d400 100644 --- a/godot/objects/player.tscn +++ b/godot/objects/player.tscn @@ -16,12 +16,81 @@ floor_snap_length = 1.0 [node name="CharacterModel" parent="." instance=ExtResource("1_cwt7u")] unique_name_in_owner = true +[node name="Skeleton3D" parent="CharacterModel/skeleton_character" index="0"] +bones/0/rotation = Quaternion(1.12928e-22, 1, 2.98023e-08, -1.94707e-07) +bones/1/position = Vector3(3.1225e-17, 0.826102, -2.26306e-09) +bones/1/rotation = Quaternion(-0.0189874, -6.30661e-09, -1.08732e-09, 0.99982) +bones/2/rotation = Quaternion(0.0262842, 8.66579e-09, 1.56723e-09, 0.999655) +bones/3/rotation = Quaternion(-0.013812, -0.124595, 8.42949e-05, 0.992112) +bones/4/rotation = Quaternion(0.0100466, -3.89644e-10, 6.78268e-10, 0.99995) +bones/5/rotation = Quaternion(-0.0233085, 0.0669743, -0.00156502, 0.997481) +bones/6/rotation = Quaternion(0.623077, 0.672557, 0.307599, -0.254607) +bones/7/rotation = Quaternion(-0.311931, -0.528262, 0.360764, 0.702487) +bones/8/rotation = Quaternion(0.385362, 0.19105, 0.552644, 0.713849) +bones/9/rotation = Quaternion(0.204715, 0.0914037, 0.275611, 0.93476) +bones/10/rotation = Quaternion(-0.160687, -0.0459478, -0.0475321, 0.984789) +bones/11/rotation = Quaternion(-0.030518, -0.0130498, -0.0216154, 0.999215) +bones/12/rotation = Quaternion(0.0087248, 0.00565774, 0.0013103, 0.999945) +bones/13/rotation = Quaternion(-0.617934, -0.0462445, 0.180663, 0.763793) +bones/14/rotation = Quaternion(-0.23045, 0.0743406, 0.160693, 0.956841) +bones/15/rotation = Quaternion(-0.541263, -0.00752765, 0.238029, 0.806424) +bones/16/rotation = Quaternion(-0.611024, -0.262913, 0.402215, 0.629087) +bones/17/rotation = Quaternion(0.0158022, 0.0368156, 0.177499, 0.983305) +bones/18/rotation = Quaternion(-0.115784, 0.0786986, 0.503797, 0.852402) +bones/19/rotation = Quaternion(-0.77808, 0.139756, 0.0140334, 0.612261) +bones/20/rotation = Quaternion(-0.0923591, 0.0238578, 0.0736642, 0.992711) +bones/21/rotation = Quaternion(-0.193467, 0.101022, 0.0447897, 0.974864) +bones/22/rotation = Quaternion(-0.293695, -0.10649, 0.259809, 0.91373) +bones/23/rotation = Quaternion(-0.0310475, -0.0162325, -0.00151601, 0.999385) +bones/24/rotation = Quaternion(0.140362, -0.0289769, -0.195164, 0.970242) +bones/25/rotation = Quaternion(0.585184, -0.476496, -0.473244, -0.454479) +bones/26/rotation = Quaternion(-0.449756, 0.301541, -0.311322, 0.780943) +bones/27/rotation = Quaternion(-0.122233, -0.135947, -0.565028, 0.804562) +bones/28/rotation = Quaternion(0.155388, -0.432411, -0.521703, 0.71882) +bones/29/rotation = Quaternion(-0.0486368, 0.0590466, -0.0759536, 0.994173) +bones/30/rotation = Quaternion(-0.0305179, 0.0130499, 0.0216153, 0.999215) +bones/31/rotation = Quaternion(-0.518356, -0.00412336, -0.00408935, 0.855145) +bones/32/rotation = Quaternion(-0.290993, 0.0788459, 0.0248015, 0.953148) +bones/33/rotation = Quaternion(-0.419789, -0.067382, -0.039477, 0.904256) +bones/34/rotation = Quaternion(-0.266884, 0.00530696, 0.000658852, 0.963714) +bones/35/rotation = Quaternion(-0.422483, 0.214372, -0.00100308, 0.880654) +bones/36/rotation = Quaternion(-0.345783, -0.0439312, -0.261553, 0.900052) +bones/37/rotation = Quaternion(-0.0107009, 0.0076969, 0.00365465, 0.999906) +bones/38/rotation = Quaternion(-0.389883, 0.108139, -0.120461, 0.906525) +bones/39/rotation = Quaternion(-0.399909, -0.0921328, -0.130163, 0.902575) +bones/40/rotation = Quaternion(-0.0125688, 0.0114118, 0.00134583, 0.999855) +bones/41/rotation = Quaternion(-0.0497163, 0.0839878, -0.166226, 0.981246) +bones/42/rotation = Quaternion(-0.0310475, 0.0162325, 0.00151601, 0.999385) +bones/43/rotation = Quaternion(-0.00109124, -0.0104143, 0.0283538, 0.999543) +bones/44/position = Vector3(0.16719, 0.195796, -0.0454406) +bones/44/rotation = Quaternion(-0.610992, 0.0971646, 0.14821, 0.771545) +bones/45/rotation = Quaternion(-0.82326, 4.1804e-09, -1.03579e-07, 0.567665) +bones/46/position = Vector3(8.07956e-09, 0.0363644, 0.0392254) +bones/46/rotation = Quaternion(-0.00112372, -6.23921e-08, 6.44731e-09, 0.999999) +bones/48/rotation = Quaternion(0.706312, -2.55434e-08, 6.24918e-08, 0.707901) +bones/49/position = Vector3(0.0228929, -0.0282939, -0.00824324) +bones/49/rotation = Quaternion(-0.112129, 0.585203, -0.155744, 0.78785) +bones/50/position = Vector3(-0.0246244, 0.246628, -0.0197923) +bones/50/rotation = Quaternion(0.31578, 0.920316, 0.115311, -0.200014) +bones/51/position = Vector3(0.0902225, 0.042579, 0.00142519) +bones/51/rotation = Quaternion(0.997309, -0.00549226, 0.0715033, -0.0152251) +bones/52/rotation = Quaternion(-0.00225666, 0.00306653, -0.000453776, 0.999993) +bones/53/rotation = Quaternion(0.665461, 0.000165138, -0.00238783, 0.746429) +bones/54/position = Vector3(-0.0902225, 0.042579, 0.00142518) +bones/54/rotation = Quaternion(0.997309, 0.00549227, -0.0715033, -0.0152251) +bones/55/rotation = Quaternion(-0.00225666, -0.0030665, 0.000453778, 0.999993) +bones/56/rotation = Quaternion(0.665461, -0.000165001, 0.00238774, 0.746429) +bones/57/position = Vector3(3.64125e-07, 0.0462301, -0.935059) +bones/58/rotation = Quaternion(-2.99921e-13, 0.707107, 0.707107, -2.99921e-13) +bones/59/rotation = Quaternion(2.01446e-13, 0.707107, 0.707107, 2.01446e-13) +bones/60/rotation = Quaternion(-0.707107, 1.25097e-07, 1.25097e-07, 0.707107) +bones/61/rotation = Quaternion(-0.707107, 1.25097e-07, 1.25097e-07, 0.707107) +bones/62/rotation = Quaternion(-0.707107, 1.5189e-07, 1.5189e-07, 0.707107) +bones/63/rotation = Quaternion(-0.707107, 1.5189e-07, 1.5189e-07, 0.707107) + [node name="mesh_helmet_a_001" parent="CharacterModel/skeleton_character/Skeleton3D" index="2"] visible = false -[node name="BoneAttachment3D" parent="CharacterModel/skeleton_character/Skeleton3D" index="3"] -transform = Transform3D(-0.937186, 0.347435, 0.0311762, 0.0973187, 0.17459, 0.97982, 0.33498, 0.921308, -0.197435, -0.16719, 1.02003, 0.0528419) - [node name="HitscanMuzzle" parent="CharacterModel/skeleton_character/Skeleton3D/BoneAttachment3D" index="0"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.00234e-08, 0.0436091, 0.0479187) @@ -38,7 +107,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.60962, 0) [node name="CameraSpring" type="SpringArm3D" parent="CameraParent"] unique_name_in_owner = true -transform = Transform3D(-0.96363, 0, -0.267238, 0, 1, 0, 0.267238, 0, -0.96363, 0, 0, 0) +transform = Transform3D(-0.982761, 0, -0.184878, 0, 1, 0, 0.184878, 0, -0.982761, 0, 0, 0) shape = SubResource("SphereShape3D_v7ajo") spring_length = 1.3 diff --git a/godot/project.godot b/godot/project.godot index 07f1c4c..1094eb1 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -92,6 +92,9 @@ switch_shoulder={ 3d_render/layer_1="Default" 3d_render/layer_3="NavMesh" +3d_physics/layer_1="Default" +3d_physics/layer_2="Characters" +3d_physics/layer_3="Enemy" [navigation] diff --git a/src/enemy.cpp b/src/enemy.cpp index 9b1e618..fe6c9c4 100644 --- a/src/enemy.cpp +++ b/src/enemy.cpp @@ -24,11 +24,12 @@ void Enemy::_ready() { if(this->has_node("%DebugLabel")) { this->debug_label = this->get_node("%DebugLabel"); } + this->agent->connect("velocity_computed", callable_mp(this, &Enemy::_on_velocity_calculated)); } void Enemy::_process(double delta) { this->set_current_state_name(this->current_state_name); - float const angle_left{this->target_rotation - this->get_rotation().y}; + float const angle_left{gd::Math::wrapf(this->target_rotation - this->get_rotation().y, -M_2_PIf, M_2_PIf)}; float const step(gd::Math::sign(angle_left) * delta * (this->anim_tree->get_current_state().begins_with("Run") ? this->TURN_SPEED : this->AIM_SPEED)); if(gd::Math::abs(angle_left) <= gd::Math::abs(step)) { this->rotate_y(angle_left); @@ -37,8 +38,11 @@ void Enemy::_process(double delta) { this->rotate_y(step); this->at_target_angle = false; } - if(this->current_action_fn == (ActionFn)&Enemy::chase_player) - this->target_rotation = gd::Vector3{0.f, 0.f, 1.f}.signed_angle_to(this->agent->get_next_path_position() - this->get_global_position(), {0.f, 1.f, 0.f}); +} + +void Enemy::_on_velocity_calculated(gd::Vector3 velocity) { + if(this->current_action_fn == (ActionFn)&Enemy::chase_player && !this->agent->is_navigation_finished()) + this->target_rotation = gd::Vector3{0.f, 0.f, 1.f}.signed_angle_to(velocity, {0.f, 1.f, 0.f}); } void Enemy::update() { @@ -53,7 +57,9 @@ void Enemy::update() { Enemy::ActionFn Enemy::wait_line_of_sight() { this->set_current_state_name("Guard"); - if(this->can_see_player) + if(this->get_global_position().distance_squared_to(this->player->get_global_position()) < this->STAB_RANGE * this->STAB_RANGE) + return (ActionFn)&Enemy::stab; + else if(this->can_see_player) return (ActionFn)&Enemy::take_aim; else return (ActionFn)&Enemy::wait_line_of_sight; @@ -73,6 +79,7 @@ Enemy::ActionFn Enemy::take_aim() { Enemy::ActionFn Enemy::fire() { this->set_current_state_name("Shoot (fire)"); ++this->shots_fired; + this->target_rotation = gd::Vector3{0.f, 0.f, 1.f}.signed_angle_to(this->last_known_player_position - this->aim_offset_position(), {0.f, 1.f, 0.f}); this->anim_tree->set_fire_weapon(); return (ActionFn)&Enemy::wait_end_of_shot; } @@ -110,6 +117,7 @@ Enemy::ActionFn Enemy::chase_enter() { this->set_current_state_name("Chase (plot)"); this->anim_tree->set_aim_weapon(false); this->agent->set_target_position(this->last_known_player_position); + this->agent->set_avoidance_priority(this->MOVING_NAV_PRIORITY); return (ActionFn)&Enemy::chase_player; } @@ -118,7 +126,7 @@ Enemy::ActionFn Enemy::chase_player() { if(this->can_see_player && this->is_in_stab_range()) { this->anim_tree->set_lock_running(false); return (ActionFn)&Enemy::stab; - } else if(this->agent->is_navigation_finished() || this->is_on_wall()) { + } else if(this->agent->is_navigation_finished()) { this->target_rotation = this->last_known_player_rotation; this->anim_tree->set_lock_running(false); return (ActionFn)&Enemy::stop_running; @@ -131,6 +139,7 @@ Enemy::ActionFn Enemy::chase_player() { Enemy::ActionFn Enemy::stop_running() { this->set_current_state_name("Chase (stop)"); this->agent->set_target_position(this->get_global_position()); + this->agent->set_avoidance_priority(this->STATIONARY_NAV_PRIORITY); return this->anim_tree->get_current_state().begins_with("Run") ? (ActionFn)&Enemy::stop_running : (ActionFn)&Enemy::wait_line_of_sight; } @@ -143,7 +152,6 @@ void Enemy::_physics_process(double delta) { basis.get_column(2) * motion.z } / delta); this->move_and_slide(); - this->update_can_see_player(); } @@ -169,7 +177,7 @@ void Enemy::update_can_see_player() { gd::Vector3 const origin{this->get_global_position() + gd::Vector3{0.f, 1.8f, 0.f}}; gd::Vector3 const target{this->player->get_global_position() + gd::Vector3{0.f, 1.8f, 0.f}}; float const dot{(target - origin).normalized().dot(this->get_global_basis().get_column(2))}; - if(dot <= 0.2f && target.distance_to(origin) > 4.f) { + if(this->current_action_fn != (ActionFn)&Enemy::chase_player && dot <= 0.2f && target.distance_to(origin) > 4.f) { this->can_see_player = false; } else { gd::PhysicsDirectSpaceState3D *space{this->get_world_3d()->get_direct_space_state()}; diff --git a/src/enemy.hpp b/src/enemy.hpp index 80e71b6..6ef0a41 100644 --- a/src/enemy.hpp +++ b/src/enemy.hpp @@ -19,6 +19,7 @@ typedef ActionFn_ (Enemy::*ActionFn)(); public: virtual void _ready() override; virtual void _process(double delta) override; + void _on_velocity_calculated(gd::Vector3 velocity); void update(); ActionFn wait_line_of_sight(); ActionFn take_aim(); @@ -45,6 +46,8 @@ private: float const TURN_SPEED{10.f}; float const AIM_OFFSET{-0.18f}; float const STAB_RANGE{2.f}; + float const MOVING_NAV_PRIORITY{.5f}; + float const STATIONARY_NAV_PRIORITY{1.f}; float target_rotation{0.f}; bool at_target_angle{false};