pub struct FixedUpdateRunner {
dt_accumulator: f64,
fixed_dt: f64,
}
impl FixedUpdateRunner {
pub fn new(fixed_dt: f64) -> Self {
Self {
dt_accumulator: 0.0,
fixed_dt,
}
}
pub fn new_from_rate_per_second(rate: f64) -> Self {
Self {
dt_accumulator: 0.0,
fixed_dt: 1.0 / rate,
}
}
pub fn fuel(&mut self, dt: f64) {
self.dt_accumulator += dt;
}
pub fn has_gas(&self) -> bool {
self.dt_accumulator >= self.fixed_dt
}
pub fn consume(&mut self) {
self.dt_accumulator -= self.fixed_dt;
}
pub fn available_ticks(&self) -> u64 {
(self.dt_accumulator / self.fixed_dt).floor() as u64
}
pub fn fixed_dt(&self) -> f64 {
self.fixed_dt
}
pub fn set_fixed_dt(&mut self, fixed_dt: f64) {
self.fixed_dt = fixed_dt;
}
}
#[cfg(test)]
mod tests {
use std::io::{repeat, Read};
use std::iter::repeat_n;
use super::*;
#[test]
fn test_fixed_update_runner() {
let mut runner = FixedUpdateRunner::new_from_rate_per_second(60.0);
let mut real_frames = vec![1.0/120.0; 120];
real_frames.push(1.0);
let mut fixed_update_calls = vec![];
for (i, dt) in real_frames.iter().enumerate() {
runner.fuel(*dt);
while runner.has_gas() {
runner.consume();
fixed_update_calls.push(i);
}
}
let mut expected_calls = (0..60).map(|x| x * 2 + 1).collect::<Vec<_>>();
expected_calls.extend(repeat_n(120, 59));
assert_eq!(fixed_update_calls, expected_calls);
assert_eq!(runner.available_ticks(), 0);
runner.fuel(0.5);
assert_eq!(runner.available_ticks(), (0.5 / (1.0 / 60.0)) as u64);
}
}