Skip to content

Commit

Permalink
feat: add sprite_frame_index method to state (#81)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The method `SpriteState::set_current_index` is renamed to `SpriteState::set_index`
  • Loading branch information
jcornaz authored Jul 17, 2022
1 parent 02918b1 commit 4b5bc45
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 34 deletions.
6 changes: 3 additions & 3 deletions src/integration/bevy_07.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl Plugin for crate::AnimationPlugin {
}

impl SpriteState for TextureAtlasSprite {
fn set_current_index(&mut self, index: usize) {
fn set_index(&mut self, index: usize) {
self.index = index;
}
}
Expand Down Expand Up @@ -114,8 +114,8 @@ fn animate<T: SpriteState + Component>(
}

impl<'w, T: SpriteState> SpriteState for Mut<'w, T> {
fn set_current_index(&mut self, index: usize) {
self.deref_mut().set_current_index(index);
fn set_index(&mut self, index: usize) {
self.deref_mut().set_index(index);
}
}

Expand Down
92 changes: 61 additions & 31 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::time::Duration;

use bevy_ecs::prelude::*;

use crate::{animation::Mode, SpriteSheetAnimation};
use crate::{animation::Mode, Frame, SpriteSheetAnimation};

/// Animation state component which is automatically inserted/removed
///
Expand All @@ -22,14 +22,14 @@ use crate::{animation::Mode, SpriteSheetAnimation};
/// ```
#[derive(Default, Component)]
pub struct SpriteSheetAnimationState {
current_frame: usize,
animation_frame_index: usize,
elapsed_in_frame: Duration,
// Control ping_pong backward frame navigation.
going_backward: bool,
}

pub trait SpriteState {
fn set_current_index(&mut self, index: usize);
fn set_index(&mut self, index: usize);
}

impl SpriteSheetAnimationState {
Expand All @@ -40,12 +40,32 @@ impl SpriteSheetAnimationState {
*self = Self::default();
}

/// Returns the index of the current frame
#[must_use]
#[deprecated(since = "4.0.0", note = "please use `animation_frame_index` instead")]
#[doc(hidden)]
pub fn current_frame_index(&self) -> usize {
self.animation_frame_index()
}

/// Returns the index of the current *animation* frame
///
/// The index is relative to the animation sequence. **not** to the sprite-sheet.
#[must_use]
pub fn current_frame_index(&self) -> usize {
self.current_frame
pub fn animation_frame_index(&self) -> usize {
self.animation_frame_index
}

/// Returns the index of the current *sprite* frame
///
/// The index is relative to the sprite atlas. **not** to the animation frame sequence.
#[must_use]
pub fn sprite_frame_index(&self, animation: &SpriteSheetAnimation) -> usize {
self.frame(animation).index
}

#[must_use]
fn frame<'a>(&self, animation: &'a SpriteSheetAnimation) -> &'a Frame {
&animation.frames[self.animation_frame_index() % animation.frames.len()]
}

/// Update the animation and the sprite (if necessary)
Expand All @@ -60,37 +80,37 @@ impl SpriteSheetAnimationState {
) -> bool {
debug_assert!(animation.has_frames());

let mut frame = animation.frames[self.current_frame % animation.frames.len()];
sprite.set_current_index(frame.index);
let mut frame = self.frame(animation);
sprite.set_index(frame.index);

self.elapsed_in_frame += delta;
while self.elapsed_in_frame >= frame.duration {
match animation.mode {
Mode::RepeatFrom(loop_from) => {
if self.current_frame < animation.frames.len() - 1 {
self.current_frame += 1;
if self.animation_frame_index < animation.frames.len() - 1 {
self.animation_frame_index += 1;
} else {
self.current_frame = loop_from;
self.animation_frame_index = loop_from;
}
}
Mode::PingPong => {
if self.going_backward {
if self.current_frame == 0 {
if self.animation_frame_index == 0 {
self.going_backward = false;
self.current_frame += 1;
self.animation_frame_index += 1;
} else {
self.current_frame -= 1;
self.animation_frame_index -= 1;
}
} else if self.current_frame < animation.frames.len() - 1 {
self.current_frame += 1;
} else if self.animation_frame_index < animation.frames.len() - 1 {
self.animation_frame_index += 1;
} else {
self.going_backward = true;
self.current_frame -= 1;
self.animation_frame_index -= 1;
}
}
Mode::Once => {
if self.current_frame < animation.frames.len() - 1 {
self.current_frame += 1;
if self.animation_frame_index < animation.frames.len() - 1 {
self.animation_frame_index += 1;
} else {
self.reset();
return true;
Expand All @@ -99,8 +119,8 @@ impl SpriteSheetAnimationState {
}

self.elapsed_in_frame -= frame.duration;
frame = animation.frames[self.current_frame];
sprite.set_current_index(frame.index);
frame = self.frame(animation);
sprite.set_index(frame.index);
}

false
Expand All @@ -116,7 +136,7 @@ mod tests {
}

impl SpriteState for TextureAtlasSprite {
fn set_current_index(&mut self, index: usize) {
fn set_index(&mut self, index: usize) {
self.index = index;
}
}
Expand All @@ -136,13 +156,20 @@ mod tests {
frame_duration - Duration::from_millis(1)
}

#[rstest]
fn sprite_index(frame_duration: Duration) {
let animation = SpriteSheetAnimation::from_range(3..=5, frame_duration);
let state = SpriteSheetAnimationState::default();
assert_eq!(state.sprite_frame_index(&animation), 3);
}

mod reset {
use super::*;

#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 1,
animation_frame_index: 1,
elapsed_in_frame: Duration::from_secs(1),
going_backward: false,
}
Expand All @@ -151,7 +178,7 @@ mod tests {
#[rstest]
fn resets_current_frame(mut state: SpriteSheetAnimationState) {
state.reset();
assert_eq!(state.current_frame, 0);
assert_eq!(state.animation_frame_index, 0);
}

#[rstest]
Expand Down Expand Up @@ -293,7 +320,7 @@ mod tests {
#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 4,
animation_frame_index: 4,
elapsed_in_frame: Duration::from_nanos(0),
going_backward: false,
}
Expand Down Expand Up @@ -338,7 +365,7 @@ mod tests {
#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 4,
animation_frame_index: 4,
elapsed_in_frame: Duration::from_nanos(0),
going_backward: false,
}
Expand Down Expand Up @@ -381,7 +408,7 @@ mod tests {
#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 1,
animation_frame_index: 1,
elapsed_in_frame: Duration::from_nanos(500),
going_backward: false,
}
Expand Down Expand Up @@ -421,7 +448,7 @@ mod tests {
#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 1,
animation_frame_index: 1,
elapsed_in_frame: Duration::from_nanos(500),
going_backward: true,
}
Expand Down Expand Up @@ -454,7 +481,7 @@ mod tests {
#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 0,
animation_frame_index: 0,
elapsed_in_frame: Duration::from_nanos(500),
going_backward: false,
}
Expand All @@ -478,7 +505,7 @@ mod tests {
#[fixture]
fn state() -> SpriteSheetAnimationState {
SpriteSheetAnimationState {
current_frame: 1,
animation_frame_index: 1,
elapsed_in_frame: Duration::from_nanos(500),
going_backward: false,
}
Expand Down Expand Up @@ -514,7 +541,10 @@ mod tests {
) {
state.update(&mut sprite, &animation, frame_duration);
let expected_state = SpriteSheetAnimationState::default();
assert_eq!(state.current_frame, expected_state.current_frame);
assert_eq!(
state.animation_frame_index,
expected_state.animation_frame_index
);
assert_eq!(state.elapsed_in_frame, expected_state.elapsed_in_frame);
}
}
Expand Down

0 comments on commit 4b5bc45

Please sign in to comment.