From 58e90780d5d31b5f715e70a57c8e71e98cb2c912 Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 19 Jul 2025 14:26:46 +0200 Subject: [PATCH] feat: implemented recoil --- modules/wave_survival/hitscan_muzzle.h | 2 +- modules/wave_survival/player_camera.cpp | 20 ++++++++++++++++---- modules/wave_survival/player_camera.h | 4 ++++ modules/wave_survival/weapons/rifle.cpp | 24 +++++++++++++++++++++++- modules/wave_survival/weapons/rifle.h | 10 ++++++++++ project/objects/weapons/rifle.tscn | 3 ++- 6 files changed, 56 insertions(+), 7 deletions(-) diff --git a/modules/wave_survival/hitscan_muzzle.h b/modules/wave_survival/hitscan_muzzle.h index be538975..59bcd6d6 100644 --- a/modules/wave_survival/hitscan_muzzle.h +++ b/modules/wave_survival/hitscan_muzzle.h @@ -21,7 +21,7 @@ public: int get_ray_count() const; private: - float spread{ 0.01f }; + float spread{ 0.001f }; int damage{ 1 }; int ray_count{ 1 }; diff --git a/modules/wave_survival/player_camera.cpp b/modules/wave_survival/player_camera.cpp index 53e6b3fd..b790470d 100644 --- a/modules/wave_survival/player_camera.cpp +++ b/modules/wave_survival/player_camera.cpp @@ -17,14 +17,20 @@ void PlayerCamera::update_fov() { } } +void PlayerCamera::ready() { + PlayerInput *input{ cast_to(get_node(NodePath("%PlayerInput"))) }; + input->connect(PlayerInput::sig_look_input, callable_mp(this, &self_type::on_look_input)); + this->base_fov = get_fov(); +} + void PlayerCamera::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; } - if (what == NOTIFICATION_READY) { - PlayerInput *input{ cast_to(get_node(NodePath("%PlayerInput"))) }; - input->connect(PlayerInput::sig_look_input, callable_mp(this, &self_type::on_look_input)); - this->base_fov = get_fov(); + switch (what) { + case NOTIFICATION_READY: + ready(); + return; } } @@ -36,3 +42,9 @@ void PlayerCamera::set_fov_factor(float value) { float PlayerCamera::get_fov_factor() const { return this->fov_factor; } + +void PlayerCamera::recoil(float r) { + GETSET(rotation, { + rotation.x = CLAMP(rotation.x + r, -Math::PI / 2.0, Math::PI / 2.0); + }); +} diff --git a/modules/wave_survival/player_camera.h b/modules/wave_survival/player_camera.h index 747cd07b..7e686ac6 100644 --- a/modules/wave_survival/player_camera.h +++ b/modules/wave_survival/player_camera.h @@ -8,6 +8,8 @@ class PlayerCamera : public Camera3D { static void _bind_methods(); void on_look_input(Vector2 input); void update_fov(); + void ready(); + void process(double delta); protected: void _notification(int what); @@ -16,6 +18,8 @@ public: void set_fov_factor(float value); float get_fov_factor() const; + void recoil(float r); + private: float base_fov{ 60.f }; float fov_factor{ 1.0f }; diff --git a/modules/wave_survival/weapons/rifle.cpp b/modules/wave_survival/weapons/rifle.cpp index b8555d8e..31a48f4e 100644 --- a/modules/wave_survival/weapons/rifle.cpp +++ b/modules/wave_survival/weapons/rifle.cpp @@ -88,7 +88,8 @@ void Rifle::ready() { void Rifle::process(double delta) { String const current{ get_anim()->get_current_animation() }; bool run_requested{ this->run_requested() }; - float const progress{ float(CLAMP(get_anim()->get_current_animation_position() / get_anim()->get_current_animation_length(), 0.0, 1.0)) }; + double const animation_time{ get_anim()->get_current_animation_position() }; + float const progress{ float(CLAMP(animation_time / get_anim()->get_current_animation_length(), 0.0, 1.0)) }; if (current == "hip_to_aim") { get_camera()->set_fov_factor(Math::lerp(1.f, this->ads_factor, progress)); } else if (current == "aim_to_hip") { @@ -112,6 +113,11 @@ void Rifle::process(double delta) { stop_run_anim(); } } + + if (current == "fire_hip" || current == "fire_aim") { + double t{ animation_time / this->recoil_time }; + get_camera()->recoil(Math::lerp((double)this->recoil_force, 0.0, CLAMP(t, 0.0, 1.0)) * delta); + } } void Rifle::_notification(int what) { @@ -147,3 +153,19 @@ void Rifle::notify_selected() { bool Rifle::is_animating() const { return !get_anim()->get_current_animation().is_empty() || !get_anim()->get_queue().is_empty(); } + +void Rifle::set_ads_factor(float value) { + this->ads_factor = value; +} + +float Rifle::get_ads_factor() const { + return this->ads_factor; +} + +void Rifle::set_run_factor(float value) { + this->run_factor = value; +} + +float Rifle::get_run_factor() const { + return this->run_factor; +} diff --git a/modules/wave_survival/weapons/rifle.h b/modules/wave_survival/weapons/rifle.h index b8282504..b6d40f5d 100644 --- a/modules/wave_survival/weapons/rifle.h +++ b/modules/wave_survival/weapons/rifle.h @@ -30,6 +30,13 @@ public: virtual void notify_selected() override; bool is_animating() const; + void set_recoil_radians(float value); + float get_recoil_radians() const; + void set_ads_factor(float value); + float get_ads_factor() const; + void set_run_factor(float value); + float get_run_factor() const; + private: float ads_factor{ 0.5f }; float run_factor{ 1.5f }; @@ -37,6 +44,9 @@ private: bool in_alt_mode{ false }; bool running{ false }; + float recoil_force{ 3.f }; + float recoil_time{ 0.05f }; + HitscanMuzzle *muzzle{ nullptr }; }; diff --git a/project/objects/weapons/rifle.tscn b/project/objects/weapons/rifle.tscn index b1ae2e12..d2901e65 100644 --- a/project/objects/weapons/rifle.tscn +++ b/project/objects/weapons/rifle.tscn @@ -20,8 +20,9 @@ bone_idx = 39 [node name="HitscanMuzzle" type="HitscanMuzzle" parent="rifle/Character/Skeleton3D/BoneAttachment3D"] unique_name_in_owner = true -transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 0.99999994, 2.746498e-26, 0, 0.059500493) +transform = Transform3D(1, 0, 0, 0, 0.99999833, -0.0017453281, 0, 0.0017453281, 0.99999833, 1.4540284e-26, 0, 0.027612558) target_position = Vector3(0, 100, 0) +spread = 0.003 [node name="AnimationPlayer" parent="rifle" index="1"] playback_default_blend_time = 0.1