@@ -34,6 +34,8 @@ pub struct Time {
34
34
raw_elapsed_wrapped : Duration ,
35
35
raw_elapsed_seconds_wrapped : f32 ,
36
36
raw_elapsed_seconds_wrapped_f64 : f64 ,
37
+ // maximum delta
38
+ maximum_delta : Option < Duration > ,
37
39
}
38
40
39
41
impl Default for Time {
@@ -63,6 +65,7 @@ impl Default for Time {
63
65
raw_elapsed_wrapped : Duration :: ZERO ,
64
66
raw_elapsed_seconds_wrapped : 0.0 ,
65
67
raw_elapsed_seconds_wrapped_f64 : 0.0 ,
68
+ maximum_delta : Some ( Duration :: from_millis ( 333 ) ) , // 0.333 seconds
66
69
}
67
70
}
68
71
}
@@ -139,13 +142,20 @@ impl Time {
139
142
/// ```
140
143
pub fn update_with_instant ( & mut self , instant : Instant ) {
141
144
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
+ } ;
142
152
let delta = if self . paused {
143
153
Duration :: ZERO
144
154
} else if self . relative_speed != 1.0 {
145
- raw_delta . mul_f64 ( self . relative_speed )
155
+ clamped_delta . mul_f64 ( self . relative_speed )
146
156
} else {
147
157
// avoid rounding when at normal speed
148
- raw_delta
158
+ clamped_delta
149
159
} ;
150
160
151
161
if self . last_update . is_some ( ) {
@@ -351,6 +361,29 @@ impl Time {
351
361
self . wrap_period = wrap_period;
352
362
}
353
363
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
+
354
387
/// Returns the speed the clock advances relative to your system clock, as [`f32`].
355
388
/// This is known as "time scaling" or "time dilation" in other engines.
356
389
///
@@ -463,6 +496,7 @@ mod tests {
463
496
assert_eq ! ( time. raw_elapsed( ) , Duration :: ZERO ) ;
464
497
assert_eq ! ( time. raw_elapsed_seconds( ) , 0.0 ) ;
465
498
assert_eq ! ( time. raw_elapsed_seconds_f64( ) , 0.0 ) ;
499
+ assert_eq ! ( time. maximum_delta( ) , Some ( Duration :: from_millis( 333 ) ) ) ;
466
500
467
501
// Update `time` and check results.
468
502
// The first update to `time` normally happens before other systems have run,
@@ -555,6 +589,7 @@ mod tests {
555
589
let mut time = Time {
556
590
startup : start_instant,
557
591
wrap_period : Duration :: from_secs ( 3 ) ,
592
+ maximum_delta : Some ( Duration :: from_secs ( 5 ) ) ,
558
593
..Default :: default ( )
559
594
} ;
560
595
@@ -632,8 +667,8 @@ mod tests {
632
667
// Make app time advance at 2x the rate of your system clock.
633
668
time. set_relative_speed ( 2.0 ) ;
634
669
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 ) ;
637
672
let third_update_instant = second_update_instant + elapsed;
638
673
time. update_with_instant ( third_update_instant) ;
639
674
@@ -725,4 +760,41 @@ mod tests {
725
760
) ;
726
761
assert_eq ! ( time. raw_elapsed( ) , third_update_instant - start_instant) ;
727
762
}
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
+ }
728
800
}
0 commit comments