♻️ Timer refactor to duration. Add Stopwatch struct. (#1151)

This pull request is following the discussion on the issue #1127. Additionally, it integrates the change proposed by #1112.

The list of change of this pull request:

*  Add `Timer::times_finished` method that counts the number of wraps for repeating timers.
* ♻️ Refactored `Timer`
* 🐛 Fix a bug where 2 successive calls to `Timer::tick` which makes a repeating timer to finish makes `Timer::just_finished` to return `false` where it should return `true`. Minimal failing example:
```rust
use bevy::prelude::*;
let mut timer: Timer<()> = Timer::from_seconds(1.0, true);
timer.tick(1.5);
assert!(timer.finished());
assert!(timer.just_finished());
timer.tick(1.5);
assert!(timer.finished());
assert!(timer.just_finished()); // <- This fails where it should not
```
* 📚 Add extensive documentation for Timer with doc examples.
*  Add a `Stopwatch` struct similar to `Timer` with extensive doc and tests.

Even if the type specialization is not retained for bevy, the doc, bugfix and added method are worth salvaging 😅.
This is my first PR for bevy, please be kind to me ❤️ .

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
Chris Janaqi 2021-03-05 19:59:14 +00:00
parent 4686437d7a
commit ab407aa697
11 changed files with 530 additions and 135 deletions

View file

@ -1,8 +1,10 @@
mod fixed_timestep;
mod stopwatch;
#[allow(clippy::module_inception)]
mod time;
mod timer;
pub use fixed_timestep::*;
pub use stopwatch::*;
pub use time::*;
pub use timer::*;

View file

@ -0,0 +1,168 @@
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,
}
impl Stopwatch {
/// Create a new unpaused `Stopwatch` with no elapsed time.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let stopwatch = Stopwatch::new();
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
/// assert_eq!(stopwatch.paused(), false);
/// ```
pub fn new() -> Self {
Default::default()
}
/// Returns the elapsed time since the last [`reset`](Stopwatch::reset)
/// of the stopwatch.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::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()
}
/// Sets the elapsed time of the stopwatch.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::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;
}
/// Advance the stopwatch by `delta` seconds.
/// 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();
/// stopwatch.tick(Duration::from_secs_f32(1.5));
/// assert_eq!(stopwatch.elapsed_secs(), 1.5);
/// ```
pub fn tick(&mut self, delta: Duration) -> &Self {
if !self.paused() {
self.elapsed += delta;
}
self
}
/// Pauses the stopwatch. Any call to [`tick`](Stopwatch::tick) while
/// paused will not have any effect on the elapsed time.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::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;
}
/// Unpauses the stopwatch. Resume the effect of ticking on elapsed time.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::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;
}
/// Returns `true` if the stopwatch is paused.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let mut stopwatch = Stopwatch::new();
/// assert!(!stopwatch.paused());
/// stopwatch.pause();
/// assert!(stopwatch.paused());
/// stopwatch.unpause();
/// assert!(!stopwatch.paused());
/// ```
#[inline]
pub fn paused(&self) -> bool {
self.paused
}
/// Resets the stopwatch.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut stopwatch = Stopwatch::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();
}
}

View file

@ -1,3 +1,4 @@
use crate::Stopwatch;
use bevy_ecs::reflect::ReflectComponent;
use bevy_reflect::Reflect;
use bevy_utils::Duration;
@ -11,228 +12,455 @@ use bevy_utils::Duration;
#[derive(Clone, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct Timer {
elapsed: f32,
duration: f32,
finished: bool,
/// Will only be non-zero on the tick `duration` is reached or exceeded.
just_finished_count: u32,
paused: bool,
stopwatch: Stopwatch,
duration: Duration,
repeating: bool,
finished: bool,
times_finished: u32,
}
impl Timer {
pub fn new(duration: Duration, repeating: bool) -> Self {
Timer {
duration: duration.as_secs_f32(),
repeating,
..Default::default()
}
}
pub fn from_seconds(seconds: f32, repeating: bool) -> Self {
Timer {
duration: seconds,
repeating,
..Default::default()
}
}
#[inline]
pub fn pause(&mut self) {
self.paused = true
}
#[inline]
pub fn unpause(&mut self) {
self.paused = false
}
#[inline]
pub fn paused(&self) -> bool {
self.paused
}
/// 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
}
#[inline]
pub fn set_elapsed(&mut self, elapsed: f32) {
self.elapsed = elapsed
}
#[inline]
pub fn duration(&self) -> f32 {
self.duration
}
#[inline]
pub fn set_duration(&mut self, duration: f32) {
self.duration = duration
}
/// Returns the finished state of the timer.
/// Creates a new timer with a given duration.
///
/// 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`.
/// See also [`Timer::from_seconds`](Timer::from_seconds).
pub fn new(duration: Duration, repeating: bool) -> Self {
Self {
duration,
repeating,
..Default::default()
}
}
/// Creates a new timer with a given duration in seconds.
///
/// # Example
/// ```
/// # use bevy_core::*;
/// let mut timer = Timer::from_seconds(1.0, false);
/// ```
pub fn from_seconds(duration: f32, repeating: bool) -> Self {
Self {
duration: Duration::from_secs_f32(duration),
repeating,
..Default::default()
}
}
/// Returns `true` if the timer has reached its duration.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// timer.tick(Duration::from_secs_f32(1.5));
/// assert!(timer.finished());
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert!(timer.finished());
/// ```
#[inline]
pub fn finished(&self) -> bool {
self.finished
}
/// Will only be true on the tick the timer's duration is reached or exceeded.
/// Returns `true` only on the tick the timer reached its duration.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// timer.tick(Duration::from_secs_f32(1.5));
/// assert!(timer.just_finished());
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert!(!timer.just_finished());
/// ```
#[inline]
pub fn just_finished(&self) -> bool {
self.just_finished_count > 0
self.times_finished > 0
}
/// Returns the total number of times the timer finished during this tick.
/// 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.
///
/// 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.
/// See also [`Stopwatch::elapsed`](Stopwatch::elapsed).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.elapsed(), Duration::from_secs_f32(0.5));
/// ```
#[inline]
pub fn just_finished_count(&self) -> u32 {
self.just_finished_count
pub fn elapsed(&self) -> Duration {
self.stopwatch.elapsed()
}
/// Returns the time elapsed on the timer as a `f32`.
/// See also [`Timer::elapsed`](Timer::elapsed).
#[inline]
pub fn elapsed_secs(&self) -> f32 {
self.stopwatch.elapsed_secs()
}
/// Sets the elapsed time of the timer without any other considerations.
///
/// See also [`Stopwatch::set`](Stopwatch::set).
///
/// #
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// 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.
/// assert!(!timer.finished());
/// ```
#[inline]
pub fn set_elapsed(&mut self, time: Duration) {
self.stopwatch.set_elapsed(time);
}
/// Returns the duration of the timer.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let timer = Timer::new(Duration::from_secs(1), false);
/// assert_eq!(timer.duration(), Duration::from_secs(1));
/// ```
#[inline]
pub fn duration(&self) -> Duration {
self.duration
}
/// Sets the duration of the timer.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.5, false);
/// timer.set_duration(Duration::from_secs(1));
/// assert_eq!(timer.duration(), Duration::from_secs(1));
/// ```
#[inline]
pub fn set_duration(&mut self, duration: Duration) {
self.duration = duration;
}
/// Returns `true` if the timer is repeating.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let mut timer = Timer::from_seconds(1.0, true);
/// assert!(timer.repeating());
/// ```
#[inline]
pub fn repeating(&self) -> bool {
self.repeating
}
/// Sets whether the timer is repeating or not.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let mut timer = Timer::from_seconds(1.0, true);
/// timer.set_repeating(false);
/// assert!(!timer.repeating());
/// ```
#[inline]
pub fn set_repeating(&mut self, repeating: bool) {
if !self.repeating && repeating && self.finished {
self.elapsed = 0.0;
self.stopwatch.reset();
self.finished = self.just_finished();
}
self.repeating = repeating
}
/// Advances the timer by `delta` seconds.
pub fn tick(&mut self, delta: f32) -> &Self {
if self.paused {
/// Advance the timer by `delta` seconds.
/// Non repeating timer will clamp at duration.
/// Repeating timer will wrap around.
///
/// See also [`Stopwatch::tick`](Stopwatch::tick).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// let mut repeating = Timer::from_seconds(1.0, true);
/// timer.tick(Duration::from_secs_f32(1.5));
/// repeating.tick(Duration::from_secs_f32(1.5));
/// assert_eq!(timer.elapsed_secs(), 1.0);
/// assert_eq!(repeating.elapsed_secs(), 0.5);
/// ```
pub fn tick(&mut self, delta: Duration) -> &Self {
if self.paused() {
return self;
}
let prev_finished = self.finished;
self.elapsed += delta;
self.finished = self.elapsed >= self.duration;
if !self.repeating() && self.finished() {
self.times_finished = 0;
return self;
}
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;
self.stopwatch.tick(delta);
self.finished = self.elapsed() >= self.duration();
if self.finished() {
if self.repeating() {
self.times_finished = self.percent().floor() as u32;
// Duration does not have a modulo
self.set_elapsed(self.elapsed() - self.duration() * self.times_finished);
} else {
self.just_finished_count = if prev_finished { 0 } else { 1 };
// Non-repeating timers clamp to duration
self.elapsed = self.duration;
self.times_finished = 1;
self.set_elapsed(self.duration());
}
} else {
self.just_finished_count = 0;
self.times_finished = 0;
}
self
}
/// Pauses the Timer. Disables the ticking of the timer.
///
/// See also [`Stopwatch::pause`](Stopwatch::pause).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// timer.pause();
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.elapsed_secs(), 0.0);
/// ```
#[inline]
pub fn pause(&mut self) {
self.stopwatch.pause();
}
/// Unpauses the Timer. Resumes the ticking of the timer.
///
/// See also [`Stopwatch::unpause()`](Stopwatch::unpause).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// timer.pause();
/// timer.tick(Duration::from_secs_f32(0.5));
/// timer.unpause();
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.elapsed_secs(), 0.5);
/// ```
#[inline]
pub fn unpause(&mut self) {
self.stopwatch.unpause();
}
/// Returns `true` if the timer is paused.
///
/// See also [`Stopwatch::paused`](Stopwatch::paused).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// let mut timer = Timer::from_seconds(1.0, false);
/// assert!(!timer.paused());
/// timer.pause();
/// assert!(timer.paused());
/// timer.unpause();
/// assert!(!timer.paused());
/// ```
#[inline]
pub fn paused(&self) -> bool {
self.stopwatch.paused()
}
/// Resets the timer. the reset doesn't affect the `paused` state of the timer.
///
/// See also [`Stopwatch::reset`](Stopwatch::reset).
///
/// Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, false);
/// timer.tick(Duration::from_secs_f32(1.5));
/// timer.reset();
/// assert!(!timer.finished());
/// assert!(!timer.just_finished());
/// assert_eq!(timer.elapsed_secs(), 0.0);
/// ```
pub fn reset(&mut self) {
self.stopwatch.reset();
self.finished = false;
self.just_finished_count = 0;
self.elapsed = 0.0;
self.times_finished = 0;
}
/// Percent timer has elapsed (goes from 0.0 to 1.0)
/// Returns the percentage of the timer elapsed time (goes from 0.0 to 1.0).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(2.0, false);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.percent(), 0.25);
/// ```
#[inline]
pub fn percent(&self) -> f32 {
self.elapsed / self.duration
self.elapsed().as_secs_f32() / self.duration().as_secs_f32()
}
/// Percent left on timer (goes from 1.0 to 0.0)
/// Returns the percentage of the timer remaining time (goes from 0.0 to 1.0).
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(2.0, false);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.percent_left(), 0.75);
/// ```
#[inline]
pub fn percent_left(&self) -> f32 {
(self.duration - self.elapsed) / self.duration
1.0 - self.percent()
}
/// Returns the number of times a repeating timer
/// finished during the last [`tick`](Timer<T>::tick) call.
///
/// For non repeating-timers, this method will only ever
/// return 0 or 1.
///
/// # Examples
/// ```
/// # use bevy_core::*;
/// use std::time::Duration;
/// let mut timer = Timer::from_seconds(1.0, true);
/// timer.tick(Duration::from_secs_f32(6.0));
/// assert_eq!(timer.times_finished(), 6);
/// timer.tick(Duration::from_secs_f32(2.0));
/// assert_eq!(timer.times_finished(), 2);
/// timer.tick(Duration::from_secs_f32(0.5));
/// assert_eq!(timer.times_finished(), 0);
/// ```
#[inline]
pub fn times_finished(&self) -> u32 {
self.times_finished
}
}
#[cfg(test)]
#[allow(clippy::float_cmp)]
mod tests {
use super::Timer;
use super::*;
#[test]
fn test_non_repeating() {
fn non_repeating_timer() {
let mut t = Timer::from_seconds(10.0, false);
// Tick once, check all attributes
t.tick(0.25);
assert_eq!(t.elapsed(), 0.25);
assert_eq!(t.duration(), 10.0);
t.tick(Duration::from_secs_f32(0.25));
assert_eq!(t.elapsed_secs(), 0.25);
assert_eq!(t.duration(), Duration::from_secs_f32(10.0));
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.times_finished(), 0);
assert_eq!(t.repeating(), false);
assert_eq!(t.percent(), 0.025);
assert_eq!(t.percent_left(), 0.975);
// Ticking while paused changes nothing
t.pause();
t.tick(500.0);
assert_eq!(t.elapsed(), 0.25);
assert_eq!(t.duration(), 10.0);
t.tick(Duration::from_secs_f32(500.0));
assert_eq!(t.elapsed_secs(), 0.25);
assert_eq!(t.duration(), Duration::from_secs_f32(10.0));
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.times_finished(), 0);
assert_eq!(t.repeating(), false);
assert_eq!(t.percent(), 0.025);
assert_eq!(t.percent_left(), 0.975);
// Tick past the end and make sure elapsed doesn't go past 0.0 and other things update
t.unpause();
t.tick(500.0);
assert_eq!(t.elapsed(), 10.0);
t.tick(Duration::from_secs_f32(500.0));
assert_eq!(t.elapsed_secs(), 10.0);
assert_eq!(t.finished(), true);
assert_eq!(t.just_finished(), true);
assert_eq!(t.just_finished_count(), 1);
assert_eq!(t.times_finished(), 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);
t.tick(Duration::from_secs_f32(1.0));
assert_eq!(t.elapsed_secs(), 10.0);
assert_eq!(t.finished(), true);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.times_finished(), 0);
assert_eq!(t.percent(), 1.0);
assert_eq!(t.percent_left(), 0.0);
}
#[test]
fn test_repeating() {
fn repeating_timer() {
let mut t = Timer::from_seconds(2.0, true);
// Tick once, check all attributes
t.tick(0.75);
assert_eq!(t.elapsed(), 0.75);
assert_eq!(t.duration(), 2.0);
t.tick(Duration::from_secs_f32(0.75));
assert_eq!(t.elapsed_secs(), 0.75);
assert_eq!(t.duration(), Duration::from_secs_f32(2.0));
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.times_finished(), 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(3.5);
assert_eq!(t.elapsed(), 0.25);
t.tick(Duration::from_secs_f32(1.5));
assert_eq!(t.elapsed_secs(), 0.25);
assert_eq!(t.finished(), true);
assert_eq!(t.just_finished(), true);
assert_eq!(t.just_finished_count(), 2);
assert_eq!(t.times_finished(), 1);
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);
t.tick(Duration::from_secs_f32(1.0));
assert_eq!(t.elapsed_secs(), 1.25);
assert_eq!(t.finished(), false);
assert_eq!(t.just_finished(), false);
assert_eq!(t.just_finished_count(), 0);
assert_eq!(t.times_finished(), 0);
assert_eq!(t.percent(), 0.625);
assert_eq!(t.percent_left(), 0.375);
}
#[test]
fn times_finished_repeating() {
let mut t = Timer::from_seconds(1.0, true);
assert_eq!(t.times_finished(), 0);
t.tick(Duration::from_secs_f32(3.5));
assert_eq!(t.times_finished(), 3);
assert_eq!(t.elapsed_secs(), 0.5);
assert!(t.finished());
assert!(t.just_finished());
t.tick(Duration::from_secs_f32(0.2));
assert_eq!(t.times_finished(), 0);
}
#[test]
fn times_finished() {
let mut t = Timer::from_seconds(1.0, false);
assert_eq!(t.times_finished(), 0);
t.tick(Duration::from_secs_f32(1.5));
assert_eq!(t.times_finished(), 1);
t.tick(Duration::from_secs_f32(0.5));
assert_eq!(t.times_finished(), 0);
}
}

View file

@ -90,7 +90,7 @@ impl LogDiagnosticsPlugin {
time: Res<Time>,
diagnostics: Res<Diagnostics>,
) {
if state.timer.tick(time.delta_seconds()).finished() {
if state.timer.tick(time.delta()).finished() {
if let Some(ref filter) = state.filter {
for diagnostic in filter.iter().map(|id| diagnostics.get(*id).unwrap()) {
Self::log_diagnostic(diagnostic);
@ -108,7 +108,7 @@ impl LogDiagnosticsPlugin {
time: Res<Time>,
diagnostics: Res<Diagnostics>,
) {
if state.timer.tick(time.delta_seconds()).finished() {
if state.timer.tick(time.delta()).finished() {
if let Some(ref filter) = state.filter {
for diagnostic in filter.iter().map(|id| diagnostics.get(*id).unwrap()) {
debug!("{:#?}\n", diagnostic);

View file

@ -4,7 +4,7 @@ use crate::{
};
use bevy_reflect_derive::impl_reflect_value;
use bevy_utils::{HashMap, HashSet};
use bevy_utils::{Duration, HashMap, HashSet};
use serde::{Deserialize, Serialize};
use std::{
any::Any,
@ -32,6 +32,7 @@ impl_reflect_value!(String(Hash, PartialEq, Serialize, Deserialize));
impl_reflect_value!(Option<T: Serialize + Clone + for<'de> Deserialize<'de> + Reflect + 'static>(Serialize, Deserialize));
impl_reflect_value!(HashSet<T: Serialize + Hash + Eq + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize));
impl_reflect_value!(Range<T: Serialize + Clone + for<'de> Deserialize<'de> + Send + Sync + 'static>(Serialize, Deserialize));
impl_reflect_value!(Duration);
impl<T: Reflect> List for Vec<T> {
fn get(&self, index: usize) -> Option<&dyn Reflect> {

View file

@ -151,7 +151,7 @@ fn select_system(
) {
let mut timer_fired = false;
for mut t in tq.iter_mut() {
if !t.tick(time.delta_seconds()).just_finished() {
if !t.tick(time.delta()).just_finished() {
continue;
}
t.reset();

View file

@ -14,7 +14,7 @@ fn animate_sprite_system(
mut query: Query<(&mut Timer, &mut TextureAtlasSprite, &Handle<TextureAtlas>)>,
) {
for (mut timer, mut sprite, texture_atlas_handle) in query.iter_mut() {
timer.tick(time.delta_seconds());
timer.tick(time.delta());
if timer.finished() {
let texture_atlas = texture_atlases.get(texture_atlas_handle).unwrap();
sprite.index = ((sprite.index as usize + 1) % texture_atlas.textures.len()) as u32;

View file

@ -39,7 +39,7 @@ struct PrintMessageState {
}
fn print_message_system(mut state: ResMut<PrintMessageState>, time: Res<Time>) {
if state.timer.tick(time.delta_seconds()).finished() {
if state.timer.tick(time.delta()).finished() {
println!("{}", state.message);
}
}

View file

@ -34,7 +34,7 @@ fn event_trigger_system(
mut state: ResMut<EventTriggerState>,
mut my_events: ResMut<Events<MyEvent>>,
) {
if state.event_timer.tick(time.delta_seconds()).finished() {
if state.event_timer.tick(time.delta()).finished() {
my_events.send(MyEvent {
message: "MyEvent just happened!".to_string(),
});

View file

@ -39,7 +39,7 @@ fn setup_system(mut commands: Commands) {
/// using bevy's `Time` resource to get the delta between each update.
fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
for mut timer in query.iter_mut() {
if timer.tick(time.delta_seconds()).just_finished() {
if timer.tick(time.delta()).just_finished() {
info!("Entity timer just finished")
}
}
@ -48,16 +48,12 @@ fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
/// This system controls ticking the timer within the countdown resource and
/// handling its state.
fn countdown_system(time: Res<Time>, mut countdown: ResMut<Countdown>) {
countdown.main_timer.tick(time.delta_seconds());
countdown.main_timer.tick(time.delta());
// The API encourages this kind of timer state checking (if you're only checking for one value)
// Additionally, `finished()` would accomplish the same thing as `just_finished` due to the timer
// being repeating, however this makes more sense visually.
if countdown
.percent_trigger
.tick(time.delta_seconds())
.just_finished()
{
if countdown.percent_trigger.tick(time.delta()).just_finished() {
if !countdown.main_timer.finished() {
// Print the percent complete the main timer is.
info!(

View file

@ -64,7 +64,7 @@ fn atlas_render_system(
}
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Query<&mut Text>) {
if state.timer.tick(time.delta_seconds()).finished() {
if state.timer.tick(time.delta()).finished() {
for mut text in query.iter_mut() {
let c = rand::random::<u8>() as char;
if !text.sections[0].value.contains(c) {