use crate::engine::animation::base::{Animation, AudioEvent};
use std::time::Duration;
pub struct Sequence {
pub(crate) items: Vec<(Duration, Box<dyn Animation>)>,
pub(crate) finished: Vec<bool>,
pub(crate) elapsed: Duration,
}
impl Sequence {
pub fn new(stagger: Duration, animations: Vec<Box<dyn Animation>>) -> Self {
let len = animations.len();
let items = animations
.into_iter()
.enumerate()
.map(|(i, anim)| (stagger * i as u32, anim))
.collect();
Self {
items,
finished: vec![false; len],
elapsed: Duration::ZERO,
}
}
}
impl Animation for Sequence {
fn update(&mut self, dt: Duration) -> (bool, Duration) {
self.elapsed += dt;
let mut all_finished = true;
let mut min_leftover = dt;
for (i, (start_time, anim)) in self.items.iter_mut().enumerate() {
if self.finished[i] {
continue;
}
if self.elapsed < *start_time {
all_finished = false;
continue;
}
let time_since_start = self.elapsed.saturating_sub(*start_time);
if time_since_start == Duration::ZERO {
all_finished = false;
continue;
}
let item_dt = if time_since_start < dt {
time_since_start
} else {
dt
};
let (finished, leftover) = anim.update(item_dt);
if !finished {
all_finished = false;
continue;
}
self.finished[i] = true;
min_leftover = min_leftover.min(leftover);
}
let total_finished = all_finished && self.elapsed >= self.duration();
let final_leftover = if total_finished {
self.elapsed.saturating_sub(self.duration())
} else {
Duration::ZERO
};
(total_finished, final_leftover)
}
fn duration(&self) -> Duration {
self.items
.iter()
.map(|(start, anim)| *start + anim.duration())
.max()
.unwrap_or(Duration::ZERO)
}
fn set_easing(&mut self, easing: fn(f32) -> f32) {
for (_, anim) in &mut self.items {
anim.set_easing(easing);
}
}
fn collect_audio_events(&mut self, current_time: Duration, events: &mut Vec<AudioEvent>) {
for (start, anim) in &mut self.items {
if self.elapsed >= *start {
anim.collect_audio_events(current_time, events);
}
}
}
fn reset(&mut self) {
for (_, anim) in &mut self.items {
anim.reset();
}
for f in &mut self.finished {
*f = false;
}
self.elapsed = Duration::ZERO;
}
}
pub fn sequence(stagger: Duration, animations: Vec<Box<dyn Animation>>) -> Box<dyn Animation> {
Box::new(Sequence::new(stagger, animations))
}