feat: added revolver

This commit is contained in:
Sara 2025-07-31 21:47:59 +02:00
parent 3b22cd86f7
commit 6eba3b0454
17 changed files with 195 additions and 29 deletions

View file

@ -0,0 +1,66 @@
#include "revolver.h"
#include "scene/animation/animation_player.h"
#include "wave_survival/player_input.h"
void Revolver::_bind_methods() {
}
void Revolver::play_equip_anim() {
get_anim()->play("equip", 0.0);
get_anim()->queue("idle_double");
get_anim()->advance(0.0);
}
void Revolver::shoot() {
if (!is_animating()) {
this->muzzle->shoot();
if (this->alt_requested) {
get_anim()->queue("fire_single");
get_anim()->queue("idle_single");
} else {
get_anim()->queue("fire_double");
get_anim()->queue("idle_double");
}
}
}
void Revolver::on_primary_fire(bool pressed) {
if (pressed) {
shoot();
}
}
void Revolver::on_alt_mode(bool pressed) {
this->alt_requested = pressed;
}
void Revolver::ready() {
this->muzzle = cast_to<HitscanMuzzle>(get_node(NodePath("%HitscanMuzzle")));
get_input()->connect(PlayerInput::sig_primary_fire, callable_mp(this, &self_type::on_primary_fire));
get_input()->connect(PlayerInput::sig_alt_mode, callable_mp(this, &self_type::on_alt_mode));
play_equip_anim();
}
void Revolver::process(double delta) {
}
void Revolver::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_READY:
set_process(true);
ready();
return;
case NOTIFICATION_PROCESS:
process(get_process_delta_time());
return;
}
}
void Revolver::notify_selected() {
play_equip_anim();
}

View file

@ -0,0 +1,27 @@
#ifndef WEAPONS_REVOLVER_H
#define WEAPONS_REVOLVER_H
#include "wave_survival/hitscan_muzzle.h"
#include "wave_survival/weapon_base.h"
class Revolver : public WeaponBase {
GDCLASS(Revolver, WeaponBase);
static void _bind_methods();
void play_equip_anim();
void shoot();
void on_primary_fire(bool pressed);
void on_alt_mode(bool pressed);
void ready();
void process(double delta);
protected:
void _notification(int what);
virtual void notify_selected() override;
private:
bool alt_requested{ false };
bool alt_active{ false };
HitscanMuzzle *muzzle{ nullptr };
};
#endif // !WEAPONS_REVOLVER_H

View file

@ -12,24 +12,24 @@ void Rifle::_bind_methods() {
BIND_PROPERTY(Variant::FLOAT, recoil_time);
}
void Rifle::queue_start_aim() {
void Rifle::queue_enter_alt() {
get_anim()->queue("hip_to_aim");
get_anim()->queue("aim");
}
void Rifle::queue_stop_ads_anim() {
void Rifle::queue_exit_alt() {
get_anim()->queue("aim_to_hip");
get_anim()->queue("hip");
}
void Rifle::queue_start_run_anim() {
void Rifle::queue_enter_run() {
this->running = true;
get_anim()->clear_queue();
get_anim()->queue("hip_to_run");
get_anim()->queue("run");
}
void Rifle::stop_run_anim() {
void Rifle::exit_run() {
this->running = false;
get_anim()->clear_queue();
if (this->request_alt_mode) {
@ -55,6 +55,7 @@ void Rifle::shoot() {
void Rifle::play_equip_anim() {
get_anim()->play("equip", 0.0);
get_anim()->queue("hip");
get_anim()->advance(0.0);
}
void Rifle::on_primary_fire(bool pressed) {
@ -90,8 +91,11 @@ void Rifle::ready() {
void Rifle::process(double delta) {
String const current{ get_anim()->get_current_animation() };
bool run_requested{ this->run_requested() };
// track animation progress
double const animation_time{ get_anim()->get_current_animation_position() };
// percentually
float const progress{ float(CLAMP(animation_time / get_anim()->get_current_animation_length(), 0.0, 1.0)) };
// lerp the current FOV factor depending on the ongoing animation
if (current == "hip_to_aim") {
get_camera()->set_fov_factor(Math::lerp(1.f, this->ads_factor, progress));
} else if (current == "aim_to_hip") {
@ -102,21 +106,23 @@ void Rifle::process(double delta) {
get_camera()->set_fov_factor(Math::lerp(1.f, this->run_factor, progress));
} else if (current == "run_to_hip") {
get_camera()->set_fov_factor(Math::lerp(this->run_factor, 1.f, progress));
// animation is not one of the transitory ones ( x_to_y ),
// check if there is a request for a transitory animation
} else if (this->request_alt_mode != this->in_alt_mode && !is_animating()) {
if (this->request_alt_mode) {
queue_start_aim();
queue_enter_alt();
} else {
queue_stop_ads_anim();
queue_exit_alt();
}
} else if (this->running != run_requested) {
if (run_requested && !is_animating()) {
queue_start_run_anim();
queue_enter_run();
} else if (!run_requested) {
stop_run_anim();
exit_run();
}
}
if (current == "fire_hip" || current == "fire_aim") {
// apply fire recoil
else 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);
}
@ -139,6 +145,14 @@ void Rifle::_notification(int what) {
}
}
PackedStringArray Rifle::get_configuration_warnings() const {
PackedStringArray warnings{ super_type::get_configuration_warnings() };
if (get_node(NodePath("%HitscanMuzzle")) == nullptr) {
warnings.push_back("Rifle needs a hitscan muzzle.\nConsider adding a node called '%HitscanMuzzle' of type HitscanMuzzle");
}
return warnings;
}
bool Rifle::allows_running() const {
String const animation{ get_anim()->get_current_animation() };
return animation == "run" && !this->request_alt_mode;
@ -149,11 +163,7 @@ bool Rifle::run_requested() const {
}
void Rifle::notify_selected() {
get_anim()->play("equip");
}
bool Rifle::is_animating() const {
return !get_anim()->get_current_animation().is_empty() || !get_anim()->get_queue().is_empty();
play_equip_anim();
}
void Rifle::set_ads_factor(float value) {

View file

@ -9,10 +9,10 @@ class HitscanMuzzle;
class Rifle : public WeaponBase {
GDCLASS(Rifle, WeaponBase);
static void _bind_methods();
void queue_start_aim();
void queue_stop_ads_anim();
void queue_start_run_anim();
void stop_run_anim();
void queue_enter_alt();
void queue_exit_alt();
void queue_enter_run();
void exit_run();
void shoot();
void play_equip_anim();
void on_primary_fire(bool down);
@ -24,11 +24,11 @@ class Rifle : public WeaponBase {
public:
void _notification(int what);
virtual PackedStringArray get_configuration_warnings() const override;
virtual bool allows_running() const override;
bool run_requested() const;
virtual void notify_selected() override;
bool is_animating() const;
void set_ads_factor(float value);
float get_ads_factor() const;