Skip to content

Commit c94f49b

Browse files
committed
Add maximum_delta to Time
1 parent 910f984 commit c94f49b

File tree

1 file changed

+76
-4
lines changed

1 file changed

+76
-4
lines changed

crates/bevy_time/src/time.rs

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ pub struct Time {
3434
raw_elapsed_wrapped: Duration,
3535
raw_elapsed_seconds_wrapped: f32,
3636
raw_elapsed_seconds_wrapped_f64: f64,
37+
// maximum delta
38+
maximum_delta: Option<Duration>,
3739
}
3840

3941
impl Default for Time {
@@ -63,6 +65,7 @@ impl Default for Time {
6365
raw_elapsed_wrapped: Duration::ZERO,
6466
raw_elapsed_seconds_wrapped: 0.0,
6567
raw_elapsed_seconds_wrapped_f64: 0.0,
68+
maximum_delta: Some(Duration::from_millis(333)), // 0.333 seconds
6669
}
6770
}
6871
}
@@ -139,13 +142,20 @@ impl Time {
139142
/// ```
140143
pub fn update_with_instant(&mut self, instant: Instant) {
141144
let raw_delta = instant - self.last_update.unwrap_or(self.startup);
145+
// if time jumps forward significantly, clamp maximum delta added to
146+
// elapsed (but not raw_elapsed), before relative speed scaling
147+
let clamped_delta = if let Some(maximum_delta) = self.maximum_delta {
148+
std::cmp::min(raw_delta, maximum_delta)
149+
} else {
150+
raw_delta
151+
};
142152
let delta = if self.paused {
143153
Duration::ZERO
144154
} else if self.relative_speed != 1.0 {
145-
raw_delta.mul_f64(self.relative_speed)
155+
clamped_delta.mul_f64(self.relative_speed)
146156
} else {
147157
// avoid rounding when at normal speed
148-
raw_delta
158+
clamped_delta
149159
};
150160

151161
if self.last_update.is_some() {
@@ -351,6 +361,29 @@ impl Time {
351361
self.wrap_period = wrap_period;
352362
}
353363

364+
/// Returns the maximum time [`elapsed`](#method.elapsed) can be increased
365+
/// in a single update.
366+
///
367+
/// This is meant to avoid glitches in game logic if the isn't updated in a
368+
/// while due to some external reason.
369+
///
370+
/// **Note:** The default is 0.333 seconds.
371+
#[inline]
372+
pub fn maximum_delta(&self) -> Option<Duration> {
373+
self.maximum_delta
374+
}
375+
376+
/// Sets the maximum time [`elapsed`](#method.elapsed) can be increased in a
377+
/// single update.
378+
///
379+
/// Setting `None` will disable the maximum delta limit, which should be
380+
/// used with care, as it may provoke undesirable behaviour in systems that
381+
/// observe time.
382+
#[inline]
383+
pub fn set_maximum_delta(&mut self, maximum_delta: Option<Duration>) {
384+
self.maximum_delta = maximum_delta;
385+
}
386+
354387
/// Returns the speed the clock advances relative to your system clock, as [`f32`].
355388
/// This is known as "time scaling" or "time dilation" in other engines.
356389
///
@@ -463,6 +496,7 @@ mod tests {
463496
assert_eq!(time.raw_elapsed(), Duration::ZERO);
464497
assert_eq!(time.raw_elapsed_seconds(), 0.0);
465498
assert_eq!(time.raw_elapsed_seconds_f64(), 0.0);
499+
assert_eq!(time.maximum_delta(), Some(Duration::from_millis(333)));
466500

467501
// Update `time` and check results.
468502
// The first update to `time` normally happens before other systems have run,
@@ -555,6 +589,7 @@ mod tests {
555589
let mut time = Time {
556590
startup: start_instant,
557591
wrap_period: Duration::from_secs(3),
592+
maximum_delta: Some(Duration::from_secs(5)),
558593
..Default::default()
559594
};
560595

@@ -632,8 +667,8 @@ mod tests {
632667
// Make app time advance at 2x the rate of your system clock.
633668
time.set_relative_speed(2.0);
634669

635-
// Update `time` again 1 second later.
636-
let elapsed = Duration::from_secs(1);
670+
// Update `time` again 250 milliseconds later.
671+
let elapsed = Duration::from_millis(250);
637672
let third_update_instant = second_update_instant + elapsed;
638673
time.update_with_instant(third_update_instant);
639674

@@ -725,4 +760,41 @@ mod tests {
725760
);
726761
assert_eq!(time.raw_elapsed(), third_update_instant - start_instant);
727762
}
763+
764+
#[test]
765+
fn maximum_delta_test() {
766+
let start_instant = Instant::now();
767+
768+
let mut time = Time::new(start_instant);
769+
770+
assert_eq!(time.elapsed_seconds(), 0.0);
771+
772+
time.update_with_instant(start_instant + Duration::from_millis(333));
773+
assert_float_eq(time.elapsed_seconds(), 0.333);
774+
775+
time.update_with_instant(start_instant + Duration::from_millis(1000));
776+
assert_float_eq(time.elapsed_seconds(), 0.666);
777+
778+
time.update_with_instant(start_instant + Duration::from_millis(4999));
779+
assert_float_eq(time.elapsed_seconds(), 0.999);
780+
781+
time.update_with_instant(start_instant + Duration::from_millis(5000));
782+
assert_float_eq(time.elapsed_seconds(), 1.0);
783+
784+
time.set_maximum_delta(Some(Duration::from_secs(10)));
785+
786+
time.update_with_instant(start_instant + Duration::from_secs(6));
787+
assert_float_eq(time.elapsed_seconds(), 2.0);
788+
789+
time.update_with_instant(start_instant + Duration::from_secs(16));
790+
assert_float_eq(time.elapsed_seconds(), 12.0);
791+
792+
time.update_with_instant(start_instant + Duration::from_secs(30));
793+
assert_float_eq(time.elapsed_seconds(), 22.0);
794+
795+
time.set_maximum_delta(None);
796+
797+
time.update_with_instant(start_instant + Duration::from_secs(60));
798+
assert_float_eq(time.elapsed_seconds(), 52.0);
799+
}
728800
}

0 commit comments

Comments
 (0)