use crate::engine::animation::base::{Animation, AudioEvent};
use std::time::Duration;
const INFINITE_DURATION_CAP: Duration = Duration::from_secs(3600);
pub struct LoopAnim {
pub(crate) factory: Box<dyn Fn() -> Box<dyn Animation> + Send + Sync>,
pub(crate) current: Box<dyn Animation>,
pub(crate) repeat_count: Option<usize>,
pub(crate) finished_count: usize,
}
impl LoopAnim {
pub fn new(
factory: Box<dyn Fn() -> Box<dyn Animation> + Send + Sync>,
count: Option<usize>,
) -> Self {
let current = factory();
Self {
factory,
current,
repeat_count: count,
finished_count: 0,
}
}
}
impl Animation for LoopAnim {
fn update(&mut self, mut dt: Duration) -> (bool, Duration) {
loop {
let (finished, leftover) = self.current.update(dt);
if !finished {
return (false, Duration::ZERO);
}
self.finished_count += 1;
if let Some(max) = self.repeat_count {
if self.finished_count >= max {
return (true, leftover);
}
}
self.current = (self.factory)();
dt = leftover;
if dt == Duration::ZERO {
return (false, Duration::ZERO);
}
}
}
fn duration(&self) -> Duration {
match self.repeat_count {
Some(count) => self.current.duration() * count as u32,
None => INFINITE_DURATION_CAP,
}
}
fn collect_audio_events(&mut self, current_time: Duration, events: &mut Vec<AudioEvent>) {
self.current.collect_audio_events(current_time, events);
}
}
pub fn loop_anim<F>(factory: F, count: Option<usize>) -> Box<dyn Animation>
where
F: Fn() -> Box<dyn Animation> + Send + Sync + 'static,
{
Box::new(LoopAnim::new(Box::new(factory), count))
}