From 376ae8c77085a88536ef9825b5dd7775d34f239c Mon Sep 17 00:00:00 2001 From: PROMETHIA-27 <42193387+PROMETHIA-27@users.noreply.github.com> Date: Mon, 23 Jun 2025 08:06:36 -0400 Subject: [PATCH] Uninterruptible shooting animations (#49) --- assets/all.headsdb.ron | 2 +- src/animation.rs | 56 +++++++++++++++++++++++++++++++++++++++--- src/heads_database.rs | 10 +++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/assets/all.headsdb.ron b/assets/all.headsdb.ron index 29fb88d..d594b51 100644 --- a/assets/all.headsdb.ron +++ b/assets/all.headsdb.ron @@ -1,5 +1,5 @@ ([ - /*00*/(key:"angry demonstrator", ability:Thrown, aps:2, ammo:10, range:90, damage:25, projectile:"molotov"), + /*00*/(key:"angry demonstrator", ability:Thrown, aps:2, ammo:10, range:90, damage:25, projectile:"molotov", interrupt_shoot:false), /*01*/(key:"carnival knife thrower", ability:Arrow, range:60, ammo:5), /*02*/(key:"chicago gangster", ability:Gun, ammo:25, range:60), /*03*/(key:"commando", ability:Gun, aps:7.4, ammo:26, range:60, damage:12), diff --git a/src/animation.rs b/src/animation.rs index 138fecb..ec567fa 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -1,4 +1,6 @@ -use crate::{GameState, character::CharacterAnimations}; +use crate::{ + GameState, character::CharacterAnimations, head::ActiveHead, heads_database::HeadsDatabase, +}; use bevy::{animation::RepeatAnimation, ecs::query::QueryData, prelude::*}; use std::time::Duration; @@ -71,24 +73,70 @@ fn update_animation( &CharacterAnimations, &mut AnimationFlags, )>, + character: Query<&ActiveHead>, + headdb: Res, ) { for (mut controller, anims, mut flags) in animated.iter_mut() { - if flags.shooting && flags.any_direction && anims.run_shoot.is_some() { + let head = character.get(anims.of_character).unwrap(); + let head = headdb.head_stats(head.0); + + let is_playing_shoot = anims.shoot.is_some() + && controller.is_playing(anims.shoot.unwrap()) + && !controller + .player + .animation(anims.shoot.unwrap()) + .unwrap() + .is_finished(); + let is_playing_run_shoot = anims.run_shoot.is_some() + && controller.is_playing(anims.run_shoot.unwrap()) + && !controller + .player + .animation(anims.run_shoot.unwrap()) + .unwrap() + .is_finished(); + let wait_for_shoot = !head.interrupt_shoot && (is_playing_shoot || is_playing_run_shoot); + if wait_for_shoot { + return; + } else if flags.shooting && flags.any_direction && anims.run_shoot.is_some() { if !controller.is_playing(anims.run_shoot.unwrap()) { controller.play( anims.run_shoot.unwrap(), DEFAULT_TRANSITION_DURATION, - RepeatAnimation::Forever, + RepeatAnimation::Never, ); } + if controller + .player + .animation(anims.run_shoot.unwrap()) + .unwrap() + .is_finished() + { + controller + .player + .animation_mut(anims.run_shoot.unwrap()) + .unwrap() + .replay(); + } } else if flags.shooting && anims.shoot.is_some() { if !controller.is_playing(anims.shoot.unwrap()) { controller.play( anims.shoot.unwrap(), DEFAULT_TRANSITION_DURATION, - RepeatAnimation::Forever, + RepeatAnimation::Never, ); } + if controller + .player + .animation(anims.shoot.unwrap()) + .unwrap() + .is_finished() + { + controller + .player + .animation_mut(anims.shoot.unwrap()) + .unwrap() + .replay(); + } } else if flags.hit { if !controller.is_playing(anims.hit) { controller.play( diff --git a/src/heads_database.rs b/src/heads_database.rs index a9f7b45..60ffaf4 100644 --- a/src/heads_database.rs +++ b/src/heads_database.rs @@ -24,9 +24,13 @@ pub struct HeadStats { pub ammo: u32, #[serde(default)] pub damage: u32, - // ability per second + /// ability per second #[serde(default = "default_aps")] pub aps: f32, + #[serde(default = "default_interrupt_shoot")] + pub interrupt_shoot: bool, + #[serde(default)] + pub shoot_offset: f32, } fn default_aps() -> f32 { @@ -37,6 +41,10 @@ fn default_ammo() -> u32 { 10 } +fn default_interrupt_shoot() -> bool { + true +} + #[derive(Debug, Asset, Reflect, Serialize, Deserialize)] pub struct HeadDatabaseAsset(pub Vec);