Skip to content

Commit

Permalink
feat: play animation with custom playback speed (#66)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonathan Cornaz <[email protected]>
  • Loading branch information
flipbit03 and jcornaz authored Jun 22, 2022
1 parent 7595217 commit 7c2a500
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 23 deletions.
60 changes: 60 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<f64> for PlaySpeedMultiplier {
fn from(mult: f64) -> Self {
Self(mult)
}
}

impl From<f32> for PlaySpeedMultiplier {
fn from(mult: f32) -> Self {
Self(mult.into())
}
}

impl Plugin for AnimationPlugin {
fn build(&self, app: &mut App) {
app.add_asset::<SpriteSheetAnimation>()
Expand All @@ -201,3 +240,24 @@ impl Plugin for AnimationPlugin {
app.init_asset_loader::<animation::load::SpriteSheetAnimationLoader>();
}
}

#[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)
);
}
}
49 changes: 26 additions & 23 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -146,33 +146,36 @@ fn remove(
}
}

type AnimationSystemQuery<'a> = (
Entity,
&'a mut TextureAtlasSprite,
&'a Handle<SpriteSheetAnimation>,
&'a mut SpriteSheetAnimationState,
Option<&'a PlaySpeedMultiplier>,
);

fn animate(
mut commands: Commands<'_, '_>,
time: Res<'_, Time>,
animation_defs: Res<'_, Assets<SpriteSheetAnimation>>,
mut animations: Query<
'_,
'_,
(
Entity,
&mut TextureAtlasSprite,
&Handle<SpriteSheetAnimation>,
&mut SpriteSheetAnimationState,
),
With<Play>,
>,
mut animations: Query<'_, '_, AnimationSystemQuery<'_>, With<Play>>,
) {
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::<Play>();
}
}
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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,));
}
}

Expand Down Expand Up @@ -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,));
}
}
}
Expand Down Expand Up @@ -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]
Expand Down

0 comments on commit 7c2a500

Please sign in to comment.