From 1feeb70176698981e891bf6fe68f29b4098de5a4 Mon Sep 17 00:00:00 2001 From: 8bit-pudding <69628967+8bit-pudding@users.noreply.github.com> Date: Thu, 13 Aug 2020 13:29:19 +0200 Subject: [PATCH] Add repeating flag to Timer Repeating timers will reset themselves upon finishing, carrying over any excess time during the last tick. This fixes timer drift upon resetting. --- crates/bevy_core/src/time/timer.rs | 29 +++++++++++++++---- .../src/print_diagnostics_plugin.rs | 6 +--- examples/2d/sprite_sheet.rs | 3 +- examples/app/plugin.rs | 3 +- examples/ecs/event.rs | 4 +-- examples/ui/font_atlas_debug.rs | 2 +- 6 files changed, 29 insertions(+), 18 deletions(-) diff --git a/crates/bevy_core/src/time/timer.rs b/crates/bevy_core/src/time/timer.rs index 7322118e0558e6..dd95b2232299ec 100644 --- a/crates/bevy_core/src/time/timer.rs +++ b/crates/bevy_core/src/time/timer.rs @@ -4,32 +4,46 @@ use bevy_property::Properties; use std::time::Duration; /// Tracks elapsed time. Enters the finished state once `duration` is reached. +/// +/// Non repeating timers will stop tracking and stay in the finished state until reset. +/// Repeating timers will only be in the finished state on each tick `duration` is reached or exceeded, and can still be reset at any given point. #[derive(Clone, Debug, Default, Properties)] pub struct Timer { pub elapsed: f32, pub duration: f32, pub finished: bool, + /// Stores the last tick's finished state. Is checked against in just_finished. + prev_finished: bool, + pub repeating: bool, } impl Timer { - pub fn new(duration: Duration) -> Self { + pub fn new(duration: Duration, repeating: bool) -> Self { Timer { duration: duration.as_secs_f32(), + repeating, ..Default::default() } } - pub fn from_seconds(seconds: f32) -> Self { + pub fn from_seconds(seconds: f32, repeating: bool) -> Self { Timer { duration: seconds, + repeating, ..Default::default() } } pub fn tick(&mut self, delta: f32) { - self.elapsed = (self.elapsed + delta).min(self.duration); - if self.elapsed >= self.duration { - self.finished = true; + if self.elapsed < self.duration { + self.elapsed += delta; + } + + self.prev_finished = self.finished; + self.finished = self.elapsed >= self.duration; + + if self.repeating && self.finished { + self.elapsed = self.elapsed % self.duration; } } @@ -37,6 +51,11 @@ impl Timer { self.finished = false; self.elapsed = 0.0; } + + /// Returns true only on the exact tick elapsed time first exceeds duration. + pub fn just_finished(&self) -> bool { + (!self.prev_finished || self.repeating) && self.finished + } } pub(crate) fn timer_system(time: Res