729 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			729 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use bevy_ecs::{reflect::ReflectResource, system::Resource};
 | |
| use bevy_reflect::{FromReflect, Reflect};
 | |
| use bevy_utils::{Duration, Instant};
 | |
| 
 | |
| /// A clock that tracks how much it has advanced (and how much real time has elapsed) since
 | |
| /// its previous update and since its creation.
 | |
| #[derive(Resource, Reflect, FromReflect, Debug, Clone)]
 | |
| #[reflect(Resource)]
 | |
| pub struct Time {
 | |
|     startup: Instant,
 | |
|     first_update: Option<Instant>,
 | |
|     last_update: Option<Instant>,
 | |
|     // pausing
 | |
|     paused: bool,
 | |
|     // scaling
 | |
|     relative_speed: f64, // using `f64` instead of `f32` to minimize drift from rounding errors
 | |
|     delta: Duration,
 | |
|     delta_seconds: f32,
 | |
|     delta_seconds_f64: f64,
 | |
|     elapsed: Duration,
 | |
|     elapsed_seconds: f32,
 | |
|     elapsed_seconds_f64: f64,
 | |
|     raw_delta: Duration,
 | |
|     raw_delta_seconds: f32,
 | |
|     raw_delta_seconds_f64: f64,
 | |
|     raw_elapsed: Duration,
 | |
|     raw_elapsed_seconds: f32,
 | |
|     raw_elapsed_seconds_f64: f64,
 | |
|     // wrapping
 | |
|     wrap_period: Duration,
 | |
|     elapsed_wrapped: Duration,
 | |
|     elapsed_seconds_wrapped: f32,
 | |
|     elapsed_seconds_wrapped_f64: f64,
 | |
|     raw_elapsed_wrapped: Duration,
 | |
|     raw_elapsed_seconds_wrapped: f32,
 | |
|     raw_elapsed_seconds_wrapped_f64: f64,
 | |
| }
 | |
| 
 | |
| impl Default for Time {
 | |
|     fn default() -> Self {
 | |
|         Self {
 | |
|             startup: Instant::now(),
 | |
|             first_update: None,
 | |
|             last_update: None,
 | |
|             paused: false,
 | |
|             relative_speed: 1.0,
 | |
|             delta: Duration::ZERO,
 | |
|             delta_seconds: 0.0,
 | |
|             delta_seconds_f64: 0.0,
 | |
|             elapsed: Duration::ZERO,
 | |
|             elapsed_seconds: 0.0,
 | |
|             elapsed_seconds_f64: 0.0,
 | |
|             raw_delta: Duration::ZERO,
 | |
|             raw_delta_seconds: 0.0,
 | |
|             raw_delta_seconds_f64: 0.0,
 | |
|             raw_elapsed: Duration::ZERO,
 | |
|             raw_elapsed_seconds: 0.0,
 | |
|             raw_elapsed_seconds_f64: 0.0,
 | |
|             wrap_period: Duration::from_secs(3600), // 1 hour
 | |
|             elapsed_wrapped: Duration::ZERO,
 | |
|             elapsed_seconds_wrapped: 0.0,
 | |
|             elapsed_seconds_wrapped_f64: 0.0,
 | |
|             raw_elapsed_wrapped: Duration::ZERO,
 | |
|             raw_elapsed_seconds_wrapped: 0.0,
 | |
|             raw_elapsed_seconds_wrapped_f64: 0.0,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl Time {
 | |
|     /// Constructs a new `Time` instance with a specific startup `Instant`.
 | |
|     pub fn new(startup: Instant) -> Self {
 | |
|         Self {
 | |
|             startup,
 | |
|             ..Default::default()
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Updates the internal time measurements.
 | |
|     ///
 | |
|     /// Calling this method as part of your app will most likely result in inaccurate timekeeping,
 | |
|     /// as the `Time` resource is ordinarily managed by the [`TimePlugin`](crate::TimePlugin).
 | |
|     pub fn update(&mut self) {
 | |
|         let now = Instant::now();
 | |
|         self.update_with_instant(now);
 | |
|     }
 | |
| 
 | |
|     /// Updates time with a specified [`Instant`].
 | |
|     ///
 | |
|     /// This method is provided for use in tests. Calling this method as part of your app will most
 | |
|     /// likely result in inaccurate timekeeping, as the `Time` resource is ordinarily managed by the
 | |
|     /// [`TimePlugin`](crate::TimePlugin).
 | |
|     ///
 | |
|     /// # Examples
 | |
|     ///
 | |
|     /// ```
 | |
|     /// # use bevy_time::prelude::*;
 | |
|     /// # use bevy_ecs::prelude::*;
 | |
|     /// # use bevy_utils::Duration;
 | |
|     /// # fn main () {
 | |
|     /// #     test_health_system();
 | |
|     /// # }
 | |
|     /// #[derive(Resource)]
 | |
|     /// struct Health {
 | |
|     ///     // Health value between 0.0 and 1.0
 | |
|     ///     health_value: f32,
 | |
|     /// }
 | |
|     ///
 | |
|     /// fn health_system(time: Res<Time>, mut health: ResMut<Health>) {
 | |
|     ///     // Increase health value by 0.1 per second, independent of frame rate,
 | |
|     ///     // but not beyond 1.0
 | |
|     ///     health.health_value = (health.health_value + 0.1 * time.delta_seconds()).min(1.0);
 | |
|     /// }
 | |
|     ///
 | |
|     /// // Mock time in tests
 | |
|     /// fn test_health_system() {
 | |
|     ///     let mut world = World::default();
 | |
|     ///     let mut time = Time::default();
 | |
|     ///     time.update();
 | |
|     ///     world.insert_resource(time);
 | |
|     ///     world.insert_resource(Health { health_value: 0.2 });
 | |
|     ///
 | |
|     ///     let mut update_stage = SystemStage::single_threaded();
 | |
|     ///     update_stage.add_system(health_system);
 | |
|     ///
 | |
|     ///     // Simulate that 30 ms have passed
 | |
|     ///     let mut time = world.resource_mut::<Time>();
 | |
|     ///     let last_update = time.last_update().unwrap();
 | |
|     ///     time.update_with_instant(last_update + Duration::from_millis(30));
 | |
|     ///
 | |
|     ///     // Run system
 | |
|     ///     update_stage.run(&mut world);
 | |
|     ///
 | |
|     ///     // Check that 0.003 has been added to the health value
 | |
|     ///     let expected_health_value = 0.2 + 0.1 * 0.03;
 | |
|     ///     let actual_health_value = world.resource::<Health>().health_value;
 | |
|     ///     assert_eq!(expected_health_value, actual_health_value);
 | |
|     /// }
 | |
|     /// ```
 | |
|     pub fn update_with_instant(&mut self, instant: Instant) {
 | |
|         let raw_delta = instant - self.last_update.unwrap_or(self.startup);
 | |
|         let delta = if self.paused {
 | |
|             Duration::ZERO
 | |
|         } else if self.relative_speed != 1.0 {
 | |
|             raw_delta.mul_f64(self.relative_speed)
 | |
|         } else {
 | |
|             // avoid rounding when at normal speed
 | |
|             raw_delta
 | |
|         };
 | |
| 
 | |
|         if self.last_update.is_some() {
 | |
|             self.delta = delta;
 | |
|             self.delta_seconds = self.delta.as_secs_f32();
 | |
|             self.delta_seconds_f64 = self.delta.as_secs_f64();
 | |
|             self.raw_delta = raw_delta;
 | |
|             self.raw_delta_seconds = self.raw_delta.as_secs_f32();
 | |
|             self.raw_delta_seconds_f64 = self.raw_delta.as_secs_f64();
 | |
|         } else {
 | |
|             self.first_update = Some(instant);
 | |
|         }
 | |
| 
 | |
|         self.elapsed += delta;
 | |
|         self.elapsed_seconds = self.elapsed.as_secs_f32();
 | |
|         self.elapsed_seconds_f64 = self.elapsed.as_secs_f64();
 | |
|         self.raw_elapsed += raw_delta;
 | |
|         self.raw_elapsed_seconds = self.raw_elapsed.as_secs_f32();
 | |
|         self.raw_elapsed_seconds_f64 = self.raw_elapsed.as_secs_f64();
 | |
| 
 | |
|         self.elapsed_wrapped = duration_div_rem(self.elapsed, self.wrap_period).1;
 | |
|         self.elapsed_seconds_wrapped = self.elapsed_wrapped.as_secs_f32();
 | |
|         self.elapsed_seconds_wrapped_f64 = self.elapsed_wrapped.as_secs_f64();
 | |
|         self.raw_elapsed_wrapped = duration_div_rem(self.raw_elapsed, self.wrap_period).1;
 | |
|         self.raw_elapsed_seconds_wrapped = self.raw_elapsed_wrapped.as_secs_f32();
 | |
|         self.raw_elapsed_seconds_wrapped_f64 = self.raw_elapsed_wrapped.as_secs_f64();
 | |
| 
 | |
|         self.last_update = Some(instant);
 | |
|     }
 | |
| 
 | |
|     /// Returns the [`Instant`] the clock was created.
 | |
|     ///
 | |
|     /// This usually represents when the app was started.
 | |
|     #[inline]
 | |
|     pub fn startup(&self) -> Instant {
 | |
|         self.startup
 | |
|     }
 | |
| 
 | |
|     /// Returns the [`Instant`] when [`update`](#method.update) was first called, if it exists.
 | |
|     ///
 | |
|     /// This usually represents when the first app update started.
 | |
|     #[inline]
 | |
|     pub fn first_update(&self) -> Option<Instant> {
 | |
|         self.first_update
 | |
|     }
 | |
| 
 | |
|     /// Returns the [`Instant`] when [`update`](#method.update) was last called, if it exists.
 | |
|     ///
 | |
|     /// This usually represents when the current app update started.
 | |
|     #[inline]
 | |
|     pub fn last_update(&self) -> Option<Instant> {
 | |
|         self.last_update
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since the last [`update`](#method.update), as a [`Duration`].
 | |
|     #[inline]
 | |
|     pub fn delta(&self) -> Duration {
 | |
|         self.delta
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since the last [`update`](#method.update), as [`f32`] seconds.
 | |
|     #[inline]
 | |
|     pub fn delta_seconds(&self) -> f32 {
 | |
|         self.delta_seconds
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since the last [`update`](#method.update), as [`f64`] seconds.
 | |
|     #[inline]
 | |
|     pub fn delta_seconds_f64(&self) -> f64 {
 | |
|         self.delta_seconds_f64
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since [`startup`](#method.startup), as [`Duration`].
 | |
|     #[inline]
 | |
|     pub fn elapsed(&self) -> Duration {
 | |
|         self.elapsed
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since [`startup`](#method.startup), as [`f32`] seconds.
 | |
|     ///
 | |
|     /// **Note:** This is a monotonically increasing value. It's precision will degrade over time.
 | |
|     /// If you need an `f32` but that precision loss is unacceptable,
 | |
|     /// use [`elapsed_seconds_wrapped`](#method.elapsed_seconds_wrapped).
 | |
|     #[inline]
 | |
|     pub fn elapsed_seconds(&self) -> f32 {
 | |
|         self.elapsed_seconds
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since [`startup`](#method.startup), as [`f64`] seconds.
 | |
|     #[inline]
 | |
|     pub fn elapsed_seconds_f64(&self) -> f64 {
 | |
|         self.elapsed_seconds_f64
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since [`startup`](#method.startup) modulo
 | |
|     /// the [`wrap_period`](#method.wrap_period), as [`Duration`].
 | |
|     #[inline]
 | |
|     pub fn elapsed_wrapped(&self) -> Duration {
 | |
|         self.elapsed_wrapped
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since [`startup`](#method.startup) modulo
 | |
|     /// the [`wrap_period`](#method.wrap_period), as [`f32`] seconds.
 | |
|     ///
 | |
|     /// This method is intended for applications (e.g. shaders) that require an [`f32`] value but
 | |
|     /// suffer from the gradual precision loss of [`elapsed_seconds`](#method.elapsed_seconds).
 | |
|     #[inline]
 | |
|     pub fn elapsed_seconds_wrapped(&self) -> f32 {
 | |
|         self.elapsed_seconds_wrapped
 | |
|     }
 | |
| 
 | |
|     /// Returns how much time has advanced since [`startup`](#method.startup) modulo
 | |
|     /// the [`wrap_period`](#method.wrap_period), as [`f64`] seconds.
 | |
|     #[inline]
 | |
|     pub fn elapsed_seconds_wrapped_f64(&self) -> f64 {
 | |
|         self.elapsed_seconds_wrapped_f64
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since the last [`update`](#method.update), as a [`Duration`].
 | |
|     #[inline]
 | |
|     pub fn raw_delta(&self) -> Duration {
 | |
|         self.raw_delta
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since the last [`update`](#method.update), as [`f32`] seconds.
 | |
|     #[inline]
 | |
|     pub fn raw_delta_seconds(&self) -> f32 {
 | |
|         self.raw_delta_seconds
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since the last [`update`](#method.update), as [`f64`] seconds.
 | |
|     #[inline]
 | |
|     pub fn raw_delta_seconds_f64(&self) -> f64 {
 | |
|         self.raw_delta_seconds_f64
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since [`startup`](#method.startup), as [`Duration`].
 | |
|     #[inline]
 | |
|     pub fn raw_elapsed(&self) -> Duration {
 | |
|         self.raw_elapsed
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since [`startup`](#method.startup), as [`f32`] seconds.
 | |
|     ///
 | |
|     /// **Note:** This is a monotonically increasing value. It's precision will degrade over time.
 | |
|     /// If you need an `f32` but that precision loss is unacceptable,
 | |
|     /// use [`raw_elapsed_seconds_wrapped`](#method.raw_elapsed_seconds_wrapped).
 | |
|     #[inline]
 | |
|     pub fn raw_elapsed_seconds(&self) -> f32 {
 | |
|         self.raw_elapsed_seconds
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since [`startup`](#method.startup), as [`f64`] seconds.
 | |
|     #[inline]
 | |
|     pub fn raw_elapsed_seconds_f64(&self) -> f64 {
 | |
|         self.raw_elapsed_seconds_f64
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since [`startup`](#method.startup) modulo
 | |
|     /// the [`wrap_period`](#method.wrap_period), as [`Duration`].
 | |
|     #[inline]
 | |
|     pub fn raw_elapsed_wrapped(&self) -> Duration {
 | |
|         self.raw_elapsed_wrapped
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since [`startup`](#method.startup) modulo
 | |
|     /// the [`wrap_period`](#method.wrap_period), as [`f32`] seconds.
 | |
|     ///
 | |
|     /// This method is intended for applications (e.g. shaders) that require an [`f32`] value but
 | |
|     /// suffer from the gradual precision loss of [`raw_elapsed_seconds`](#method.raw_elapsed_seconds).
 | |
|     #[inline]
 | |
|     pub fn raw_elapsed_seconds_wrapped(&self) -> f32 {
 | |
|         self.raw_elapsed_seconds_wrapped
 | |
|     }
 | |
| 
 | |
|     /// Returns how much real time has elapsed since [`startup`](#method.startup) modulo
 | |
|     /// the [`wrap_period`](#method.wrap_period), as [`f64`] seconds.
 | |
|     #[inline]
 | |
|     pub fn raw_elapsed_seconds_wrapped_f64(&self) -> f64 {
 | |
|         self.raw_elapsed_seconds_wrapped_f64
 | |
|     }
 | |
| 
 | |
|     /// Returns the modulus used to calculate [`elapsed_wrapped`](#method.elapsed_wrapped) and
 | |
|     /// [`raw_elapsed_wrapped`](#method.raw_elapsed_wrapped).
 | |
|     ///
 | |
|     /// **Note:** The default modulus is one hour.
 | |
|     #[inline]
 | |
|     pub fn wrap_period(&self) -> Duration {
 | |
|         self.wrap_period
 | |
|     }
 | |
| 
 | |
|     /// Sets the modulus used to calculate [`elapsed_wrapped`](#method.elapsed_wrapped) and
 | |
|     /// [`raw_elapsed_wrapped`](#method.raw_elapsed_wrapped).
 | |
|     ///
 | |
|     /// **Note:** This will not take effect until the next update.
 | |
|     ///
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `wrap_period` is a zero-length duration.
 | |
|     #[inline]
 | |
|     pub fn set_wrap_period(&mut self, wrap_period: Duration) {
 | |
|         assert!(!wrap_period.is_zero(), "division by zero");
 | |
|         self.wrap_period = wrap_period;
 | |
|     }
 | |
| 
 | |
|     /// Returns the speed the clock advances relative to your system clock, as [`f32`].
 | |
|     /// This is known as "time scaling" or "time dilation" in other engines.
 | |
|     ///
 | |
|     /// **Note:** This function will return zero when time is paused.
 | |
|     #[inline]
 | |
|     pub fn relative_speed(&self) -> f32 {
 | |
|         self.relative_speed_f64() as f32
 | |
|     }
 | |
| 
 | |
|     /// Returns the speed the clock advances relative to your system clock, as [`f64`].
 | |
|     /// This is known as "time scaling" or "time dilation" in other engines.
 | |
|     ///
 | |
|     /// **Note:** This function will return zero when time is paused.
 | |
|     #[inline]
 | |
|     pub fn relative_speed_f64(&self) -> f64 {
 | |
|         if self.paused {
 | |
|             0.0
 | |
|         } else {
 | |
|             self.relative_speed
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Sets the speed the clock advances relative to your system clock, given as an [`f32`].
 | |
|     ///
 | |
|     /// For example, setting this to `2.0` will make the clock advance twice as fast as your system clock.
 | |
|     ///
 | |
|     /// **Note:** This does not affect the `raw_*` measurements.
 | |
|     ///
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `ratio` is negative or not finite.
 | |
|     #[inline]
 | |
|     pub fn set_relative_speed(&mut self, ratio: f32) {
 | |
|         self.set_relative_speed_f64(ratio as f64);
 | |
|     }
 | |
| 
 | |
|     /// Sets the speed the clock advances relative to your system clock, given as an [`f64`].
 | |
|     ///
 | |
|     /// For example, setting this to `2.0` will make the clock advance twice as fast as your system clock.
 | |
|     ///
 | |
|     /// **Note:** This does not affect the `raw_*` measurements.
 | |
|     ///
 | |
|     /// # Panics
 | |
|     ///
 | |
|     /// Panics if `ratio` is negative or not finite.
 | |
|     #[inline]
 | |
|     pub fn set_relative_speed_f64(&mut self, ratio: f64) {
 | |
|         assert!(ratio.is_finite(), "tried to go infinitely fast");
 | |
|         assert!(ratio.is_sign_positive(), "tried to go back in time");
 | |
|         self.relative_speed = ratio;
 | |
|     }
 | |
| 
 | |
|     /// Stops the clock, preventing it from advancing until resumed.
 | |
|     ///
 | |
|     /// **Note:** This does affect the `raw_*` measurements.
 | |
|     #[inline]
 | |
|     pub fn pause(&mut self) {
 | |
|         self.paused = true;
 | |
|     }
 | |
| 
 | |
|     /// Resumes the clock if paused.
 | |
|     #[inline]
 | |
|     pub fn unpause(&mut self) {
 | |
|         self.paused = false;
 | |
|     }
 | |
| 
 | |
|     /// Returns `true` if the clock is currently paused.
 | |
|     #[inline]
 | |
|     pub fn is_paused(&self) -> bool {
 | |
|         self.paused
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn duration_div_rem(dividend: Duration, divisor: Duration) -> (u32, Duration) {
 | |
|     // `Duration` does not have a built-in modulo operation
 | |
|     let quotient = (dividend.as_nanos() / divisor.as_nanos()) as u32;
 | |
|     let remainder = dividend - (quotient * divisor);
 | |
|     (quotient, remainder)
 | |
| }
 | |
| 
 | |
| #[cfg(test)]
 | |
| #[allow(clippy::float_cmp)]
 | |
| mod tests {
 | |
|     use super::Time;
 | |
|     use bevy_utils::{Duration, Instant};
 | |
| 
 | |
|     fn assert_float_eq(a: f32, b: f32) {
 | |
|         assert!((a - b).abs() <= f32::EPSILON, "{a} != {b}");
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn update_test() {
 | |
|         let start_instant = Instant::now();
 | |
|         let mut time = Time::new(start_instant);
 | |
| 
 | |
|         // Ensure `time` was constructed correctly.
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), None);
 | |
|         assert_eq!(time.last_update(), None);
 | |
|         assert_eq!(time.relative_speed(), 1.0);
 | |
|         assert_eq!(time.delta(), Duration::ZERO);
 | |
|         assert_eq!(time.delta_seconds(), 0.0);
 | |
|         assert_eq!(time.delta_seconds_f64(), 0.0);
 | |
|         assert_eq!(time.raw_delta(), Duration::ZERO);
 | |
|         assert_eq!(time.raw_delta_seconds(), 0.0);
 | |
|         assert_eq!(time.raw_delta_seconds_f64(), 0.0);
 | |
|         assert_eq!(time.elapsed(), Duration::ZERO);
 | |
|         assert_eq!(time.elapsed_seconds(), 0.0);
 | |
|         assert_eq!(time.elapsed_seconds_f64(), 0.0);
 | |
|         assert_eq!(time.raw_elapsed(), Duration::ZERO);
 | |
|         assert_eq!(time.raw_elapsed_seconds(), 0.0);
 | |
|         assert_eq!(time.raw_elapsed_seconds_f64(), 0.0);
 | |
| 
 | |
|         // Update `time` and check results.
 | |
|         // The first update to `time` normally happens before other systems have run,
 | |
|         // so the first delta doesn't appear until the second update.
 | |
|         let first_update_instant = Instant::now();
 | |
|         time.update_with_instant(first_update_instant);
 | |
| 
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.last_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.relative_speed(), 1.0);
 | |
|         assert_eq!(time.delta(), Duration::ZERO);
 | |
|         assert_eq!(time.delta_seconds(), 0.0);
 | |
|         assert_eq!(time.delta_seconds_f64(), 0.0);
 | |
|         assert_eq!(time.raw_delta(), Duration::ZERO);
 | |
|         assert_eq!(time.raw_delta_seconds(), 0.0);
 | |
|         assert_eq!(time.raw_delta_seconds_f64(), 0.0);
 | |
|         assert_eq!(time.elapsed(), first_update_instant - start_instant,);
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds(),
 | |
|             (first_update_instant - start_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds_f64(),
 | |
|             (first_update_instant - start_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(time.raw_elapsed(), first_update_instant - start_instant,);
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds(),
 | |
|             (first_update_instant - start_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds_f64(),
 | |
|             (first_update_instant - start_instant).as_secs_f64(),
 | |
|         );
 | |
| 
 | |
|         // Update `time` again and check results.
 | |
|         // At this point its safe to use time.delta().
 | |
|         let second_update_instant = Instant::now();
 | |
|         time.update_with_instant(second_update_instant);
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.last_update(), Some(second_update_instant));
 | |
|         assert_eq!(time.relative_speed(), 1.0);
 | |
|         assert_eq!(time.delta(), second_update_instant - first_update_instant);
 | |
|         assert_eq!(
 | |
|             time.delta_seconds(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.delta_seconds_f64(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_delta(),
 | |
|             second_update_instant - first_update_instant,
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_delta_seconds(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_delta_seconds_f64(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(time.elapsed(), second_update_instant - start_instant,);
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds(),
 | |
|             (second_update_instant - start_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds_f64(),
 | |
|             (second_update_instant - start_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(time.raw_elapsed(), second_update_instant - start_instant,);
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds(),
 | |
|             (second_update_instant - start_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds_f64(),
 | |
|             (second_update_instant - start_instant).as_secs_f64(),
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn wrapping_test() {
 | |
|         let start_instant = Instant::now();
 | |
| 
 | |
|         let mut time = Time {
 | |
|             startup: start_instant,
 | |
|             wrap_period: Duration::from_secs(3),
 | |
|             ..Default::default()
 | |
|         };
 | |
| 
 | |
|         assert_eq!(time.elapsed_seconds_wrapped(), 0.0);
 | |
| 
 | |
|         time.update_with_instant(start_instant + Duration::from_secs(1));
 | |
|         assert_float_eq(time.elapsed_seconds_wrapped(), 1.0);
 | |
| 
 | |
|         time.update_with_instant(start_instant + Duration::from_secs(2));
 | |
|         assert_float_eq(time.elapsed_seconds_wrapped(), 2.0);
 | |
| 
 | |
|         time.update_with_instant(start_instant + Duration::from_secs(3));
 | |
|         assert_float_eq(time.elapsed_seconds_wrapped(), 0.0);
 | |
| 
 | |
|         time.update_with_instant(start_instant + Duration::from_secs(4));
 | |
|         assert_float_eq(time.elapsed_seconds_wrapped(), 1.0);
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn relative_speed_test() {
 | |
|         let start_instant = Instant::now();
 | |
|         let mut time = Time::new(start_instant);
 | |
| 
 | |
|         let first_update_instant = Instant::now();
 | |
|         time.update_with_instant(first_update_instant);
 | |
| 
 | |
|         // Update `time` again and check results.
 | |
|         // At this point its safe to use time.delta().
 | |
|         let second_update_instant = Instant::now();
 | |
|         time.update_with_instant(second_update_instant);
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.last_update(), Some(second_update_instant));
 | |
|         assert_eq!(time.relative_speed(), 1.0);
 | |
|         assert_eq!(time.delta(), second_update_instant - first_update_instant);
 | |
|         assert_eq!(
 | |
|             time.delta_seconds(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.delta_seconds_f64(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_delta(),
 | |
|             second_update_instant - first_update_instant,
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_delta_seconds(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_delta_seconds_f64(),
 | |
|             (second_update_instant - first_update_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(time.elapsed(), second_update_instant - start_instant,);
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds(),
 | |
|             (second_update_instant - start_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds_f64(),
 | |
|             (second_update_instant - start_instant).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(time.raw_elapsed(), second_update_instant - start_instant,);
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds(),
 | |
|             (second_update_instant - start_instant).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds_f64(),
 | |
|             (second_update_instant - start_instant).as_secs_f64(),
 | |
|         );
 | |
| 
 | |
|         // Make app time advance at 2x the rate of your system clock.
 | |
|         time.set_relative_speed(2.0);
 | |
| 
 | |
|         // Update `time` again 1 second later.
 | |
|         let elapsed = Duration::from_secs(1);
 | |
|         let third_update_instant = second_update_instant + elapsed;
 | |
|         time.update_with_instant(third_update_instant);
 | |
| 
 | |
|         // Since app is advancing 2x your system clock, expect time
 | |
|         // to have advanced by twice the amount of real time elapsed.
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.last_update(), Some(third_update_instant));
 | |
|         assert_eq!(time.relative_speed(), 2.0);
 | |
|         assert_eq!(time.delta(), elapsed.mul_f32(2.0));
 | |
|         assert_eq!(time.delta_seconds(), elapsed.mul_f32(2.0).as_secs_f32());
 | |
|         assert_eq!(time.delta_seconds_f64(), elapsed.mul_f32(2.0).as_secs_f64());
 | |
|         assert_eq!(time.raw_delta(), elapsed);
 | |
|         assert_eq!(time.raw_delta_seconds(), elapsed.as_secs_f32());
 | |
|         assert_eq!(time.raw_delta_seconds_f64(), elapsed.as_secs_f64());
 | |
|         assert_eq!(
 | |
|             time.elapsed(),
 | |
|             second_update_instant - start_instant + elapsed.mul_f32(2.0),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds(),
 | |
|             (second_update_instant - start_instant + elapsed.mul_f32(2.0)).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.elapsed_seconds_f64(),
 | |
|             (second_update_instant - start_instant + elapsed.mul_f32(2.0)).as_secs_f64(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed(),
 | |
|             second_update_instant - start_instant + elapsed,
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds(),
 | |
|             (second_update_instant - start_instant + elapsed).as_secs_f32(),
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.raw_elapsed_seconds_f64(),
 | |
|             (second_update_instant - start_instant + elapsed).as_secs_f64(),
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     #[test]
 | |
|     fn pause_test() {
 | |
|         let start_instant = Instant::now();
 | |
|         let mut time = Time::new(start_instant);
 | |
| 
 | |
|         let first_update_instant = Instant::now();
 | |
|         time.update_with_instant(first_update_instant);
 | |
| 
 | |
|         assert!(!time.is_paused());
 | |
|         assert_eq!(time.relative_speed(), 1.0);
 | |
| 
 | |
|         time.pause();
 | |
| 
 | |
|         assert!(time.is_paused());
 | |
|         assert_eq!(time.relative_speed(), 0.0);
 | |
| 
 | |
|         let second_update_instant = Instant::now();
 | |
|         time.update_with_instant(second_update_instant);
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.last_update(), Some(second_update_instant));
 | |
|         assert_eq!(time.delta(), Duration::ZERO);
 | |
|         assert_eq!(
 | |
|             time.raw_delta(),
 | |
|             second_update_instant - first_update_instant,
 | |
|         );
 | |
|         assert_eq!(time.elapsed(), first_update_instant - start_instant);
 | |
|         assert_eq!(time.raw_elapsed(), second_update_instant - start_instant);
 | |
| 
 | |
|         time.unpause();
 | |
| 
 | |
|         assert!(!time.is_paused());
 | |
|         assert_eq!(time.relative_speed(), 1.0);
 | |
| 
 | |
|         let third_update_instant = Instant::now();
 | |
|         time.update_with_instant(third_update_instant);
 | |
|         assert_eq!(time.startup(), start_instant);
 | |
|         assert_eq!(time.first_update(), Some(first_update_instant));
 | |
|         assert_eq!(time.last_update(), Some(third_update_instant));
 | |
|         assert_eq!(time.delta(), third_update_instant - second_update_instant);
 | |
|         assert_eq!(
 | |
|             time.raw_delta(),
 | |
|             third_update_instant - second_update_instant,
 | |
|         );
 | |
|         assert_eq!(
 | |
|             time.elapsed(),
 | |
|             (third_update_instant - second_update_instant) + (first_update_instant - start_instant),
 | |
|         );
 | |
|         assert_eq!(time.raw_elapsed(), third_update_instant - start_instant);
 | |
|     }
 | |
| }
 | 
