Skip to content

Commit

Permalink
Count number of times a repeating Timer wraps around in a tick (bevye…
Browse files Browse the repository at this point in the history
…ngine#1112)

Added just_finished_count() function
  • Loading branch information
reidbhuntley authored and rparrett committed Jan 27, 2021
1 parent 43135e5 commit 82a9150
Showing 1 changed file with 36 additions and 11 deletions.
47 changes: 36 additions & 11 deletions crates/bevy_core/src/time/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -84,16 +86,28 @@ 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]
pub fn repeating(&self) -> bool {
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
}

Expand All @@ -102,28 +116,32 @@ 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
}

#[inline]
pub fn reset(&mut self) {
self.finished = false;
self.just_finished = false;
self.just_finished_count = 0;
self.elapsed = 0.0;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -170,13 +190,15 @@ 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
t.tick(1.0);
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);
}
Expand All @@ -190,21 +212,24 @@ 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
t.tick(1.0);
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);
}
Expand Down

0 comments on commit 82a9150

Please sign in to comment.