Skip to content

Commit

Permalink
three variants of time since startup
Browse files Browse the repository at this point in the history
There's a non-zero duration between startup and the very first update to time. Fixed timestep starts accumulating with the latter. Not sure if it's important to know, but we can just save the first update instant if we need it later.
  • Loading branch information
maniwani committed Oct 22, 2021
1 parent 46d5e6e commit 2dddfc6
Showing 1 changed file with 67 additions and 10 deletions.
77 changes: 67 additions & 10 deletions crates/bevy_core/src/time/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Time {
fixed_delta_seconds_f64: f64,
speed_multiplier: f32,
time_since_startup: Duration,
first_update: Option<Instant>,
last_update: Option<Instant>,
startup: Instant,
}
Expand All @@ -32,6 +33,7 @@ impl Default for Time {
fixed_delta_seconds_f64: fixed_delta.as_secs_f64(),
speed_multiplier: 1.0,
time_since_startup: Duration::from_secs(0),
first_update: None,
last_update: None,
startup: Instant::now(),
}
Expand All @@ -50,6 +52,9 @@ impl Time {
self.delta_seconds = self.delta.as_secs_f32();
self.delta_seconds_f64 = self.delta.as_secs_f64();
self.time_since_startup += self.delta.mul_f32(self.speed_multiplier);
} else {
self.first_update = Some(instant);
self.time_since_startup += (instant - self.startup).mul_f32(self.speed_multiplier);
}

self.last_update = Some(instant);
Expand Down Expand Up @@ -94,9 +99,10 @@ impl Time {
self.fixed_delta_seconds_f64
}

/// Changes fixed delta. Users are strongly cautioned against modifying
/// Changes [`Time::fixed_delta`]. Users are strongly cautioned against modifying
/// the step rate this way, except during startup.
/// Prefer [`Time::set_speed_multiplier`] to ensure consistent simulation behavior.
/// Prefer [`Time::set_speed_multiplier`] to ensure that consumers of
/// [`Time::fixed_delta`] produce consistent behavior.
pub fn set_steps_per_second(&mut self, steps: f32) {
self.fixed_delta = Duration::from_secs_f32(1.0 / steps);
self.fixed_delta_seconds = self.fixed_delta.as_secs_f32();
Expand All @@ -117,13 +123,19 @@ impl Time {
self.speed_multiplier as f64
}

/// Set rate app time advances relative to true clock time.
/// Set rate app time advances relative to true clock time. Must be >= 0.0.
#[inline]
pub fn set_speed_multiplier(&mut self, speed_multiplier: f32) {
assert!(speed_multiplier > 0.0);
assert!(speed_multiplier >= 0.0);
self.speed_multiplier = speed_multiplier;
}

/// The ['Instant'] when [`Time::update`] was first called, if it exists.
#[inline]
pub fn first_update(&self) -> Option<Instant> {
self.first_update
}

/// The ['Instant'] when [`Time::update`] was last called, if it exists.
#[inline]
pub fn last_update(&self) -> Option<Instant> {
Expand All @@ -137,39 +149,64 @@ impl Time {
}

/// The time since startup, as [`Duration`]. Affected by speed multiplier.
#[inline]
/// Sampled during the latest update.
pub fn time_since_startup(&self) -> Duration {
self.time_since_startup
}

/// The time since startup, as [`f32`] seconds. Affected by speed multiplier.
/// Sampled during the latest update.
#[inline]
pub fn seconds_since_startup(&self) -> f32 {
self.time_since_startup().as_secs_f32()
}

/// The time since startup, as [`f64`] seconds. Affected by speed multiplier.
/// Sampled during the latest update.
#[inline]
pub fn seconds_since_startup_f64(&self) -> f64 {
self.time_since_startup().as_secs_f64()
}

/// The true clock time since startup, as [`Duration`]. May be different every call.
/// The time since startup, as [`Duration`]. Unaffected by speed multiplier.
/// Sampled during the latest update.
pub fn real_time_since_startup(&self) -> Duration {
Instant::now() - self.startup
self.last_update.unwrap_or(self.startup) - self.startup
}

/// The true clock time since startup, as [`f32`] seconds. May be different every call.
/// The time since startup, as [`f32`] seconds. Unaffected by speed multiplier.
/// Sampled during the latest update.
#[inline]
pub fn real_seconds_since_startup(&self) -> f32 {
self.real_time_since_startup().as_secs_f32()
}

/// The true clock time since startup, as [`f64`] seconds. May be different every call.
/// The time since startup, as [`f64`] seconds. Unaffected by speed multiplier.
/// Sampled during the latest update.
#[inline]
pub fn real_seconds_since_startup_f64(&self) -> f64 {
self.real_time_since_startup().as_secs_f64()
}

/// The time since startup, as [`Duration`]. Unaffected by speed multiplier.
/// Sampled at call.
pub fn live_real_time_since_startup(&self) -> Duration {
Instant::now() - self.startup
}

/// The time since startup, as [`f32`] seconds. Unaffected by speed multiplier.
/// Sampled at call.
#[inline]
pub fn live_real_seconds_since_startup(&self) -> f32 {
self.live_real_time_since_startup().as_secs_f32()
}

/// The time since startup, as [`f64`] seconds. Unaffected by speed multiplier.
/// Sampled at call.
#[inline]
pub fn live_real_seconds_since_startup_f64(&self) -> f64 {
self.live_real_time_since_startup().as_secs_f64()
}
}

pub(crate) fn time_system(mut time: ResMut<Time>, mut accumulator: ResMut<FixedTimestepState>) {
Expand Down Expand Up @@ -210,10 +247,12 @@ mod tests {
);

// Sanity check.
assert_eq!(time.first_update(), None);
assert_eq!(time.last_update(), None);
assert_eq!(time.startup(), start_instant);
assert_eq!(time.speed_multiplier(), 1.0);
assert_eq!(time.time_since_startup(), Duration::from_secs(0));
assert_eq!(time.real_time_since_startup(), Duration::from_secs(0));

// Update `time` and check results.
// The first update to `time` normally happens before other systems have run,
Expand All @@ -235,10 +274,18 @@ mod tests {
);

// Sanity check.
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.speed_multiplier(), 1.0);
assert_eq!(time.time_since_startup(), Duration::from_secs(0));
assert_eq!(
time.time_since_startup(),
first_update_instant - start_instant
);
assert_eq!(
time.real_time_since_startup(),
first_update_instant - start_instant
);

// Update `time` again and check results.
// At this point its safe to use time.delta().
Expand All @@ -259,13 +306,18 @@ mod tests {
);

// Sanity check.
assert_eq!(time.first_update(), Some(first_update_instant));
assert_eq!(time.last_update(), Some(second_update_instant));
assert_eq!(time.startup(), start_instant);
assert_eq!(time.speed_multiplier(), 1.0);
assert_eq!(
time.time_since_startup(),
second_update_instant - start_instant
);
assert_eq!(
time.real_time_since_startup(),
second_update_instant - start_instant
);

// Make app time advance at 2x the rate of real world time.
time.set_speed_multiplier(2.0);
Expand All @@ -288,6 +340,7 @@ mod tests {
);

// Sanity check.
assert_eq!(time.first_update(), Some(first_update_instant));
assert_eq!(time.last_update(), Some(third_update_instant));
assert_eq!(time.startup(), start_instant);

Expand All @@ -297,5 +350,9 @@ mod tests {
time.time_since_startup(),
second_update_instant - start_instant + Duration::from_secs(2)
);
assert_eq!(
time.real_time_since_startup(),
second_update_instant - start_instant + Duration::from_secs(1)
);
}
}

0 comments on commit 2dddfc6

Please sign in to comment.