use crate::Stopwatch;1#[cfg(feature = "bevy_reflect")]2use bevy_reflect::prelude::*;3use core::time::Duration;45/// Tracks elapsed time. Enters the finished state once `duration` is reached.6///7/// Note that in order to advance the timer [`tick`](Timer::tick) **MUST** be called.8///9/// # Timer modes10///11/// There are two timer modes ([`TimerMode`]):12///13/// - Non repeating timers will stop tracking and stay in the finished state until reset.14/// - Repeating timers will only be in the finished state on each tick `duration` is reached or15/// exceeded, and can still be reset at any given point.16///17/// # Pausing timers18///19/// You can pause a timer using [`Timer::pause`]. Paused timers will not have elapsed time increased.20///21/// # Elapsing multiple times a frame22///23/// Repeating timers might elapse multiple times per frame if the time is advanced by more than the timer duration.24/// You can check how many times a timer elapsed each tick with [`Timer::times_finished_this_tick`].25/// For non-repeating timers, this will always be 0 or 1.26#[derive(Clone, Debug, Default, PartialEq, Eq)]27#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]28#[cfg_attr(29feature = "bevy_reflect",30derive(Reflect),31reflect(Default, Clone, PartialEq)32)]33pub struct Timer {34stopwatch: Stopwatch,35duration: Duration,36mode: TimerMode,37finished: bool,38times_finished_this_tick: u32,39}4041impl Timer {42/// Creates a new timer with a given duration.43///44/// See also [`Timer::from_seconds`](Timer::from_seconds).45pub fn new(duration: Duration, mode: TimerMode) -> Self {46Self {47duration,48mode,49..Default::default()50}51}5253/// Creates a new timer with a given duration in seconds.54///55/// # Example56/// ```57/// # use bevy_time::*;58/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);59/// ```60pub fn from_seconds(duration: f32, mode: TimerMode) -> Self {61Self {62duration: Duration::from_secs_f32(duration),63mode,64..Default::default()65}66}6768/// Returns `true` if the timer has reached its duration.69///70/// For repeating timers, this method behaves identically to [`Timer::just_finished`].71///72/// # Examples73/// ```74/// # use bevy_time::*;75/// use std::time::Duration;76///77/// let mut timer_once = Timer::from_seconds(1.0, TimerMode::Once);78/// timer_once.tick(Duration::from_secs_f32(1.5));79/// assert!(timer_once.is_finished());80/// timer_once.tick(Duration::from_secs_f32(0.5));81/// assert!(timer_once.is_finished());82///83/// let mut timer_repeating = Timer::from_seconds(1.0, TimerMode::Repeating);84/// timer_repeating.tick(Duration::from_secs_f32(1.1));85/// assert!(timer_repeating.is_finished());86/// timer_repeating.tick(Duration::from_secs_f32(0.8));87/// assert!(!timer_repeating.is_finished());88/// timer_repeating.tick(Duration::from_secs_f32(0.6));89/// assert!(timer_repeating.is_finished());90/// ```91#[inline]92pub fn is_finished(&self) -> bool {93self.finished94}9596/// Returns `true` if the timer has reached its duration.97///98/// For repeating timers, this method behaves identically to [`Timer::just_finished`].99///100/// # Examples101/// ```102/// # use bevy_time::*;103/// use std::time::Duration;104///105/// let mut timer_once = Timer::from_seconds(1.0, TimerMode::Once);106/// timer_once.tick(Duration::from_secs_f32(1.5));107/// assert!(timer_once.finished());108/// timer_once.tick(Duration::from_secs_f32(0.5));109/// assert!(timer_once.finished());110///111/// let mut timer_repeating = Timer::from_seconds(1.0, TimerMode::Repeating);112/// timer_repeating.tick(Duration::from_secs_f32(1.1));113/// assert!(timer_repeating.finished());114/// timer_repeating.tick(Duration::from_secs_f32(0.8));115/// assert!(!timer_repeating.finished());116/// timer_repeating.tick(Duration::from_secs_f32(0.6));117/// assert!(timer_repeating.finished());118/// ```119#[deprecated(since = "0.17.0", note = "Use `is_finished` instead")]120#[inline]121pub fn finished(&self) -> bool {122self.finished123}124125/// Returns `true` only on the tick the timer reached its duration.126///127/// # Examples128/// ```129/// # use bevy_time::*;130/// use std::time::Duration;131/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);132/// timer.tick(Duration::from_secs_f32(1.5));133/// assert!(timer.just_finished());134/// timer.tick(Duration::from_secs_f32(0.5));135/// assert!(!timer.just_finished());136/// ```137#[inline]138pub fn just_finished(&self) -> bool {139self.times_finished_this_tick > 0140}141142/// Returns the time elapsed on the timer. Guaranteed to be between 0.0 and `duration`.143/// Will only equal `duration` when the timer is finished and non repeating.144///145/// See also [`Stopwatch::elapsed`](Stopwatch::elapsed).146///147/// # Examples148/// ```149/// # use bevy_time::*;150/// use std::time::Duration;151/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);152/// timer.tick(Duration::from_secs_f32(0.5));153/// assert_eq!(timer.elapsed(), Duration::from_secs_f32(0.5));154/// ```155#[inline]156pub fn elapsed(&self) -> Duration {157self.stopwatch.elapsed()158}159160/// Returns the time elapsed on the timer as an `f32`.161/// See also [`Timer::elapsed`](Timer::elapsed).162#[inline]163pub fn elapsed_secs(&self) -> f32 {164self.stopwatch.elapsed_secs()165}166167/// Returns the time elapsed on the timer as an `f64`.168/// See also [`Timer::elapsed`](Timer::elapsed).169#[inline]170pub fn elapsed_secs_f64(&self) -> f64 {171self.stopwatch.elapsed_secs_f64()172}173174/// Sets the elapsed time of the timer without any other considerations.175///176/// See also [`Stopwatch::set`](Stopwatch::set).177///178/// #179/// ```180/// # use bevy_time::*;181/// use std::time::Duration;182/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);183/// timer.set_elapsed(Duration::from_secs(2));184/// assert_eq!(timer.elapsed(), Duration::from_secs(2));185/// // the timer is not finished even if the elapsed time is greater than the duration.186/// assert!(!timer.is_finished());187/// ```188#[inline]189pub fn set_elapsed(&mut self, time: Duration) {190self.stopwatch.set_elapsed(time);191}192193/// Returns the duration of the timer.194///195/// # Examples196/// ```197/// # use bevy_time::*;198/// use std::time::Duration;199/// let timer = Timer::new(Duration::from_secs(1), TimerMode::Once);200/// assert_eq!(timer.duration(), Duration::from_secs(1));201/// ```202#[inline]203pub fn duration(&self) -> Duration {204self.duration205}206207/// Sets the duration of the timer.208///209/// # Examples210/// ```211/// # use bevy_time::*;212/// use std::time::Duration;213/// let mut timer = Timer::from_seconds(1.5, TimerMode::Once);214/// timer.set_duration(Duration::from_secs(1));215/// assert_eq!(timer.duration(), Duration::from_secs(1));216/// ```217#[inline]218pub fn set_duration(&mut self, duration: Duration) {219self.duration = duration;220}221222/// Finishes the timer.223///224/// # Examples225/// ```226/// # use bevy_time::*;227/// let mut timer = Timer::from_seconds(1.5, TimerMode::Once);228/// timer.finish();229/// assert!(timer.finished());230/// ```231#[inline]232pub fn finish(&mut self) {233let remaining = self.remaining();234self.tick(remaining);235}236237/// Returns the mode of the timer.238///239/// # Examples240/// ```241/// # use bevy_time::*;242/// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);243/// assert_eq!(timer.mode(), TimerMode::Repeating);244/// ```245#[inline]246pub fn mode(&self) -> TimerMode {247self.mode248}249250/// Sets the mode of the timer.251///252/// # Examples253/// ```254/// # use bevy_time::*;255/// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);256/// timer.set_mode(TimerMode::Once);257/// assert_eq!(timer.mode(), TimerMode::Once);258/// ```259#[doc(alias = "repeating")]260#[inline]261pub fn set_mode(&mut self, mode: TimerMode) {262if self.mode != TimerMode::Repeating && mode == TimerMode::Repeating && self.finished {263self.stopwatch.reset();264self.finished = self.just_finished();265}266self.mode = mode;267}268269/// Advance the timer by `delta` seconds.270/// Non repeating timer will clamp at duration.271/// Repeating timer will wrap around.272/// Will not affect paused timers.273///274/// See also [`Stopwatch::tick`](Stopwatch::tick).275///276/// # Examples277/// ```278/// # use bevy_time::*;279/// use std::time::Duration;280/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);281/// let mut repeating = Timer::from_seconds(1.0, TimerMode::Repeating);282/// timer.tick(Duration::from_secs_f32(1.5));283/// repeating.tick(Duration::from_secs_f32(1.5));284/// assert_eq!(timer.elapsed_secs(), 1.0);285/// assert_eq!(repeating.elapsed_secs(), 0.5);286/// ```287pub fn tick(&mut self, delta: Duration) -> &Self {288if self.is_paused() {289self.times_finished_this_tick = 0;290if self.mode == TimerMode::Repeating {291self.finished = false;292}293return self;294}295296if self.mode != TimerMode::Repeating && self.is_finished() {297self.times_finished_this_tick = 0;298return self;299}300301self.stopwatch.tick(delta);302self.finished = self.elapsed() >= self.duration();303304if self.is_finished() {305if self.mode == TimerMode::Repeating {306self.times_finished_this_tick = self307.elapsed()308.as_nanos()309.checked_div(self.duration().as_nanos())310.map_or(u32::MAX, |x| x as u32);311self.set_elapsed(312self.elapsed()313.as_nanos()314.checked_rem(self.duration().as_nanos())315.map_or(Duration::ZERO, |x| Duration::from_nanos(x as u64)),316);317} else {318self.times_finished_this_tick = 1;319self.set_elapsed(self.duration());320}321} else {322self.times_finished_this_tick = 0;323}324325self326}327328/// Pauses the Timer. Disables the ticking of the timer.329///330/// See also [`Stopwatch::pause`](Stopwatch::pause).331///332/// # Examples333/// ```334/// # use bevy_time::*;335/// use std::time::Duration;336/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);337/// timer.pause();338/// timer.tick(Duration::from_secs_f32(0.5));339/// assert_eq!(timer.elapsed_secs(), 0.0);340/// ```341#[inline]342pub fn pause(&mut self) {343self.stopwatch.pause();344}345346/// Unpauses the Timer. Resumes the ticking of the timer.347///348/// See also [`Stopwatch::unpause()`](Stopwatch::unpause).349///350/// # Examples351/// ```352/// # use bevy_time::*;353/// use std::time::Duration;354/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);355/// timer.pause();356/// timer.tick(Duration::from_secs_f32(0.5));357/// timer.unpause();358/// timer.tick(Duration::from_secs_f32(0.5));359/// assert_eq!(timer.elapsed_secs(), 0.5);360/// ```361#[inline]362pub fn unpause(&mut self) {363self.stopwatch.unpause();364}365366/// Returns `true` if the timer is paused.367///368/// See also [`Stopwatch::is_paused`](Stopwatch::is_paused).369///370/// # Examples371/// ```372/// # use bevy_time::*;373/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);374/// assert!(!timer.is_paused());375/// timer.pause();376/// assert!(timer.is_paused());377/// timer.unpause();378/// assert!(!timer.is_paused());379/// ```380#[inline]381pub fn is_paused(&self) -> bool {382self.stopwatch.is_paused()383}384385/// Returns `true` if the timer is paused.386///387/// See also [`Stopwatch::is_paused`](Stopwatch::is_paused).388///389/// # Examples390/// ```391/// # use bevy_time::*;392/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);393/// assert!(!timer.paused());394/// timer.pause();395/// assert!(timer.paused());396/// timer.unpause();397/// assert!(!timer.paused());398/// ```399#[deprecated(since = "0.17.0", note = "Use `is_paused` instead")]400#[inline]401pub fn paused(&self) -> bool {402self.stopwatch.is_paused()403}404405/// Resets the timer. The reset doesn't affect the `paused` state of the timer.406///407/// See also [`Stopwatch::reset`](Stopwatch::reset).408///409/// Examples410/// ```411/// # use bevy_time::*;412/// use std::time::Duration;413/// let mut timer = Timer::from_seconds(1.0, TimerMode::Once);414/// timer.tick(Duration::from_secs_f32(1.5));415/// timer.reset();416/// assert!(!timer.is_finished());417/// assert!(!timer.just_finished());418/// assert_eq!(timer.elapsed_secs(), 0.0);419/// ```420pub fn reset(&mut self) {421self.stopwatch.reset();422self.finished = false;423self.times_finished_this_tick = 0;424}425426/// Returns the fraction of the timer elapsed time (goes from 0.0 to 1.0).427///428/// # Examples429/// ```430/// # use bevy_time::*;431/// use std::time::Duration;432/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);433/// timer.tick(Duration::from_secs_f32(0.5));434/// assert_eq!(timer.fraction(), 0.25);435/// ```436#[inline]437pub fn fraction(&self) -> f32 {438if self.duration == Duration::ZERO {4391.0440} else {441self.elapsed().as_secs_f32() / self.duration().as_secs_f32()442}443}444445/// Returns the fraction of the timer remaining time (goes from 1.0 to 0.0).446///447/// # Examples448/// ```449/// # use bevy_time::*;450/// use std::time::Duration;451/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);452/// timer.tick(Duration::from_secs_f32(0.5));453/// assert_eq!(timer.fraction_remaining(), 0.75);454/// ```455#[inline]456pub fn fraction_remaining(&self) -> f32 {4571.0 - self.fraction()458}459460/// Returns the remaining time in seconds461///462/// # Examples463/// ```464/// # use bevy_time::*;465/// use std::cmp::Ordering;466/// use std::time::Duration;467/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);468/// timer.tick(Duration::from_secs_f32(0.5));469/// let result = timer.remaining_secs().total_cmp(&1.5);470/// assert_eq!(Ordering::Equal, result);471/// ```472#[inline]473pub fn remaining_secs(&self) -> f32 {474self.remaining().as_secs_f32()475}476477/// Returns the remaining time using Duration478///479/// # Examples480/// ```481/// # use bevy_time::*;482/// use std::time::Duration;483/// let mut timer = Timer::from_seconds(2.0, TimerMode::Once);484/// timer.tick(Duration::from_secs_f32(0.5));485/// assert_eq!(timer.remaining(), Duration::from_secs_f32(1.5));486/// ```487#[inline]488pub fn remaining(&self) -> Duration {489self.duration() - self.elapsed()490}491492/// Returns the number of times a repeating timer493/// finished during the last [`tick`](Timer<T>::tick) call.494///495/// For non repeating-timers, this method will only ever496/// return 0 or 1.497///498/// # Examples499/// ```500/// # use bevy_time::*;501/// use std::time::Duration;502/// let mut timer = Timer::from_seconds(1.0, TimerMode::Repeating);503/// timer.tick(Duration::from_secs_f32(6.0));504/// assert_eq!(timer.times_finished_this_tick(), 6);505/// timer.tick(Duration::from_secs_f32(2.0));506/// assert_eq!(timer.times_finished_this_tick(), 2);507/// timer.tick(Duration::from_secs_f32(0.5));508/// assert_eq!(timer.times_finished_this_tick(), 0);509/// ```510#[inline]511pub fn times_finished_this_tick(&self) -> u32 {512self.times_finished_this_tick513}514}515516/// Specifies [`Timer`] behavior.517#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default)]518#[cfg_attr(feature = "serialize", derive(serde::Deserialize, serde::Serialize))]519#[cfg_attr(520feature = "bevy_reflect",521derive(Reflect),522reflect(Default, Clone, PartialEq, Hash)523)]524pub enum TimerMode {525/// Run once and stop.526#[default]527Once,528/// Reset when finished.529Repeating,530}531532#[cfg(test)]533mod tests {534use super::*;535536#[test]537fn non_repeating_timer() {538let mut t = Timer::from_seconds(10.0, TimerMode::Once);539// Tick once, check all attributes540t.tick(Duration::from_secs_f32(0.25));541assert_eq!(t.elapsed_secs(), 0.25);542assert_eq!(t.elapsed_secs_f64(), 0.25);543assert_eq!(t.duration(), Duration::from_secs_f32(10.0));544assert!(!t.is_finished());545assert!(!t.just_finished());546assert_eq!(t.times_finished_this_tick(), 0);547assert_eq!(t.mode(), TimerMode::Once);548assert_eq!(t.fraction(), 0.025);549assert_eq!(t.fraction_remaining(), 0.975);550// Ticking while paused changes nothing551t.pause();552t.tick(Duration::from_secs_f32(500.0));553assert_eq!(t.elapsed_secs(), 0.25);554assert_eq!(t.duration(), Duration::from_secs_f32(10.0));555assert!(!t.is_finished());556assert!(!t.just_finished());557assert_eq!(t.times_finished_this_tick(), 0);558assert_eq!(t.mode(), TimerMode::Once);559assert_eq!(t.fraction(), 0.025);560assert_eq!(t.fraction_remaining(), 0.975);561// Tick past the end and make sure elapsed doesn't go past 0.0 and other things update562t.unpause();563t.tick(Duration::from_secs_f32(500.0));564assert_eq!(t.elapsed_secs(), 10.0);565assert_eq!(t.elapsed_secs_f64(), 10.0);566assert!(t.is_finished());567assert!(t.just_finished());568assert_eq!(t.times_finished_this_tick(), 1);569assert_eq!(t.fraction(), 1.0);570assert_eq!(t.fraction_remaining(), 0.0);571// Continuing to tick when finished should only change just_finished572t.tick(Duration::from_secs_f32(1.0));573assert_eq!(t.elapsed_secs(), 10.0);574assert_eq!(t.elapsed_secs_f64(), 10.0);575assert!(t.is_finished());576assert!(!t.just_finished());577assert_eq!(t.times_finished_this_tick(), 0);578assert_eq!(t.fraction(), 1.0);579assert_eq!(t.fraction_remaining(), 0.0);580}581582#[test]583fn repeating_timer() {584let mut t = Timer::from_seconds(2.0, TimerMode::Repeating);585// Tick once, check all attributes586t.tick(Duration::from_secs_f32(0.75));587assert_eq!(t.elapsed_secs(), 0.75);588assert_eq!(t.elapsed_secs_f64(), 0.75);589assert_eq!(t.duration(), Duration::from_secs_f32(2.0));590assert!(!t.is_finished());591assert!(!t.just_finished());592assert_eq!(t.times_finished_this_tick(), 0);593assert_eq!(t.mode(), TimerMode::Repeating);594assert_eq!(t.fraction(), 0.375);595assert_eq!(t.fraction_remaining(), 0.625);596// Tick past the end and make sure elapsed wraps597t.tick(Duration::from_secs_f32(1.5));598assert_eq!(t.elapsed_secs(), 0.25);599assert_eq!(t.elapsed_secs_f64(), 0.25);600assert!(t.is_finished());601assert!(t.just_finished());602assert_eq!(t.times_finished_this_tick(), 1);603assert_eq!(t.fraction(), 0.125);604assert_eq!(t.fraction_remaining(), 0.875);605// Continuing to tick should turn off both finished & just_finished for repeating timers606t.tick(Duration::from_secs_f32(1.0));607assert_eq!(t.elapsed_secs(), 1.25);608assert_eq!(t.elapsed_secs_f64(), 1.25);609assert!(!t.is_finished());610assert!(!t.just_finished());611assert_eq!(t.times_finished_this_tick(), 0);612assert_eq!(t.fraction(), 0.625);613assert_eq!(t.fraction_remaining(), 0.375);614}615616#[test]617fn times_finished_repeating() {618let mut t = Timer::from_seconds(1.0, TimerMode::Repeating);619assert_eq!(t.times_finished_this_tick(), 0);620t.tick(Duration::from_secs_f32(3.5));621assert_eq!(t.times_finished_this_tick(), 3);622assert_eq!(t.elapsed_secs(), 0.5);623assert_eq!(t.elapsed_secs_f64(), 0.5);624assert!(t.is_finished());625assert!(t.just_finished());626t.tick(Duration::from_secs_f32(0.2));627assert_eq!(t.times_finished_this_tick(), 0);628}629630#[test]631fn times_finished_this_tick() {632let mut t = Timer::from_seconds(1.0, TimerMode::Once);633assert_eq!(t.times_finished_this_tick(), 0);634t.tick(Duration::from_secs_f32(1.5));635assert_eq!(t.times_finished_this_tick(), 1);636t.tick(Duration::from_secs_f32(0.5));637assert_eq!(t.times_finished_this_tick(), 0);638}639640#[test]641fn times_finished_this_tick_repeating_zero_duration() {642let mut t = Timer::from_seconds(0.0, TimerMode::Repeating);643assert_eq!(t.times_finished_this_tick(), 0);644assert_eq!(t.elapsed(), Duration::ZERO);645assert_eq!(t.fraction(), 1.0);646t.tick(Duration::from_secs(1));647assert_eq!(t.times_finished_this_tick(), u32::MAX);648assert_eq!(t.elapsed(), Duration::ZERO);649assert_eq!(t.fraction(), 1.0);650t.tick(Duration::from_secs(2));651assert_eq!(t.times_finished_this_tick(), u32::MAX);652assert_eq!(t.elapsed(), Duration::ZERO);653assert_eq!(t.fraction(), 1.0);654t.reset();655assert_eq!(t.times_finished_this_tick(), 0);656assert_eq!(t.elapsed(), Duration::ZERO);657assert_eq!(t.fraction(), 1.0);658}659660#[test]661fn times_finished_this_tick_precise() {662let mut t = Timer::from_seconds(0.01, TimerMode::Repeating);663let duration = Duration::from_secs_f64(0.333);664665// total duration: 0.333 => 33 times finished666t.tick(duration);667assert_eq!(t.times_finished_this_tick(), 33);668// total duration: 0.666 => 33 times finished669t.tick(duration);670assert_eq!(t.times_finished_this_tick(), 33);671// total duration: 0.999 => 33 times finished672t.tick(duration);673assert_eq!(t.times_finished_this_tick(), 33);674// total duration: 1.332 => 34 times finished675t.tick(duration);676assert_eq!(t.times_finished_this_tick(), 34);677}678679#[test]680fn paused() {681let mut t = Timer::from_seconds(10.0, TimerMode::Once);682683t.tick(Duration::from_secs_f32(10.0));684assert!(t.just_finished());685assert!(t.is_finished());686// A paused timer should change just_finished to false after a tick687t.pause();688t.tick(Duration::from_secs_f32(5.0));689assert!(!t.just_finished());690assert!(t.is_finished());691}692693#[test]694fn paused_repeating() {695let mut t = Timer::from_seconds(10.0, TimerMode::Repeating);696697t.tick(Duration::from_secs_f32(10.0));698assert!(t.just_finished());699assert!(t.is_finished());700// A paused repeating timer should change finished and just_finished to false after a tick701t.pause();702t.tick(Duration::from_secs_f32(5.0));703assert!(!t.just_finished());704assert!(!t.is_finished());705}706}707708709