use std::time::Duration;
use bevy_core::Time;
use bevy_ecs::prelude::*;
pub struct FixedTimestepInfo {
step: Duration,
accumulator: Duration,
}
impl FixedTimestepInfo {
pub fn timestep(&self) -> Duration {
self.step
}
pub fn rate(&self) -> f64 {
1.0 / self.step.as_secs_f64()
}
pub fn remaining(&self) -> Duration {
self.accumulator
}
pub fn overstep(&self) -> f64 {
self.accumulator.as_secs_f64() / self.step.as_secs_f64()
}
}
pub struct FixedTimestepStage {
step: Duration,
accumulator: Duration,
stages: Vec<Box<dyn Stage>>,
}
impl FixedTimestepStage {
pub fn from_stage<S: Stage>(timestep: Duration, stage: S) -> Self {
Self {
step: timestep,
accumulator: Duration::default(),
stages: vec![Box::new(stage)],
}
}
pub fn new(timestep: Duration) -> Self {
Self {
step: timestep,
accumulator: Duration::default(),
stages: Vec::new(),
}
}
pub fn add_stage<S: Stage>(&mut self, stage: S) {
self.stages.push(Box::new(stage));
}
pub fn with_stage<S: Stage>(mut self, stage: S) -> Self {
self.add_stage(stage);
self
}
}
impl Stage for FixedTimestepStage {
fn run(&mut self, world: &mut World) {
self.accumulator += {
let time = world.get_resource::<Time>();
if let Some(time) = time {
time.delta()
} else {
return;
}
};
while self.accumulator >= self.step {
self.accumulator -= self.step;
for stage in self.stages.iter_mut() {
world.insert_resource(FixedTimestepInfo {
step: self.step,
accumulator: self.accumulator,
});
stage.run(world);
world.remove_resource::<FixedTimestepInfo>();
}
}
}
}