Skip to content

Commit

Permalink
Replace "cycles" terminology with "repetitions"
Browse files Browse the repository at this point in the history
  • Loading branch information
merwaaan committed Aug 27, 2024
1 parent 1b55379 commit dea7858
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 52 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Changed

- Rename structs related to 3D sprites with lowercase "3d" to better match Bevy
- Rename AnimationRepeat::Cycles to AnimationRepeat::Times

## 0.3.0 - 2024-08-26

Expand Down
2 changes: 1 addition & 1 deletion examples/composition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn setup(
.add_stage(run_clip_id.into())
.add_stage(shoot_clip_id.into())
// Let's repeat it some times and then stop
.set_repeat(AnimationRepeat::Cycles(2));
.set_repeat(AnimationRepeat::Times(2));
});

// Spawn a sprite that uses the animation
Expand Down
4 changes: 2 additions & 2 deletions examples/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ fn setup(
(Some(AnimationDuration::PerCycle(2000)), None, None, None),
(Some(AnimationDuration::PerCycle(100)), None, None, None),
// Repeat
(None, Some(AnimationRepeat::Cycles(10)), None, None),
(None, Some(AnimationRepeat::Cycles(100)), None, None),
(None, Some(AnimationRepeat::Times(10)), None, None),
(None, Some(AnimationRepeat::Times(100)), None, None),
(None, Some(AnimationRepeat::Loop), None, None),
// Direction
(None, None, Some(AnimationDirection::Forwards), None),
Expand Down
4 changes: 2 additions & 2 deletions src/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub enum AnimationRepeat {
/// Loops indefinitely
Loop,
/// Repeats a fixed number of times
Cycles(u32),
Times(u32),
}

impl Default for AnimationRepeat {
Expand Down Expand Up @@ -97,7 +97,7 @@ impl Default for AnimationDirection {
/// animation
/// .add_stage(stage1)
/// .add_stage(stage2)
/// .set_repeat(AnimationRepeat::Cycles(5));
/// .set_repeat(AnimationRepeat::Times(5));
/// });
/// ```
#[derive(Debug, Clone)]
Expand Down
68 changes: 34 additions & 34 deletions src/animator/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ pub(super) struct AnimationCache {
/// All the frames
pub frames: Vec<AnimationFrame>,

/// Frames for odd cycles when the direction is PingPong, None for other directions
/// Frames for odd repetitions when the direction is PingPong, None for other directions
pub frames_pong: Option<Vec<AnimationFrame>>,

// The total number of cycles to play.
// The total number of repetitions to play.
// None if infinite.
pub cycle_count: Option<u32>,
pub repetitions: Option<u32>,

// The direction of the animation to handle a special case for PingPong
pub animation_direction: AnimationDirection,
Expand All @@ -78,11 +78,11 @@ impl AnimationCache {

let animation_repeat = animation.repeat().unwrap_or_default();

if matches!(animation_repeat, AnimationRepeat::Cycles(0)) {
if matches!(animation_repeat, AnimationRepeat::Times(0)) {
return Self {
frames: Vec::new(),
frames_pong: None,
cycle_count: None,
repetitions: None,
animation_direction,
};
}
Expand Down Expand Up @@ -186,23 +186,23 @@ impl AnimationCache {
return Self {
frames: Vec::new(),
frames_pong: None,
cycle_count: None,
repetitions: None,
animation_direction,
};
}

// Generate all the frames that make up one full cycle of the animation
//
// Level 1: stages
// Level 2: cycles
// Level 2: repetitions
// Level 3: frames
//
// This nested structure is not ideal to work with but it's convenient as it preserves the clip boundaries
// that we need to inject events at the appropriate frames

let mut all_cycles: Vec<Vec<Vec<AnimationFrame>>> = Vec::new();
let mut all_repetitions: Vec<Vec<Vec<AnimationFrame>>> = Vec::new();

let mut all_cycles_pong = None;
let mut all_repetitions_pong = None;

for (
stage_index,
Expand Down Expand Up @@ -277,73 +277,73 @@ impl AnimationCache {
},
);

// Repeat/reverse the cycle for all the cycles of the current stage
// Repeat/reverse the cycle for all the repetitions of the current stage

let mut stage_cycles = Vec::new();
let mut stage_repetitions = Vec::new();

for cycle_index in 0..stage_repeat {
stage_cycles.push(match stage_direction {
stage_repetitions.push(match stage_direction {
AnimationDirection::Forwards => one_cycle.clone().collect_vec(),
AnimationDirection::Backwards => one_cycle.clone().rev().collect_vec(),
AnimationDirection::PingPong => {
// First cycle: use all the frames
if cycle_index == 0 {
one_cycle.clone().collect_vec()
}
// Following odd cycles, use all the frames but the first one, and reversed
// Following odd repetitions, use all the frames but the first one, and reversed
else if cycle_index % 2 == 1 {
one_cycle.clone().rev().skip(1).collect_vec()
}
// Even cycles: use all the frames but the first one
// Even repetitions: use all the frames but the first one
else {
one_cycle.clone().skip(1).collect_vec()
}
}
});
}

all_cycles.push(stage_cycles);
all_repetitions.push(stage_repetitions);
}

// Filter out empty stages/cycles/frames
// Filter out empty stages/repetitions/frames
//
// Removing them does not change the nature of the animation and simplifies the playback code since
// we won't have to consider this special case.
//
// This must be done before attaching events or we might lose some of them!

for stage in &mut all_cycles {
for stage in &mut all_repetitions {
for cycle in &mut *stage {
cycle.retain(|frame| frame.duration > 0);
}

stage.retain(|cycle| cycle.len() > 0);
}

all_cycles.retain(|stage| stage.len() > 0);
all_repetitions.retain(|stage| stage.len() > 0);

// Order/reverse the cycles to match the animation direction if needed
// Order/reverse the repetitions to match the animation direction if needed

let reverse = |all_cycles: &mut Vec<Vec<Vec<AnimationFrame>>>| {
for stage in &mut *all_cycles {
let reverse = |all_repetitions: &mut Vec<Vec<Vec<AnimationFrame>>>| {
for stage in &mut *all_repetitions {
for cycle in &mut *stage {
cycle.reverse();
}

stage.reverse();
}

all_cycles.reverse();
all_repetitions.reverse();
};

match animation_direction {
// Backwards: reverse all the frames
AnimationDirection::Backwards => reverse(&mut all_cycles),
AnimationDirection::Backwards => reverse(&mut all_repetitions),

// PingPong: reverse all the frame in the alternate "pong" collection
AnimationDirection::PingPong => {
all_cycles_pong = Some(all_cycles.clone());
reverse(all_cycles_pong.as_mut().unwrap())
all_repetitions_pong = Some(all_repetitions.clone());
reverse(all_repetitions_pong.as_mut().unwrap())
}

// Forwards: nothing to do
Expand All @@ -352,20 +352,20 @@ impl AnimationCache {

// Merge the nested frames into a single sequence

let merge_cycles = |cycles: &mut Vec<Vec<Vec<AnimationFrame>>>| {
let merge_repetitions = |repetitions: &mut Vec<Vec<Vec<AnimationFrame>>>| {
let mut all_frames = Vec::new();

// Inject events at clip/clip cycle boundaries

let mut previous_stage_stage_index = None;
let mut previous_cycle_stage_index = None;

for stage in &mut *cycles {
for stage in &mut *repetitions {
for cycle in &mut *stage {
// Inject a ClipCycleEnd event on the first frame of each cycle after the first one

if let Some(stage_index) = previous_cycle_stage_index {
// At this point, we can safely access [0] as empty cycles have been filtered out
// At this point, we can safely access [0] as empty repetitions have been filtered out

cycle[0].events.push(AnimationFrameEvent::ClipCycleEnd {
stage_index,
Expand Down Expand Up @@ -401,7 +401,7 @@ impl AnimationCache {

// Merge the nested frames into a single sequence

for stage in cycles {
for stage in repetitions {
let mut stage_frames = Vec::new();

for cycle in stage {
Expand All @@ -427,10 +427,10 @@ impl AnimationCache {
all_frames
};

let all_frames = merge_cycles(&mut all_cycles);
let all_frames = merge_repetitions(&mut all_repetitions);

let all_frames_pong = if let Some(cycles) = &mut all_cycles_pong {
Some(merge_cycles(cycles))
let all_frames_pong = if let Some(repetitions) = &mut all_repetitions_pong {
Some(merge_repetitions(repetitions))
} else {
None
};
Expand All @@ -441,15 +441,15 @@ impl AnimationCache {

let cycle_count = match animation_repeat {
AnimationRepeat::Loop => None,
AnimationRepeat::Cycles(n) => Some(n),
AnimationRepeat::Times(n) => Some(n),
};

// Done!

Self {
frames: all_frames,
frames_pong: all_frames_pong,
cycle_count,
repetitions: cycle_count,
animation_direction,
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/animator/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl Iterator for AnimationIterator {
if self.current_animation_cycle_index % 2 == 0 {
&self.cache.frames
} else {
// PingPong + odd cycles
// PingPong + odd repetitions
frames_pong
}
} else {
Expand Down Expand Up @@ -94,7 +94,7 @@ impl Iterator for AnimationIterator {

if self
.cache
.cycle_count
.repetitions
.map(|cycle_count| self.current_animation_cycle_index < cycle_count as usize)
.unwrap_or(true)
{
Expand Down
4 changes: 2 additions & 2 deletions tests/direction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn stage_backwards() {
animation
.add_stage(stage)
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(2));
.set_repeat(AnimationRepeat::Times(2));
});

ctx.add_animation_to_sprite(animation_id);
Expand Down Expand Up @@ -69,7 +69,7 @@ fn animation_backwards() {
.add_stage(stage)
.set_direction(AnimationDirection::Backwards)
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(2));
.set_repeat(AnimationRepeat::Times(2));
});

ctx.add_animation_to_sprite(animation_id);
Expand Down
18 changes: 9 additions & 9 deletions tests/repeat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn clip_zero() {
animation
.add_stage(clip_id.into())
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(1));
.set_repeat(AnimationRepeat::Times(1));
});

ctx.add_animation_to_sprite(animation_id);
Expand All @@ -38,7 +38,7 @@ fn clip_once() {
animation
.add_stage(clip_id.into())
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(1));
.set_repeat(AnimationRepeat::Times(1));
});

ctx.add_animation_to_sprite(animation_id);
Expand Down Expand Up @@ -80,12 +80,12 @@ fn clip_many() {
animation
.add_stage(clip_id.into())
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(1));
.set_repeat(AnimationRepeat::Times(1));
});

ctx.add_animation_to_sprite(animation_id);

// 9 cycles
// 9 repetitions

ctx.run(50);
ctx.check(0, []);
Expand Down Expand Up @@ -144,7 +144,7 @@ fn some_clips_repeated_zero_times() {
.add_stage(zero_clip_id.into())
.add_stage(zero_clip_id.into())
.set_duration(AnimationDuration::PerFrame(110))
.set_repeat(AnimationRepeat::Cycles(1));
.set_repeat(AnimationRepeat::Times(1));
});

ctx.add_animation_to_sprite(animation_id);
Expand Down Expand Up @@ -193,7 +193,7 @@ fn animation_zero() {

animation
.add_stage(stage)
.set_repeat(AnimationRepeat::Cycles(0));
.set_repeat(AnimationRepeat::Times(0));
});

ctx.add_animation_to_sprite(animation_id);
Expand All @@ -216,7 +216,7 @@ fn animation_once() {
animation
.add_stage(clip_id.into())
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(1));
.set_repeat(AnimationRepeat::Times(1));
});

ctx.add_animation_to_sprite(animation_id);
Expand Down Expand Up @@ -258,12 +258,12 @@ fn animation_many() {
animation
.add_stage(clip_id.into())
.set_duration(AnimationDuration::PerFrame(100))
.set_repeat(AnimationRepeat::Cycles(10));
.set_repeat(AnimationRepeat::Times(10));
});

ctx.add_animation_to_sprite(animation_id);

// 9 cycles
// 9 repetitions

ctx.run(50);
ctx.check(0, []);
Expand Down

0 comments on commit dea7858

Please sign in to comment.