From 7c2a5007dc06eed6e8d0832a6b3705bebffd1626 Mon Sep 17 00:00:00 2001 From: Cadu Date: Wed, 22 Jun 2022 15:49:17 -0300 Subject: [PATCH] feat: play animation with custom playback speed (#66) Co-authored-by: Jonathan Cornaz --- src/lib.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/state.rs | 49 ++++++++++++++++++++++-------------------- 2 files changed, 86 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9303f2b..0f5d27e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,6 +154,8 @@ use bevy_ecs::component::SparseStorage; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; +use std::time::Duration; + pub use animation::{Frame, SpriteSheetAnimation}; pub use state::SpriteSheetAnimationState; @@ -191,6 +193,43 @@ impl Component for Play { type Storage = SparseStorage; } +/// Component that, when applied, can change the playback's rate of the animation. +/// +/// Receives a f64 multiplier which will alter the delta, speeding up or slowing down to the desired playback rate. +#[derive(Debug, Copy, Component, Clone, Reflect)] +#[reflect(Component)] +pub struct PlaySpeedMultiplier(f64); + +impl PlaySpeedMultiplier { + /// Creates a new `PlaySpeedMultiplier` Component with the multiplier set as desired + #[must_use] + pub fn new(multiplier: f64) -> Self { + Self(multiplier) + } + + fn transform(self, duration: Duration) -> Duration { + duration.mul_f64(self.0) + } +} + +impl Default for PlaySpeedMultiplier { + fn default() -> Self { + Self(1.0) + } +} + +impl From for PlaySpeedMultiplier { + fn from(mult: f64) -> Self { + Self(mult) + } +} + +impl From for PlaySpeedMultiplier { + fn from(mult: f32) -> Self { + Self(mult.into()) + } +} + impl Plugin for AnimationPlugin { fn build(&self, app: &mut App) { app.add_asset::() @@ -201,3 +240,24 @@ impl Plugin for AnimationPlugin { app.init_asset_loader::(); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn identity_transformation() { + assert_eq!( + PlaySpeedMultiplier::default().transform(Duration::from_secs(1)), + Duration::from_secs(1) + ); + } + + #[test] + fn double_speed() { + assert_eq!( + PlaySpeedMultiplier::from(2.0).transform(Duration::from_secs(2)), + Duration::from_secs(4) + ); + } +} diff --git a/src/state.rs b/src/state.rs index 3d67c54..7b23f32 100644 --- a/src/state.rs +++ b/src/state.rs @@ -6,7 +6,7 @@ use bevy_core::prelude::*; use bevy_ecs::prelude::*; use bevy_sprite::prelude::*; -use crate::{animation::Mode, Play, SpriteSheetAnimation}; +use crate::{animation::Mode, Play, PlaySpeedMultiplier, SpriteSheetAnimation}; pub(crate) fn maintenance_systems() -> SystemSet { SystemSet::new().with_system(insert).with_system(remove) @@ -146,33 +146,36 @@ fn remove( } } +type AnimationSystemQuery<'a> = ( + Entity, + &'a mut TextureAtlasSprite, + &'a Handle, + &'a mut SpriteSheetAnimationState, + Option<&'a PlaySpeedMultiplier>, +); + fn animate( mut commands: Commands<'_, '_>, time: Res<'_, Time>, animation_defs: Res<'_, Assets>, - mut animations: Query< - '_, - '_, - ( - Entity, - &mut TextureAtlasSprite, - &Handle, - &mut SpriteSheetAnimationState, - ), - With, - >, + mut animations: Query<'_, '_, AnimationSystemQuery<'_>, With>, ) { - for (entity, sprite, animation, mut state) in - animations - .iter_mut() - .filter_map(|(entity, sprite, anim_handle, state)| { + for (entity, sprite, animation, mut state, speed_multiplier) in + animations.iter_mut().filter_map( + |(entity, sprite, anim_handle, state, optional_speed_multiplier)| { animation_defs .get(anim_handle) .filter(|anim| anim.has_frames()) - .map(|anim| (entity, sprite, anim, state)) - }) + .map(|anim| (entity, sprite, anim, state, optional_speed_multiplier)) + }, + ) { - if state.update(sprite, animation, time.delta()) { + let delta = speed_multiplier + .copied() + .unwrap_or_default() + .transform(time.delta()); + + if state.update(sprite, animation, delta) { commands.entity(entity).remove::(); } } @@ -308,7 +311,7 @@ mod tests { animation: SpriteSheetAnimation, frame_duration: Duration, ) { - assert!(!state.update(&mut sprite_at_second_frame, &animation, frame_duration)); + assert!(!state.update(&mut sprite_at_second_frame, &animation, frame_duration,)); } #[rstest] @@ -370,7 +373,7 @@ mod tests { animation: SpriteSheetAnimation, frame_duration: Duration, ) { - assert!(!state.update(&mut sprite_at_second_frame, &animation, frame_duration)); + assert!(!state.update(&mut sprite_at_second_frame, &animation, frame_duration,)); } } @@ -415,7 +418,7 @@ mod tests { animation: SpriteSheetAnimation, frame_duration: Duration, ) { - assert!(!state.update(&mut sprite_at_second_frame, &animation, frame_duration)); + assert!(!state.update(&mut sprite_at_second_frame, &animation, frame_duration,)); } } } @@ -532,7 +535,7 @@ mod tests { animation: SpriteSheetAnimation, frame_duration: Duration, ) { - assert!(state.update(&mut sprite_at_second_frame, &animation, frame_duration)); + assert!(state.update(&mut sprite_at_second_frame, &animation, frame_duration,)); } #[rstest]