Count number of times a repeating Timer wraps around in a tick (#1112)

Added just_finished_count() function
This commit is contained in:
reidbhuntley 2021-01-19 17:41:37 -05:00 committed by GitHub
parent 1e8060a5a2
commit ac7d2de67c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -13,8 +13,8 @@ pub struct Timer {
elapsed: f32,
duration: f32,
finished: bool,
/// Will only be true on the tick `duration` is reached or exceeded.
just_finished: bool,
/// Will only be non-zero on the tick `duration` is reached or exceeded.
just_finished_count: u32,
paused: bool,
repeating: bool,
}
@ -51,7 +51,8 @@ impl Timer {
self.paused
}
/// Returns the time elapsed on the timer. Guaranteed to be between 0.0 and `duration`, inclusive.
/// Returns the time elapsed on the timer. Guaranteed to be between 0.0 and `duration`.
/// Will only equal `duration` when the timer is finished and non repeating.
#[inline]
pub fn elapsed(&self) -> f32 {
self.elapsed
@ -74,8 +75,9 @@ impl Timer {
/// Returns the finished state of the timer.
///
/// 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.
/// 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, so in that case
/// this function is equivalent to `just_finished`.
#[inline]
pub fn finished(&self) -> bool {
self.finished
@ -84,7 +86,16 @@ impl Timer {
/// Will only be true on the tick the timer's duration is reached or exceeded.
#[inline]
pub fn just_finished(&self) -> bool {
self.just_finished
self.just_finished_count > 0
}
/// Returns the total number of times the timer finished during this tick.
///
/// This value can be used to ensure no completions of a repeating timer are skipped over due to a tick with an unexpectedly
/// long delta time. For non repeating timers, the value will only ever be 0 or 1.
#[inline]
pub fn just_finished_count(&self) -> u32 {
self.just_finished_count
}
#[inline]
@ -92,8 +103,11 @@ impl Timer {
self.repeating
}
#[inline]
pub fn set_repeating(&mut self, repeating: bool) {
if !self.repeating && repeating && self.finished {
self.elapsed = 0.0;
self.finished = self.just_finished();
}
self.repeating = repeating
}
@ -102,20 +116,24 @@ impl Timer {
if self.paused {
return self;
}
let prev_finished = self.finished;
self.elapsed += delta;
self.finished = self.elapsed >= self.duration;
self.just_finished = !prev_finished && self.finished;
if self.finished {
if self.repeating {
// Count the number of times the timer will wrap around from this tick
self.just_finished_count = (self.elapsed / self.duration) as u32;
// Repeating timers wrap around
self.elapsed %= self.duration;
} else {
self.just_finished_count = if prev_finished { 0 } else { 1 };
// Non-repeating timers clamp to duration
self.elapsed = self.duration;
}
} else {
self.just_finished_count = 0;
}
self
}
@ -123,7 +141,7 @@ impl Timer {
#[inline]
pub fn reset(&mut self) {
self.finished = false;
self.just_finished = false;
self.just_finished_count = 0;
self.elapsed = 0.0;
}
@ -151,6 +169,7 @@ mod tests {
assert_eq!(t.duration(), 10.0);
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.repeating(), false);
assert_eq!(t.percent(), 0.025);
assert_eq!(t.percent_left(), 0.975);
@ -161,6 +180,7 @@ mod tests {
assert_eq!(t.duration(), 10.0);
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.repeating(), false);
assert_eq!(t.percent(), 0.025);
assert_eq!(t.percent_left(), 0.975);
@ -170,6 +190,7 @@ mod tests {
assert_eq!(t.elapsed(), 10.0);
assert_eq!(t.finished(), true);
assert_eq!(t.just_finished(), true);
assert_eq!(t.just_finished_count(), 1);
assert_eq!(t.percent(), 1.0);
assert_eq!(t.percent_left(), 0.0);
// Continuing to tick when finished should only change just_finished
@ -177,6 +198,7 @@ mod tests {
assert_eq!(t.elapsed(), 10.0);
assert_eq!(t.finished(), true);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.percent(), 1.0);
assert_eq!(t.percent_left(), 0.0);
}
@ -190,14 +212,16 @@ mod tests {
assert_eq!(t.duration(), 2.0);
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.repeating(), true);
assert_eq!(t.percent(), 0.375);
assert_eq!(t.percent_left(), 0.625);
// Tick past the end and make sure elapsed wraps
t.tick(1.5);
t.tick(3.5);
assert_eq!(t.elapsed(), 0.25);
assert_eq!(t.finished(), true);
assert_eq!(t.just_finished(), true);
assert_eq!(t.just_finished_count(), 2);
assert_eq!(t.percent(), 0.125);
assert_eq!(t.percent_left(), 0.875);
// Continuing to tick should turn off both finished & just_finished for repeating timers
@ -205,6 +229,7 @@ mod tests {
assert_eq!(t.elapsed(), 1.25);
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.percent(), 0.625);
assert_eq!(t.percent_left(), 0.375);
}