Add global time scaling (#5752)
# Objective - Make `Time` API more consistent. - Support time accel/decel/pause. ## Solution This is just the `Time` half of #3002. I was told that part isn't controversial. - Give the "delta time" and "total elapsed time" methods `f32`, `f64`, and `Duration` variants with consistent naming. - Implement accelerating / decelerating the passage of time. - Implement stopping time. --- ## Changelog - Changed `time_since_startup` to `elapsed` because `time.time_*` is just silly. - Added `relative_speed` and `set_relative_speed` methods. - Added `is_paused`, `pause`, `unpause` , and methods. (I'd prefer `resume`, but `unpause` matches `Timer` API.) - Added `raw_*` variants of the "delta time" and "total elapsed time" methods. - Added `first_update` method because there's a non-zero duration between startup and the first update. ## Migration Guide - `time.time_since_startup()` -> `time.elapsed()` - `time.seconds_since_startup()` -> `time.elapsed_seconds_f64()` - `time.seconds_since_startup_wrapped_f32()` -> `time.elapsed_seconds_wrapped()` If you aren't sure which to use, most systems should continue to use "scaled" time (e.g. `time.delta_seconds()`). The realtime "unscaled" time measurements (e.g. `time.raw_delta_seconds()`) are mostly for debugging and profiling.
This commit is contained in:
parent
cb5e2d84be
commit
7989cb2650
@ -35,12 +35,13 @@ impl FrameTimeDiagnosticsPlugin {
|
||||
) {
|
||||
diagnostics.add_measurement(Self::FRAME_COUNT, || frame_count.0 as f64);
|
||||
|
||||
if time.delta_seconds_f64() == 0.0 {
|
||||
let delta_seconds = time.raw_delta_seconds_f64();
|
||||
if delta_seconds == 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
diagnostics.add_measurement(Self::FRAME_TIME, || time.delta_seconds_f64() * 1000.);
|
||||
diagnostics.add_measurement(Self::FRAME_TIME, || delta_seconds * 1000.0);
|
||||
|
||||
diagnostics.add_measurement(Self::FPS, || 1.0 / time.delta_seconds_f64());
|
||||
diagnostics.add_measurement(Self::FPS, || 1.0 / delta_seconds);
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ impl LogDiagnosticsPlugin {
|
||||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta()).finished() {
|
||||
if state.timer.tick(time.raw_delta()).finished() {
|
||||
if let Some(ref filter) = state.filter {
|
||||
for diagnostic in filter.iter().flat_map(|id| {
|
||||
diagnostics
|
||||
@ -110,7 +110,7 @@ impl LogDiagnosticsPlugin {
|
||||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta()).finished() {
|
||||
if state.timer.tick(time.raw_delta()).finished() {
|
||||
if let Some(ref filter) = state.filter {
|
||||
for diagnostic in filter.iter().flat_map(|id| {
|
||||
diagnostics
|
||||
|
@ -57,7 +57,7 @@ fn prepare_globals_buffer(
|
||||
frame_count: Res<FrameCount>,
|
||||
) {
|
||||
let buffer = globals_buffer.buffer.get_mut();
|
||||
buffer.time = time.seconds_since_startup_wrapped_f32();
|
||||
buffer.time = time.elapsed_seconds_wrapped();
|
||||
buffer.delta_time = time.delta_seconds();
|
||||
buffer.frame_count = frame_count.0;
|
||||
|
||||
|
@ -2,55 +2,92 @@ use bevy_ecs::{reflect::ReflectResource, system::Resource};
|
||||
use bevy_reflect::{FromReflect, Reflect};
|
||||
use bevy_utils::{Duration, Instant};
|
||||
|
||||
const SECONDS_PER_HOUR: u64 = 60 * 60;
|
||||
|
||||
/// Tracks elapsed time since the last update and since the App has started
|
||||
/// Tracks how much time has advanced (and also how much real time has elapsed) since
|
||||
/// the previous app update and since the app was started.
|
||||
#[derive(Resource, Reflect, FromReflect, Debug, Clone)]
|
||||
#[reflect(Resource)]
|
||||
pub struct Time {
|
||||
delta: Duration,
|
||||
last_update: Option<Instant>,
|
||||
delta_seconds_f64: f64,
|
||||
delta_seconds: f32,
|
||||
seconds_since_startup: f64,
|
||||
time_since_startup: Duration,
|
||||
startup: Instant,
|
||||
/// The maximum period before [`Time::seconds_since_startup_wrapped_f32`] wraps to 0
|
||||
///
|
||||
/// Defaults to 1 hour
|
||||
pub wrap_period: Duration,
|
||||
first_update: Option<Instant>,
|
||||
last_update: Option<Instant>,
|
||||
relative_speed: f64, // using `f64` instead of `f32` to minimize drift from rounding errors
|
||||
paused: bool,
|
||||
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() -> Time {
|
||||
Time {
|
||||
delta: Duration::from_secs(0),
|
||||
last_update: None,
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
startup: Instant::now(),
|
||||
delta_seconds_f64: 0.0,
|
||||
seconds_since_startup: 0.0,
|
||||
time_since_startup: Duration::from_secs(0),
|
||||
first_update: None,
|
||||
last_update: None,
|
||||
relative_speed: 1.0,
|
||||
paused: false,
|
||||
delta: Duration::ZERO,
|
||||
delta_seconds: 0.0,
|
||||
wrap_period: Duration::from_secs(SECONDS_PER_HOUR),
|
||||
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 {
|
||||
/// Updates the internal time measurements.
|
||||
///
|
||||
/// Calling this method on the [`Time`] resource as part of your app will most likely result in
|
||||
/// inaccurate timekeeping, as the resource is ordinarily managed by the
|
||||
/// [`TimePlugin`](crate::TimePlugin).
|
||||
pub fn update(&mut self) {
|
||||
self.update_with_instant(Instant::now());
|
||||
/// Constructs a new `Time` instance with a specific startup `Instant`.
|
||||
pub fn new(startup: Instant) -> Self {
|
||||
Self {
|
||||
startup,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Update time with a specified [`Instant`]
|
||||
/// Updates the internal time measurements.
|
||||
///
|
||||
/// This method is provided for use in tests. Calling this method on the [`Time`] resource as
|
||||
/// part of your app will most likely result in inaccurate timekeeping, as the resource is
|
||||
/// ordinarily managed by the [`TimePlugin`](crate::TimePlugin).
|
||||
/// 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
|
||||
///
|
||||
@ -99,75 +136,283 @@ impl Time {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn update_with_instant(&mut self, instant: Instant) {
|
||||
if let Some(last_update) = self.last_update {
|
||||
self.delta = instant - last_update;
|
||||
self.delta_seconds_f64 = self.delta.as_secs_f64();
|
||||
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 errors 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.time_since_startup = instant - self.startup;
|
||||
self.seconds_since_startup = self.time_since_startup.as_secs_f64();
|
||||
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);
|
||||
}
|
||||
|
||||
/// The delta between the current tick and last tick as a [`Duration`]
|
||||
#[inline]
|
||||
pub fn delta(&self) -> Duration {
|
||||
self.delta
|
||||
}
|
||||
|
||||
/// The delta between the current and last tick as [`f32`] seconds
|
||||
#[inline]
|
||||
pub fn delta_seconds(&self) -> f32 {
|
||||
self.delta_seconds
|
||||
}
|
||||
|
||||
/// The delta between the current and last tick as [`f64`] seconds
|
||||
#[inline]
|
||||
pub fn delta_seconds_f64(&self) -> f64 {
|
||||
self.delta_seconds_f64
|
||||
}
|
||||
|
||||
/// The time from startup to the last update in seconds
|
||||
///
|
||||
/// If you intend to cast this to an `f32` value, note that this value is monotonically increasing,
|
||||
/// and that its precision as an `f32` will noticeably degrade over time (in a matter of hours).
|
||||
/// If that precision loss is unacceptable, you should use [`Time::seconds_since_startup_wrapped_f32`],
|
||||
/// which will return the time from startup modulo a wrapping period.
|
||||
#[inline]
|
||||
pub fn seconds_since_startup(&self) -> f64 {
|
||||
self.seconds_since_startup
|
||||
}
|
||||
|
||||
/// The time from startup to the last update, modulo the [`Time::wrap_period`], in seconds.
|
||||
///
|
||||
/// Time from startup is a monotonically increasing value and so its precision when read as an `f32`
|
||||
/// will noticeably degrade over time, which causes issues for some uses, e.g. shaders.
|
||||
/// This method avoids noticeable degradation by limiting the values to a much smaller range.
|
||||
///
|
||||
/// The default wrapping period is one hour.
|
||||
#[inline]
|
||||
pub fn seconds_since_startup_wrapped_f32(&self) -> f32 {
|
||||
(self.seconds_since_startup % self.wrap_period.as_secs_f64()) as f32
|
||||
}
|
||||
|
||||
/// The [`Instant`] the app was started
|
||||
/// Returns the [`Instant`] the app was started.
|
||||
#[inline]
|
||||
pub fn startup(&self) -> Instant {
|
||||
self.startup
|
||||
}
|
||||
|
||||
/// The [`Instant`] when [`Time::update`] was last called, if it exists
|
||||
/// Returns the [`Instant`] when [`update`](#method.update) was first called, if it exists.
|
||||
#[inline]
|
||||
pub fn first_update(&self) -> Option<Instant> {
|
||||
self.first_update
|
||||
}
|
||||
|
||||
/// Returns the [`Instant`] when [`update`](#method.update) was last called, if it exists.
|
||||
#[inline]
|
||||
pub fn last_update(&self) -> Option<Instant> {
|
||||
self.last_update
|
||||
}
|
||||
|
||||
/// The [`Duration`] from startup to the last update
|
||||
/// Returns how much time has advanced since the last [`update`](#method.update), as a [`Duration`].
|
||||
#[inline]
|
||||
pub fn time_since_startup(&self) -> Duration {
|
||||
self.time_since_startup
|
||||
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 the exact clock time elapsed since the last [`update`](#method.update), as a [`Duration`].
|
||||
#[inline]
|
||||
pub fn raw_delta(&self) -> Duration {
|
||||
self.raw_delta
|
||||
}
|
||||
|
||||
/// Returns the exact clock time elapsed since the last [`update`](#method.update), as [`f32`] seconds.
|
||||
#[inline]
|
||||
pub fn raw_delta_seconds(&self) -> f32 {
|
||||
self.raw_delta_seconds
|
||||
}
|
||||
|
||||
/// Returns the exact clock time 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 the exact clock time elapsed since [`startup`](#method.startup), as [`Duration`].
|
||||
#[inline]
|
||||
pub fn raw_elapsed(&self) -> Duration {
|
||||
self.raw_elapsed
|
||||
}
|
||||
|
||||
/// Returns the exact clock time 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 the exact clock time elapsed since [`startup`](#method.startup), as [`f64`] seconds.
|
||||
#[inline]
|
||||
pub fn raw_elapsed_seconds_f64(&self) -> f64 {
|
||||
self.raw_elapsed_seconds_f64
|
||||
}
|
||||
|
||||
/// Returns the exact clock time 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 the exact clock time 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 the exact clock time 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).
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `wrap_period` is zero.
|
||||
#[inline]
|
||||
pub fn set_wrap_period(&mut self, wrap_period: Duration) {
|
||||
assert!(wrap_period != Duration::ZERO, "division by zero");
|
||||
self.wrap_period = wrap_period;
|
||||
}
|
||||
|
||||
/// Returns the rate that time advances relative to real time, as [`f32`].
|
||||
/// You might recognize this 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 rate that time advances relative to real time, as [`f64`].
|
||||
/// You might recognize this 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 rate that time advances relative to real time, given as an [`f32`].
|
||||
///
|
||||
/// For example, if set to `2.0`, time will advance twice as fast as your system clock.
|
||||
///
|
||||
/// # 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 rate that time advances relative to real time, given as an [`f64`].
|
||||
///
|
||||
/// For example, if set to `2.0`, time will advance twice as fast as your system clock.
|
||||
///
|
||||
/// # 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 time, preventing it from advancing until resumed. Does not affect raw measurements.
|
||||
#[inline]
|
||||
pub fn pause(&mut self) {
|
||||
self.paused = true;
|
||||
}
|
||||
|
||||
/// Resumes time if paused.
|
||||
#[inline]
|
||||
pub fn unpause(&mut self) {
|
||||
self.paused = false;
|
||||
}
|
||||
|
||||
/// Returns `true` if time has been 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)]
|
||||
@ -176,77 +421,119 @@ 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);
|
||||
|
||||
// Create a `Time` for testing
|
||||
let mut time = Time {
|
||||
startup: start_instant,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Ensure `time` was constructed correctly
|
||||
assert_eq!(time.delta(), Duration::from_secs(0));
|
||||
assert_eq!(time.last_update(), None);
|
||||
// Ensure `time` was constructed correctly.
|
||||
assert_eq!(time.startup(), start_instant);
|
||||
assert_eq!(time.delta_seconds_f64(), 0.0);
|
||||
assert_eq!(time.seconds_since_startup(), 0.0);
|
||||
assert_eq!(time.time_since_startup(), Duration::from_secs(0));
|
||||
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.seconds_since_startup_wrapped_f32(), 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
|
||||
// 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.delta(), Duration::from_secs(0));
|
||||
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.startup(), start_instant);
|
||||
assert_eq!(time.delta_seconds_f64(), 0.0);
|
||||
assert_eq!(
|
||||
time.seconds_since_startup(),
|
||||
(first_update_instant - start_instant).as_secs_f64()
|
||||
);
|
||||
assert_eq!(
|
||||
time.time_since_startup(),
|
||||
(first_update_instant - start_instant)
|
||||
);
|
||||
assert_eq!(time.relative_speed(), 1.0);
|
||||
assert_eq!(time.delta(), Duration::ZERO);
|
||||
assert_eq!(time.delta_seconds(), 0.0);
|
||||
assert_float_eq(
|
||||
time.seconds_since_startup_wrapped_f32(),
|
||||
time.seconds_since_startup() as f32,
|
||||
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
|
||||
// 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.delta(), second_update_instant - first_update_instant);
|
||||
assert_eq!(time.last_update(), Some(second_update_instant));
|
||||
assert_eq!(time.startup(), start_instant);
|
||||
// At this point its safe to use time.delta as a valid value
|
||||
// because it's been previously verified to be correct
|
||||
assert_eq!(time.delta_seconds_f64(), time.delta().as_secs_f64());
|
||||
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.seconds_since_startup(),
|
||||
(second_update_instant - start_instant).as_secs_f64()
|
||||
time.delta_seconds(),
|
||||
(second_update_instant - first_update_instant).as_secs_f32(),
|
||||
);
|
||||
assert_eq!(
|
||||
time.time_since_startup(),
|
||||
(second_update_instant - start_instant)
|
||||
time.delta_seconds_f64(),
|
||||
(second_update_instant - first_update_instant).as_secs_f64(),
|
||||
);
|
||||
assert_eq!(time.delta_seconds(), time.delta().as_secs_f32());
|
||||
assert_float_eq(
|
||||
time.seconds_since_startup_wrapped_f32(),
|
||||
time.seconds_since_startup() as f32,
|
||||
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 update_wrapping() {
|
||||
fn wrapping_test() {
|
||||
let start_instant = Instant::now();
|
||||
|
||||
let mut time = Time {
|
||||
@ -255,22 +542,171 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(time.seconds_since_startup_wrapped_f32(), 0.0);
|
||||
assert_eq!(time.elapsed_seconds_wrapped(), 0.0);
|
||||
|
||||
time.update_with_instant(start_instant + Duration::from_secs(1));
|
||||
assert_float_eq(time.seconds_since_startup_wrapped_f32(), 1.0);
|
||||
assert_float_eq(time.elapsed_seconds_wrapped(), 1.0);
|
||||
|
||||
time.update_with_instant(start_instant + Duration::from_secs(2));
|
||||
assert_float_eq(time.seconds_since_startup_wrapped_f32(), 2.0);
|
||||
assert_float_eq(time.elapsed_seconds_wrapped(), 2.0);
|
||||
|
||||
time.update_with_instant(start_instant + Duration::from_secs(3));
|
||||
assert_float_eq(time.seconds_since_startup_wrapped_f32(), 0.0);
|
||||
assert_float_eq(time.elapsed_seconds_wrapped(), 0.0);
|
||||
|
||||
time.update_with_instant(start_instant + Duration::from_secs(4));
|
||||
assert_float_eq(time.seconds_since_startup_wrapped_f32(), 1.0);
|
||||
assert_float_eq(time.elapsed_seconds_wrapped(), 1.0);
|
||||
}
|
||||
|
||||
fn assert_float_eq(a: f32, b: f32) {
|
||||
assert!((a - b).abs() <= f32::EPSILON, "{a} != {b}");
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
|
@ -96,8 +96,8 @@ fn animate_translation(
|
||||
mut query: Query<&mut Transform, (With<Text>, With<AnimateTranslation>)>,
|
||||
) {
|
||||
for mut transform in &mut query {
|
||||
transform.translation.x = 100.0 * time.seconds_since_startup().sin() as f32 - 400.0;
|
||||
transform.translation.y = 100.0 * time.seconds_since_startup().cos() as f32;
|
||||
transform.translation.x = 100.0 * time.elapsed_seconds().sin() - 400.0;
|
||||
transform.translation.y = 100.0 * time.elapsed_seconds().cos();
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,7 +106,7 @@ fn animate_rotation(
|
||||
mut query: Query<&mut Transform, (With<Text>, With<AnimateRotation>)>,
|
||||
) {
|
||||
for mut transform in &mut query {
|
||||
transform.rotation = Quat::from_rotation_z(time.seconds_since_startup().cos() as f32);
|
||||
transform.rotation = Quat::from_rotation_z(time.elapsed_seconds().cos());
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,6 +118,6 @@ fn animate_scale(
|
||||
// rendered quad, resulting in a pixellated look.
|
||||
for mut transform in &mut query {
|
||||
transform.translation = Vec3::new(400.0, 0.0, 0.0);
|
||||
transform.scale = Vec3::splat((time.seconds_since_startup().sin() as f32 + 1.1) * 2.0);
|
||||
transform.scale = Vec3::splat((time.elapsed_seconds().sin() + 1.1) * 2.0);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Loads and renders a glTF file as a scene.
|
||||
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::consts::*;
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
@ -52,8 +52,8 @@ fn animate_light_direction(
|
||||
transform.rotation = Quat::from_euler(
|
||||
EulerRot::ZYX,
|
||||
0.0,
|
||||
time.seconds_since_startup() as f32 * PI / 5.0,
|
||||
-PI / 4.,
|
||||
time.elapsed_seconds() * PI / 5.0,
|
||||
-FRAC_PI_4,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -98,16 +98,16 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
});
|
||||
}
|
||||
|
||||
const CUBEMAP_SWAP_DELAY: f64 = 3.0;
|
||||
const CUBEMAP_SWAP_DELAY: f32 = 3.0;
|
||||
|
||||
fn cycle_cubemap_asset(
|
||||
time: Res<Time>,
|
||||
mut next_swap: Local<f64>,
|
||||
mut next_swap: Local<f32>,
|
||||
mut cubemap: ResMut<Cubemap>,
|
||||
asset_server: Res<AssetServer>,
|
||||
render_device: Res<RenderDevice>,
|
||||
) {
|
||||
let now = time.seconds_since_startup();
|
||||
let now = time.elapsed_seconds();
|
||||
if *next_swap == 0.0 {
|
||||
*next_swap = now + CUBEMAP_SWAP_DELAY;
|
||||
return;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::consts::*;
|
||||
|
||||
use bevy::{
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
@ -127,11 +127,11 @@ fn light_sway(time: Res<Time>, mut query: Query<(&mut Transform, &mut SpotLight)
|
||||
for (mut transform, mut angles) in query.iter_mut() {
|
||||
transform.rotation = Quat::from_euler(
|
||||
EulerRot::XYZ,
|
||||
-PI / 2. + (time.seconds_since_startup() * 0.67 * 3.0).sin() as f32 * 0.5,
|
||||
(time.seconds_since_startup() * 3.0).sin() as f32 * 0.5,
|
||||
-FRAC_PI_2 + (time.elapsed_seconds() * 0.67 * 3.0).sin() * 0.5,
|
||||
(time.elapsed_seconds() * 3.0).sin() * 0.5,
|
||||
0.0,
|
||||
);
|
||||
let angle = ((time.seconds_since_startup() * 1.2).sin() as f32 + 1.0) * (PI / 4. - 0.1);
|
||||
let angle = ((time.elapsed_seconds() * 1.2).sin() + 1.0) * (FRAC_PI_4 - 0.1);
|
||||
angles.inner_angle = angle * 0.8;
|
||||
angles.outer_angle = angle;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ fn setup(
|
||||
/// when the alpha value goes back below the threshold.
|
||||
/// - `Blend`: Object fades in and out smoothly.
|
||||
pub fn fade_transparency(time: Res<Time>, mut materials: ResMut<Assets<StandardMaterial>>) {
|
||||
let alpha = (time.time_since_startup().as_secs_f32().sin() / 2.0) + 0.5;
|
||||
let alpha = (time.elapsed_seconds().sin() / 2.0) + 0.5;
|
||||
for (_, material) in materials.iter_mut() {
|
||||
material.base_color.set_a(alpha);
|
||||
}
|
||||
|
@ -54,9 +54,9 @@ fn move_scene_entities(
|
||||
iter_hierarchy(moved_scene_entity, &children, &mut |entity| {
|
||||
if let Ok(mut transform) = transforms.get_mut(entity) {
|
||||
transform.translation = Vec3::new(
|
||||
offset * time.seconds_since_startup().sin() as f32 / 20.,
|
||||
offset * time.elapsed_seconds().sin() / 20.,
|
||||
0.,
|
||||
time.seconds_since_startup().cos() as f32 / 20.,
|
||||
time.elapsed_seconds().cos() / 20.,
|
||||
);
|
||||
offset += 1.0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Skinned mesh example with mesh and joints data defined in code.
|
||||
//! Example taken from <https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md>
|
||||
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::consts::*;
|
||||
|
||||
use bevy::{
|
||||
pbr::AmbientLight,
|
||||
@ -162,7 +162,6 @@ fn setup(
|
||||
/// Animate the joint marked with [`AnimatedJoint`] component.
|
||||
fn joint_animation(time: Res<Time>, mut query: Query<&mut Transform, With<AnimatedJoint>>) {
|
||||
for mut transform in &mut query {
|
||||
transform.rotation =
|
||||
Quat::from_rotation_z(PI / 2. * time.time_since_startup().as_secs_f32().sin());
|
||||
transform.rotation = Quat::from_rotation_z(FRAC_PI_2 * time.elapsed_seconds().sin());
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Skinned mesh example with mesh and joints data loaded from a glTF file.
|
||||
//! Example taken from <https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md>
|
||||
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::consts::*;
|
||||
|
||||
use bevy::{pbr::AmbientLight, prelude::*, render::mesh::skinning::SkinnedMesh};
|
||||
|
||||
@ -67,6 +67,6 @@ fn joint_animation(
|
||||
let mut second_joint_transform = transform_query.get_mut(second_joint_entity).unwrap();
|
||||
|
||||
second_joint_transform.rotation =
|
||||
Quat::from_rotation_z(PI / 2. * time.time_since_startup().as_secs_f32().sin());
|
||||
Quat::from_rotation_z(FRAC_PI_2 * time.elapsed_seconds().sin());
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ fn update_speed(
|
||||
time: Res<Time>,
|
||||
) {
|
||||
if let Some(sink) = audio_sinks.get(&music_controller.0) {
|
||||
sink.set_speed(((time.seconds_since_startup() / 5.0).sin() as f32 + 1.0).max(0.1));
|
||||
sink.set_speed(((time.elapsed_seconds() / 5.0).sin() + 1.0).max(0.1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ fn main() {
|
||||
}
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
struct MyComponent(f64);
|
||||
struct MyComponent(f32);
|
||||
|
||||
fn setup(mut commands: Commands) {
|
||||
commands.spawn(MyComponent(0.));
|
||||
@ -25,7 +25,7 @@ fn change_component(time: Res<Time>, mut query: Query<(Entity, &mut MyComponent)
|
||||
for (entity, mut component) in &mut query {
|
||||
if rand::thread_rng().gen_bool(0.1) {
|
||||
info!("changing component {:?}", entity);
|
||||
component.0 = time.seconds_since_startup();
|
||||
component.0 = time.elapsed_seconds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,22 +31,30 @@ fn main() {
|
||||
.run();
|
||||
}
|
||||
|
||||
fn frame_update(mut last_time: Local<f64>, time: Res<Time>) {
|
||||
info!("update: {}", time.seconds_since_startup() - *last_time);
|
||||
*last_time = time.seconds_since_startup();
|
||||
fn frame_update(mut last_time: Local<f32>, time: Res<Time>) {
|
||||
info!(
|
||||
"time since last frame_update: {}",
|
||||
time.raw_elapsed_seconds() - *last_time
|
||||
);
|
||||
*last_time = time.raw_elapsed_seconds();
|
||||
}
|
||||
|
||||
fn fixed_update(mut last_time: Local<f64>, time: Res<Time>, fixed_timesteps: Res<FixedTimesteps>) {
|
||||
fn fixed_update(mut last_time: Local<f32>, time: Res<Time>, fixed_timesteps: Res<FixedTimesteps>) {
|
||||
info!(
|
||||
"fixed_update: {}",
|
||||
time.seconds_since_startup() - *last_time,
|
||||
"time since last fixed_update: {}\n",
|
||||
time.raw_elapsed_seconds() - *last_time
|
||||
);
|
||||
|
||||
let fixed_timestep = fixed_timesteps.get(LABEL).unwrap();
|
||||
info!(
|
||||
" overstep_percentage: {}",
|
||||
fixed_timestep.overstep_percentage()
|
||||
);
|
||||
let state = fixed_timesteps.get(LABEL).unwrap();
|
||||
|
||||
*last_time = time.seconds_since_startup();
|
||||
info!("fixed timestep: {}\n", 0.5);
|
||||
info!(
|
||||
"time accrued toward next fixed_update: {}\n",
|
||||
state.accumulator()
|
||||
);
|
||||
info!(
|
||||
"time accrued toward next fixed_update (% of timestep): {}",
|
||||
state.overstep_percentage()
|
||||
);
|
||||
*last_time = time.raw_elapsed_seconds();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Creates a hierarchy of parents and children entities.
|
||||
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::consts::*;
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
@ -78,12 +78,12 @@ fn rotate(
|
||||
}
|
||||
|
||||
// To demonstrate removing children, we'll remove a child after a couple of seconds.
|
||||
if time.seconds_since_startup() >= 2.0 && children.len() == 2 {
|
||||
if time.elapsed_seconds() >= 2.0 && children.len() == 2 {
|
||||
let child = children.last().unwrap();
|
||||
commands.entity(*child).despawn_recursive();
|
||||
}
|
||||
|
||||
if time.seconds_since_startup() >= 4.0 {
|
||||
if time.elapsed_seconds() >= 4.0 {
|
||||
// This will remove the entity from its parent's list of children, as well as despawn
|
||||
// any children the entity has.
|
||||
commands.entity(parent).despawn_recursive();
|
||||
|
@ -44,7 +44,7 @@ fn remove_component(
|
||||
query: Query<Entity, With<MyComponent>>,
|
||||
) {
|
||||
// After two seconds have passed the `Component` is removed.
|
||||
if time.seconds_since_startup() > 2.0 {
|
||||
if time.elapsed_seconds() > 2.0 {
|
||||
if let Some(entity) = query.iter().next() {
|
||||
commands.entity(entity).remove::<MyComponent>();
|
||||
}
|
||||
|
@ -134,6 +134,6 @@ fn change_color(time: Res<Time>, mut query: Query<&mut Sprite>) {
|
||||
for mut sprite in &mut query {
|
||||
sprite
|
||||
.color
|
||||
.set_b((time.seconds_since_startup() * 0.5).sin() as f32 + 2.0);
|
||||
.set_b((time.elapsed_seconds() * 0.5).sin() as f32 + 2.0);
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ fn main() {
|
||||
/// Example of a run criteria.
|
||||
/// Here we only want to run for a second, then stop.
|
||||
fn run_for_a_second(time: Res<Time>, mut done: ResMut<Done>) -> ShouldRun {
|
||||
let elapsed = time.seconds_since_startup();
|
||||
let elapsed = time.elapsed_seconds();
|
||||
if elapsed < 1.0 {
|
||||
info!(
|
||||
"We should run again. Elapsed/remaining: {:.2}s/{:.2}s",
|
||||
|
@ -356,9 +356,8 @@ fn rotate_bonus(game: Res<Game>, time: Res<Time>, mut transforms: Query<&mut Tra
|
||||
if let Some(entity) = game.bonus.entity {
|
||||
if let Ok(mut cake_transform) = transforms.get_mut(entity) {
|
||||
cake_transform.rotate_y(time.delta_seconds());
|
||||
cake_transform.scale = Vec3::splat(
|
||||
1.0 + (game.score as f32 / 10.0 * time.seconds_since_startup().sin() as f32).abs(),
|
||||
);
|
||||
cake_transform.scale =
|
||||
Vec3::splat(1.0 + (game.score as f32 / 10.0 * time.elapsed_seconds().sin()).abs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ impl FromWorld for ComponentB {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let time = world.resource::<Time>();
|
||||
ComponentB {
|
||||
_time_since_startup: time.time_since_startup(),
|
||||
_time_since_startup: time.elapsed(),
|
||||
value: "Default Value".to_string(),
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use bevy::{
|
||||
scene::InstanceId,
|
||||
};
|
||||
|
||||
use std::f32::consts::PI;
|
||||
use std::f32::consts::*;
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]
|
||||
struct CameraControllerCheckSystem;
|
||||
@ -331,8 +331,8 @@ fn update_lights(
|
||||
transform.rotation = Quat::from_euler(
|
||||
EulerRot::ZYX,
|
||||
0.0,
|
||||
time.seconds_since_startup() as f32 * PI / 15.0,
|
||||
-PI / 4.,
|
||||
time.elapsed_seconds() * PI / 15.0,
|
||||
-FRAC_PI_4,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
|
||||
fn text_color_system(time: Res<Time>, mut query: Query<&mut Text, With<ColorText>>) {
|
||||
for mut text in &mut query {
|
||||
let seconds = time.seconds_since_startup() as f32;
|
||||
let seconds = time.elapsed_seconds();
|
||||
|
||||
// Update the color of the first and only section.
|
||||
text.sections[0].style.color = Color::Rgba {
|
||||
|
@ -46,7 +46,7 @@ fn change_title(time: Res<Time>, mut windows: ResMut<Windows>) {
|
||||
let window = windows.primary_mut();
|
||||
window.set_title(format!(
|
||||
"Seconds since startup: {}",
|
||||
time.seconds_since_startup().round()
|
||||
time.elapsed_seconds().round()
|
||||
));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user