Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discrete timer and stopwatch #2683

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions crates/bevy_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ pub use time::*;

pub mod prelude {
#[doc(hidden)]
pub use crate::{DefaultTaskPoolOptions, EntityLabels, Labels, Name, Time, Timer};
pub use crate::{
DefaultTaskPoolOptions, DiscreteTimer, DurationTimer, EntityLabels, Labels, Name, Time,
Timer,
};
}

use bevy_app::prelude::*;
Expand Down Expand Up @@ -55,7 +58,7 @@ impl Plugin for CorePlugin {
.register_type::<Name>()
.register_type::<Labels>()
.register_type::<Range<f32>>()
.register_type::<Timer>()
.register_type::<DurationTimer>()
// time system is added as an "exclusive system" to ensure it runs before other systems
// in CoreStage::First
.add_system_to_stage(
Expand Down
214 changes: 146 additions & 68 deletions crates/bevy_core/src/time/stopwatch.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,24 @@
use std::ops::Add;

use bevy_ecs::reflect::ReflectComponent;
use bevy_reflect::Reflect;
use bevy_utils::Duration;

/// A Stopwatch is a struct that track elapsed time when started.
///
/// # Examples
///
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
///
/// stopwatch.tick(Duration::from_secs_f32(1.0)); // tick one second
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
///
/// stopwatch.pause();
/// stopwatch.tick(Duration::from_secs_f32(1.0)); // paused stopwatches don't tick
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
///
/// stopwatch.reset(); // reset the stopwatch
/// assert!(stopwatch.paused());
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// ```
#[derive(Clone, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct Stopwatch {
elapsed: Duration,
paused: bool,
}
/// The `Stopwatch` trait enables counting-up behavior to track the passage of time.
pub trait Stopwatch: Default {
/// The unit by which elapsed time is measured
type TimeUnit: Default + Add<Output = Self::TimeUnit>;

impl Stopwatch {
/// Create a new unpaused `Stopwatch` with no elapsed time.
/// Create a new unpaused `Stopwatch` object with no elapsed time.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let stopwatch = Stopwatch::new();
/// let stopwatch = DurationStopwatch::new();
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// assert_eq!(stopwatch.paused(), false);
/// ```
pub fn new() -> Self {
fn new() -> Self {
Default::default()
}

Expand All @@ -51,50 +29,39 @@ impl Stopwatch {
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// stopwatch.tick(Duration::from_secs(1));
/// assert_eq!(stopwatch.elapsed(), Duration::from_secs(1));
/// ```
#[inline]
pub fn elapsed(&self) -> Duration {
self.elapsed
}

#[inline]
pub fn elapsed_secs(&self) -> f32 {
self.elapsed().as_secs_f32()
}
fn elapsed(&self) -> Self::TimeUnit;

/// Sets the elapsed time of the stopwatch.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// stopwatch.set_elapsed(Duration::from_secs_f32(1.0));
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
/// ```
#[inline]
pub fn set_elapsed(&mut self, time: Duration) {
self.elapsed = time;
}
fn set_elapsed(&mut self, time: Self::TimeUnit);

/// Advance the stopwatch by `delta` seconds.
/// Advance the stopwatch by `delta` units.
/// If the stopwatch is paused, ticking will not have any effect
/// on elapsed time.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// stopwatch.tick(Duration::from_secs_f32(1.5));
/// assert_eq!(stopwatch.elapsed_secs(), 1.5);
/// ```
pub fn tick(&mut self, delta: Duration) -> &Self {
fn tick(&mut self, delta: Self::TimeUnit) -> &Self {
if !self.paused() {
self.elapsed += delta;
self.set_elapsed(self.elapsed() + delta);
}
self
}
Expand All @@ -106,66 +73,177 @@ impl Stopwatch {
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// stopwatch.pause();
/// stopwatch.tick(Duration::from_secs_f32(1.5));
/// assert!(stopwatch.paused());
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// ```
#[inline]
pub fn pause(&mut self) {
self.paused = true;
}
fn pause(&mut self);

/// Unpauses the stopwatch. Resume the effect of ticking on elapsed time.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// stopwatch.pause();
/// stopwatch.tick(Duration::from_secs_f32(1.0));
/// stopwatch.unpause();
/// stopwatch.tick(Duration::from_secs_f32(1.0));
/// assert!(!stopwatch.paused());
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
/// ```
#[inline]
pub fn unpause(&mut self) {
self.paused = false;
}
fn unpause(&mut self);

/// Returns `true` if the stopwatch is paused.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// assert!(!stopwatch.paused());
/// stopwatch.pause();
/// assert!(stopwatch.paused());
/// stopwatch.unpause();
/// assert!(!stopwatch.paused());
/// ```
#[inline]
pub fn paused(&self) -> bool {
self.paused
}
fn paused(&self) -> bool;

/// Resets the stopwatch.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::new();
/// let mut stopwatch = DurationStopwatch::new();
/// stopwatch.tick(Duration::from_secs_f32(1.5));
/// stopwatch.reset();
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// ```
#[inline]
pub fn reset(&mut self) {
self.elapsed = Default::default();
fn reset(&mut self) {
self.set_elapsed(Self::TimeUnit::default());
}
}

/// A Stopwatch is a struct that tracks elapsed time when started.
///
/// # Examples
///
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = DurationStopwatch::new();
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
///
/// stopwatch.tick(Duration::from_secs_f32(1.0)); // tick one second
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
///
/// stopwatch.pause();
/// stopwatch.tick(Duration::from_secs_f32(1.0)); // paused stopwatches don't tick
/// assert_eq!(stopwatch.elapsed_secs(), 1.0);
///
/// stopwatch.reset(); // reset the stopwatch
/// assert!(stopwatch.paused());
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// ```
#[derive(Clone, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct DurationStopwatch {
elapsed: Duration,
paused: bool,
}

impl Stopwatch for DurationStopwatch {
type TimeUnit = Duration;

#[inline]
fn elapsed(&self) -> Self::TimeUnit {
self.elapsed
}

#[inline]
fn set_elapsed(&mut self, time: Self::TimeUnit) {
self.elapsed = time;
}

#[inline]
fn pause(&mut self) {
self.paused = true;
}

#[inline]
fn unpause(&mut self) {
self.paused = false;
}

#[inline]
fn paused(&self) -> bool {
self.paused
}
}

impl DurationStopwatch {
#[inline]
pub fn elapsed_secs(&self) -> f32 {
self.elapsed().as_secs_f32()
}
}

/// A DiscreteStopwatch is a struct that tracks the number of times it has been incremented when started.
///
/// # Examples
///
/// ```
/// # use bevy_core::*;
/// let mut stopwatch = DiscreteStopwatch::new();
/// assert_eq!(stopwatch.elapsed(), 0);
///
/// stopwatch.tick(1); // tick once
/// assert_eq!(stopwatch.elapsed(), 1);
///
/// stopwatch.pause();
/// stopwatch.tick(1); // paused stopwatches don't tick
/// assert_eq!(stopwatch.elapsed(), 1);
///
/// stopwatch.reset(); // reset the stopwatch
/// assert!(stopwatch.paused());
/// assert_eq!(stopwatch.elapsed(), 0);
/// ```
#[derive(Clone, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct DiscreteStopwatch {
elapsed: u64,
paused: bool,
}

impl Stopwatch for DiscreteStopwatch {
type TimeUnit = u64;

#[inline]
fn elapsed(&self) -> Self::TimeUnit {
self.elapsed
}

#[inline]
fn set_elapsed(&mut self, time: Self::TimeUnit) {
self.elapsed = time;
}

#[inline]
fn pause(&mut self) {
self.paused = true;
}

#[inline]
fn unpause(&mut self) {
self.paused = false;
}

#[inline]
fn paused(&self) -> bool {
self.paused
}
}
Loading