Skip to content

Commit

Permalink
add TimerMode, replace repeating: bool
Browse files Browse the repository at this point in the history
As mentioned in #2926, it's better to have an explicit type that clearly
communicates the intent of the timer mode rather than an opaque boolean,
which can be only understood when knowing the signature or reading the
documentation.

Signed-off-by: Lena Milizé <me@lvmn.org>
  • Loading branch information
lovelymono committed Oct 13, 2022
1 parent 000e6e2 commit 5a58300
Show file tree
Hide file tree
Showing 17 changed files with 90 additions and 58 deletions.
4 changes: 2 additions & 2 deletions crates/bevy_diagnostic/src/log_diagnostics_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{Diagnostic, DiagnosticId, Diagnostics};
use bevy_app::prelude::*;
use bevy_ecs::system::{Res, ResMut, Resource};
use bevy_log::{debug, info};
use bevy_time::{Time, Timer};
use bevy_time::{Time, Timer, TimerMode};
use bevy_utils::Duration;

/// An App Plugin that logs diagnostics to the console
Expand Down Expand Up @@ -32,7 +32,7 @@ impl Default for LogDiagnosticsPlugin {
impl Plugin for LogDiagnosticsPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(LogDiagnosticsState {
timer: Timer::new(self.wait_duration, true),
timer: Timer::new(self.wait_duration, TimerMode::Repeating),
filter: self.filter.clone(),
});

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_time/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crossbeam_channel::{Receiver, Sender};
pub mod prelude {
//! The Bevy Time Prelude.
#[doc(hidden)]
pub use crate::{Time, Timer};
pub use crate::{Time, Timer, TimerMode};
}

use bevy_app::prelude::*;
Expand Down
96 changes: 61 additions & 35 deletions crates/bevy_time/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use bevy_utils::Duration;
pub struct Timer {
stopwatch: Stopwatch,
duration: Duration,
repeating: bool,
mode: TimerMode,
finished: bool,
times_finished_this_tick: u32,
}
Expand All @@ -23,10 +23,10 @@ impl Timer {
/// Creates a new timer with a given duration.
///
/// See also [`Timer::from_seconds`](Timer::from_seconds).
pub fn new(duration: Duration, repeating: bool) -> Self {
pub fn new(duration: Duration, mode: TimerMode) -> Self {
Self {
duration,
repeating,
mode,
..Default::default()
}
}
Expand All @@ -36,12 +36,12 @@ impl Timer {
/// # Example
/// ```
/// # use bevy_time::*;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// ```
pub fn from_seconds(duration: f32, repeating: bool) -> Self {
pub fn from_seconds(duration: f32, mode: TimerMode) -> Self {
Self {
duration: Duration::from_secs_f32(duration),
repeating,
mode,
..Default::default()
}
}
Expand All @@ -52,7 +52,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(1.5));
/// assert!(timer.finished());
/// timer.tick(Duration::from_secs_f32(0.5));
Expand All @@ -69,7 +69,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(1.5));
/// assert!(timer.just_finished());
/// timer.tick(Duration::from_secs_f32(0.5));
Expand All @@ -89,7 +89,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.elapsed(), Duration::from_secs_f32(0.5));
/// ```
Expand All @@ -113,7 +113,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.set_elapsed(Duration::from_secs(2));
/// assert_eq!(timer.elapsed(), Duration::from_secs(2));
/// // the timer is not finished even if the elapsed time is greater than the duration.
Expand All @@ -130,7 +130,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let timer = Timer::new(Duration::from_secs(1), false);
/// let timer = Timer::new(Duration::from_secs(1), TimerMode::Once);
/// assert_eq!(timer.duration(), Duration::from_secs(1));
/// ```
#[inline]
Expand All @@ -144,7 +144,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.5, false);
/// let mut timer = Timer::from_seconds(1.5, TimerMode::Once);
/// timer.set_duration(Duration::from_secs(1));
/// assert_eq!(timer.duration(), Duration::from_secs(1));
/// ```
Expand All @@ -158,30 +158,34 @@ impl Timer {
/// # Examples
/// ```
/// # use bevy_time::*;
/// let mut timer = Timer::from_seconds(1.0, true);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);
/// assert!(timer.repeating());
/// ```
#[inline]
pub fn repeating(&self) -> bool {
self.repeating
self.mode.repeating()
}

/// Sets whether the timer is repeating or not.
///
/// # Examples
/// ```
/// # use bevy_time::*;
/// let mut timer = Timer::from_seconds(1.0, true);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);
/// timer.set_repeating(false);
/// assert!(!timer.repeating());
/// ```
#[inline]
pub fn set_repeating(&mut self, repeating: bool) {
if !self.repeating && repeating && self.finished {
if !self.mode.repeating() && repeating && self.finished {
self.stopwatch.reset();
self.finished = self.just_finished();
}
self.repeating = repeating;
self.mode = if repeating {
TimerMode::Repeating
} else {
TimerMode::Once
};
}

/// Advance the timer by `delta` seconds.
Expand All @@ -194,8 +198,8 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut repeating = Timer::from_seconds(1.0, true);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// let mut repeating = Timer::from_seconds(1.0, TimerMode::Repeating);
/// timer.tick(Duration::from_secs_f32(1.5));
/// repeating.tick(Duration::from_secs_f32(1.5));
/// assert_eq!(timer.elapsed_secs(), 1.0);
Expand Down Expand Up @@ -243,7 +247,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.pause();
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.elapsed_secs(), 0.0);
Expand All @@ -261,7 +265,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.pause();
/// timer.tick(Duration::from_secs_f32(0.5));
/// timer.unpause();
Expand All @@ -280,7 +284,7 @@ impl Timer {
/// # Examples
/// ```
/// # use bevy_time::*;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// assert!(!timer.paused());
/// timer.pause();
/// assert!(timer.paused());
Expand All @@ -300,7 +304,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(1.5));
/// timer.reset();
/// assert!(!timer.finished());
Expand All @@ -319,7 +323,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(2.0, false);
/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.percent(), 0.25);
/// ```
Expand All @@ -334,7 +338,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(2.0, false);
/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.percent_left(), 0.75);
/// ```
Expand All @@ -350,7 +354,7 @@ impl Timer {
/// # use bevy_time::*;
/// use std::cmp::Ordering;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(2.0, false);
/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(0.5));
/// let result = timer.remaining_secs().total_cmp(&1.5);
/// assert_eq!(Ordering::Equal, result);
Expand All @@ -366,7 +370,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(2.0, false);
/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.remaining(), Duration::from_secs_f32(1.5));
/// ```
Expand All @@ -385,7 +389,7 @@ impl Timer {
/// ```
/// # use bevy_time::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, true);
/// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);
/// timer.tick(Duration::from_secs_f32(6.0));
/// assert_eq!(timer.times_finished_this_tick(), 6);
/// timer.tick(Duration::from_secs_f32(2.0));
Expand All @@ -399,14 +403,36 @@ impl Timer {
}
}

/// Specifies [`Timer`] behavior.
#[derive(Debug, Clone, Copy, Reflect)]
#[reflect(Default)]
pub enum TimerMode {
/// Run once and stop.
Once,
/// Reset when finished.
Repeating,
}

impl TimerMode {
pub fn repeating(self) -> bool {
matches!(self, Self::Repeating)
}
}

impl Default for TimerMode {
fn default() -> Self {
Self::Once
}
}

#[cfg(test)]
#[allow(clippy::float_cmp)]
mod tests {
use super::*;

#[test]
fn non_repeating_timer() {
let mut t = Timer::from_seconds(10.0, false);
let mut t = Timer::from_seconds(10.0, TimerMode::Once);
// Tick once, check all attributes
t.tick(Duration::from_secs_f32(0.25));
assert_eq!(t.elapsed_secs(), 0.25);
Expand Down Expand Up @@ -449,7 +475,7 @@ mod tests {

#[test]
fn repeating_timer() {
let mut t = Timer::from_seconds(2.0, true);
let mut t = Timer::from_seconds(2.0, TimerMode::Repeating);
// Tick once, check all attributes
t.tick(Duration::from_secs_f32(0.75));
assert_eq!(t.elapsed_secs(), 0.75);
Expand Down Expand Up @@ -480,7 +506,7 @@ mod tests {

#[test]
fn times_finished_repeating() {
let mut t = Timer::from_seconds(1.0, true);
let mut t = Timer::from_seconds(1.0, TimerMode::Repeating);
assert_eq!(t.times_finished_this_tick(), 0);
t.tick(Duration::from_secs_f32(3.5));
assert_eq!(t.times_finished_this_tick(), 3);
Expand All @@ -493,7 +519,7 @@ mod tests {

#[test]
fn times_finished_this_tick() {
let mut t = Timer::from_seconds(1.0, false);
let mut t = Timer::from_seconds(1.0, TimerMode::Once);
assert_eq!(t.times_finished_this_tick(), 0);
t.tick(Duration::from_secs_f32(1.5));
assert_eq!(t.times_finished_this_tick(), 1);
Expand All @@ -503,7 +529,7 @@ mod tests {

#[test]
fn times_finished_this_tick_precise() {
let mut t = Timer::from_seconds(0.01, true);
let mut t = Timer::from_seconds(0.01, TimerMode::Repeating);
let duration = Duration::from_secs_f64(0.333);

// total duration: 0.333 => 33 times finished
Expand All @@ -522,7 +548,7 @@ mod tests {

#[test]
fn paused() {
let mut t = Timer::from_seconds(10.0, false);
let mut t = Timer::from_seconds(10.0, TimerMode::Once);

t.tick(Duration::from_secs_f32(10.0));
assert!(t.just_finished());
Expand All @@ -536,7 +562,7 @@ mod tests {

#[test]
fn paused_repeating() {
let mut t = Timer::from_seconds(10.0, true);
let mut t = Timer::from_seconds(10.0, TimerMode::Repeating);

t.tick(Duration::from_secs_f32(10.0));
assert!(t.just_finished());
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/sprite_sheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ fn setup(
transform: Transform::from_scale(Vec3::splat(6.0)),
..default()
},
AnimationTimer(Timer::from_seconds(0.1, true)),
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
));
}
2 changes: 1 addition & 1 deletion examples/app/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl Plugin for PrintMessagePlugin {
fn build(&self, app: &mut App) {
let state = PrintMessageState {
message: self.message.clone(),
timer: Timer::new(self.wait_duration, true),
timer: Timer::new(self.wait_duration, TimerMode::Repeating),
};
app.insert_resource(state).add_system(print_message_system);
}
Expand Down
2 changes: 1 addition & 1 deletion examples/ecs/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct EventTriggerState {
impl Default for EventTriggerState {
fn default() -> Self {
EventTriggerState {
event_timer: Timer::from_seconds(1.0, true),
event_timer: Timer::from_seconds(1.0, TimerMode::Repeating),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions examples/ecs/generic_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ fn main() {

fn setup_system(mut commands: Commands) {
commands.spawn((
PrinterTick(Timer::from_seconds(1.0, true)),
PrinterTick(Timer::from_seconds(1.0, TimerMode::Repeating)),
TextToPrint("I will print until you press space.".to_string()),
MenuClose,
));

commands.spawn((
PrinterTick(Timer::from_seconds(1.0, true)),
PrinterTick(Timer::from_seconds(1.0, TimerMode::Repeating)),
TextToPrint("I will always print".to_string()),
LevelUnload,
));
Expand Down
Loading

0 comments on commit 5a58300

Please sign in to comment.