diff --git a/src/lib.rs b/src/lib.rs index e992df2..9eaf1f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ //! //! For a more precise configuration, it is possible to define the duration of each frame: //! -//! ```rust +//! ``` //! # use benimator::*; //! # use std::time::Duration; //! SpriteSheetAnimation::from_frames(vec![ @@ -91,6 +91,22 @@ //! ]); //! ``` //! +//! ## Reset animation +//! +//! For each entity with a [`SpriteSheetAnimation`], a [`SpriteSheetAnimationState`] component is automatically inserted. +//! It can be used to reset the animation state by calling [`SpriteSheetAnimationState::reset`] +//! +//! ``` +//! # use bevy::prelude::*; +//! # use benimator::SpriteSheetAnimationState; +//! +//! fn restart_anim_from_start(mut query: Query<&mut SpriteSheetAnimationState>) { +//! for mut state in query.iter_mut() { +//! state.reset(); +//! } +//! } +//! ``` + #[cfg(test)] #[macro_use] extern crate rstest; @@ -101,6 +117,7 @@ use bevy_ecs::prelude::*; use bevy_reflect::Reflect; pub use animation::{AnimationMode, Frame, SpriteSheetAnimation}; +pub use state::SpriteSheetAnimationState; mod animation; mod state; diff --git a/src/state.rs b/src/state.rs index e18e5ab..0f0a450 100644 --- a/src/state.rs +++ b/src/state.rs @@ -18,13 +18,36 @@ pub(crate) fn post_update_system() -> impl System { animate.system() } +/// Animation state component which is automatically inserted/removed +/// +/// It can be used to reset the animation state. +/// +/// # Example +/// +/// ``` +/// # use bevy::prelude::*; +/// # use benimator::SpriteSheetAnimationState; +/// +/// fn restart_anim_from_start(mut query: Query<&mut SpriteSheetAnimationState>) { +/// for mut state in query.iter_mut() { +/// state.reset(); +/// } +/// } +/// ``` #[derive(Default)] -struct SpriteSheetAnimationState { +pub struct SpriteSheetAnimationState { current_frame: usize, elapsed_in_frame: Duration, } impl SpriteSheetAnimationState { + /// Reset animation state + /// + /// The animation will restart from the first frame, like if the animation was freshly spawned. + pub fn reset(&mut self) { + *self = Self::default(); + } + /// Update the animation and the sprite (if necessary) /// /// Returns true if the animation has ended @@ -45,8 +68,7 @@ impl SpriteSheetAnimationState { } else if matches!(animation.mode, AnimationMode::Repeat) { self.current_frame = 0; } else { - self.current_frame = 0; - self.elapsed_in_frame = Duration::ZERO; + self.reset(); return true; } @@ -145,6 +167,30 @@ mod tests { frame_duration - Duration::from_millis(1) } + mod reset { + use super::*; + + #[fixture] + fn state() -> SpriteSheetAnimationState { + SpriteSheetAnimationState { + current_frame: 1, + elapsed_in_frame: Duration::from_secs(1), + } + } + + #[rstest] + fn resets_current_frame(mut state: SpriteSheetAnimationState) { + state.reset(); + assert_eq!(state.current_frame, 0); + } + + #[rstest] + fn resets_elapsed_time(mut state: SpriteSheetAnimationState) { + state.reset(); + assert_eq!(state.elapsed_in_frame, Duration::ZERO); + } + } + mod on_first_frame { use super::*;