use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Time {
delta_time: Duration,
delta_real_time: Duration,
fixed_time: Duration,
frame_number: u64,
absolute_real_time: Duration,
absolute_time: Duration,
time_scale: f32,
fixed_time_accumulator: Duration,
}
impl Time {
pub fn delta_time(&self) -> Duration {
self.delta_time
}
pub fn delta_real_time(&self) -> Duration {
self.delta_real_time
}
pub fn fixed_time(&self) -> Duration {
self.fixed_time
}
pub fn frame_number(&self) -> u64 {
self.frame_number
}
pub fn absolute_time(&self) -> Duration {
self.absolute_time
}
pub fn absolute_real_time(&self) -> Duration {
self.absolute_real_time
}
pub fn time_scale(&self) -> f32 {
self.time_scale
}
pub fn advance_frame(&mut self, time_diff: Duration) {
self.delta_time = time_diff.clone().mul_f32(self.time_scale);
self.delta_real_time = time_diff;
self.frame_number += 1;
self.absolute_time += self.delta_time;
self.absolute_real_time += self.delta_real_time;
self.fixed_time_accumulator += self.delta_real_time;
}
pub fn set_fixed_time(&mut self, time: Duration) {
self.fixed_time = time;
}
pub fn set_time_scale(&mut self, multiplier: f32) {
assert!(multiplier >= 0.0);
assert!(multiplier != std::f32::INFINITY);
self.time_scale = multiplier;
}
pub fn step_fixed_update(&mut self) -> bool {
if self.fixed_time_accumulator >= self.fixed_time {
self.fixed_time_accumulator -= self.fixed_time;
true
} else {
false
}
}
}
impl Default for Time {
fn default() -> Time {
Time {
delta_time: Duration::from_secs(0),
delta_real_time: Duration::from_secs(0),
fixed_time: Duration::new(0, 16_666_666),
fixed_time_accumulator: Duration::new(0, 0),
frame_number: 0,
absolute_real_time: Duration::default(),
absolute_time: Duration::default(),
time_scale: 1.0,
}
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn fixed_update_120fps() {
let mut time = Time::default();
time.set_fixed_time(Duration::from_secs_f64(1.0 / 120.0));
time.set_time_scale(10.0);
let step = 1.0 / 60.0;
let mut fixed_count = 0;
for _ in 0..60 {
time.advance_frame(Duration::from_secs_f64(step));
while time.step_fixed_update() {
fixed_count += 1;
}
}
assert_eq!(fixed_count, 120);
}
#[test]
fn fixed_update_1sec() {
let mut time = Time::default();
time.set_fixed_time(Duration::from_secs_f64(1.0));
let step = 1.0 / 60.0;
let mut fixed_count = 0;
for _ in 0..130 {
time.advance_frame(Duration::from_secs_f64(step));
while time.step_fixed_update() {
fixed_count += 1;
}
}
assert_eq!(fixed_count, 2);
}
#[test]
fn all_getters() {
use std::time::Duration;
let mut time = Time::default();
time.set_time_scale(2.0);
time.set_fixed_time(Duration::from_secs_f64(1.0 / 120.0));
let step = 1.0 / 60.0;
time.advance_frame(Duration::from_secs_f64(step));
assert_eq!(time.time_scale(), 2.0);
assert!(approx_zero(time.delta_time().as_secs_f64() - step * 2.0));
assert!(approx_zero(time.delta_real_time().as_secs_f64() - step));
assert!(approx_zero(time.absolute_time().as_secs_f64() - step * 2.0));
assert!(approx_zero(time.absolute_real_time().as_secs_f64() - step));
assert_eq!(time.frame_number(), 1);
assert_eq!(time.time_scale(), 2.0);
assert_eq!(time.fixed_time(), Duration::from_secs_f64(1.0 / 120.0));
time.advance_frame(Duration::from_secs_f64(step));
assert_eq!(time.time_scale(), 2.0);
assert!(approx_zero(time.delta_time().as_secs_f64() - step * 2.0));
assert!(approx_zero(time.delta_real_time().as_secs_f64() - step));
assert!(approx_zero(time.absolute_time().as_secs_f64() - step * 4.0));
assert!(approx_zero(
time.absolute_real_time().as_secs_f64() - step * 2.0
));
assert_eq!(time.frame_number(), 2);
assert_eq!(time.time_scale(), 2.0);
assert_eq!(time.fixed_time(), Duration::from_secs_f64(1.0 / 120.0));
}
fn approx_zero(v: f64) -> bool {
v >= -0.000001 && v <= 0.000001
}
}