Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add sprite_frame_index method to state #81

Merged
merged 1 commit into from
Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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