#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::time::Instant;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub struct Timer {
remaining: f64,
reset: f64,
looping: bool,
}
impl Timer {
pub fn new_with_delay(delay: f64, duration: f64) -> Self {
Self {
remaining: delay,
reset: duration,
looping: true,
}
}
pub fn new(duration: f64) -> Self {
Self {
remaining: 0.0,
reset: duration,
looping: true,
}
}
pub fn new_once(after: f64) -> Self {
Self {
remaining: after,
reset: after,
looping: false,
}
}
}
impl Timer {
#[inline]
pub fn update(&mut self, timing: &Timing) -> bool {
self.update_secs(timing.fixed_time_step)
}
pub fn update_secs(&mut self, delta: f64) -> bool {
self.remaining -= delta;
let triggered = self.remaining <= 0.0;
if triggered && self.looping {
self.remaining = self.reset;
}
triggered
}
#[inline]
pub fn reset(&mut self) {
self.remaining = self.reset;
}
#[inline]
pub fn has_triggered(&self) -> bool {
self.remaining <= 0.0
}
#[inline]
pub fn trigger(&mut self) {
self.remaining = 0.0;
}
#[inline]
pub fn delay(&mut self, seconds: f64) {
self.remaining += seconds;
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Timing {
pub delta: f64,
pub started_at: Instant,
pub now: Instant,
pub last: Instant,
pub updates: usize,
pub renders: usize,
pub accumulated_time: f64,
max_render_time: f64,
pub fixed_time_step: f64,
pub fixed_time_step_f32: f32,
pub stats: Stats,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Stats {
pub fps: usize,
pub last_frame_count: usize,
pub last_frame_check: Instant,
}
impl Timing {
pub fn new(speed: usize) -> Timing {
Timing {
delta: 0.0,
started_at: Instant::now(),
now: Instant::now(),
last: Instant::now(),
updates: 0,
renders: 0,
accumulated_time: 0.0,
max_render_time: 0.1,
fixed_time_step: 1.0 / (speed as f64),
fixed_time_step_f32: 1.0 / (speed as f32),
stats: Stats {
fps: 0,
last_frame_count: 0,
last_frame_check: Instant::now(),
},
}
}
pub fn update_fps(&mut self) {
if self
.now
.duration_since(self.stats.last_frame_check)
.as_secs_f32()
>= 1.0
{
self.stats.fps = self.renders - self.stats.last_frame_count;
self.stats.last_frame_check = self.now;
self.stats.last_frame_count = self.renders;
}
}
pub fn update(&mut self) {
self.now = Instant::now();
self.delta = self.now.duration_since(self.last).as_secs_f64();
self.accumulated_time += self.delta;
if self.delta > self.max_render_time {
self.delta = self.max_render_time;
}
}
}
#[cfg(test)]
mod test {
use crate::timing::Timer;
#[test]
fn basic_test_delayed() {
let mut timer = Timer::new_with_delay(1.0, 1.0);
assert!(!timer.update_secs(0.4));
assert!(!timer.update_secs(0.4));
assert!(timer.update_secs(0.4));
assert!(!timer.has_triggered());
}
#[test]
fn basic_test() {
let mut timer = Timer::new(0.5);
assert!(timer.has_triggered());
timer.reset();
assert!(!timer.has_triggered());
assert!(!timer.update_secs(0.4));
assert!(timer.update_secs(0.4));
assert!(!timer.has_triggered());
}
}