@@ -10,6 +10,7 @@ use bevy_ecs::{
10
10
use bevy_utils:: HashMap ;
11
11
use std:: borrow:: Cow ;
12
12
13
+ #[ derive( Debug ) ]
13
14
pub struct FixedTimestepState {
14
15
pub step : f64 ,
15
16
pub accumulator : f64 ,
@@ -49,14 +50,14 @@ impl FixedTimesteps {
49
50
}
50
51
51
52
pub struct FixedTimestep {
52
- state : State ,
53
+ state : LocalFixedTimestepState ,
53
54
internal_system : Box < dyn System < In = ( ) , Out = ShouldRun > > ,
54
55
}
55
56
56
57
impl Default for FixedTimestep {
57
58
fn default ( ) -> Self {
58
59
Self {
59
- state : State :: default ( ) ,
60
+ state : LocalFixedTimestepState :: default ( ) ,
60
61
internal_system : Box :: new ( Self :: prepare_system. system ( ) ) ,
61
62
}
62
63
}
@@ -65,7 +66,7 @@ impl Default for FixedTimestep {
65
66
impl FixedTimestep {
66
67
pub fn step ( step : f64 ) -> Self {
67
68
Self {
68
- state : State {
69
+ state : LocalFixedTimestepState {
69
70
step,
70
71
..Default :: default ( )
71
72
} ,
@@ -75,7 +76,7 @@ impl FixedTimestep {
75
76
76
77
pub fn steps_per_second ( rate : f64 ) -> Self {
77
78
Self {
78
- state : State {
79
+ state : LocalFixedTimestepState {
79
80
step : 1.0 / rate,
80
81
..Default :: default ( )
81
82
} ,
@@ -89,7 +90,7 @@ impl FixedTimestep {
89
90
}
90
91
91
92
fn prepare_system (
92
- mut state : Local < State > ,
93
+ mut state : Local < LocalFixedTimestepState > ,
93
94
time : Res < Time > ,
94
95
mut fixed_timesteps : ResMut < FixedTimesteps > ,
95
96
) -> ShouldRun {
@@ -105,14 +106,14 @@ impl FixedTimestep {
105
106
}
106
107
107
108
#[ derive( Clone ) ]
108
- pub struct State {
109
+ pub struct LocalFixedTimestepState {
109
110
label : Option < String > , // TODO: consider making this a TypedLabel
110
111
step : f64 ,
111
112
accumulator : f64 ,
112
113
looping : bool ,
113
114
}
114
115
115
- impl Default for State {
116
+ impl Default for LocalFixedTimestepState {
116
117
fn default ( ) -> Self {
117
118
Self {
118
119
step : 1.0 / 60.0 ,
@@ -123,7 +124,7 @@ impl Default for State {
123
124
}
124
125
}
125
126
126
- impl State {
127
+ impl LocalFixedTimestepState {
127
128
fn update ( & mut self , time : & Time ) -> ShouldRun {
128
129
if !self . looping {
129
130
self . accumulator += time. delta_seconds_f64 ( ) ;
@@ -194,3 +195,80 @@ impl System for FixedTimestep {
194
195
self . internal_system . check_change_tick ( change_tick) ;
195
196
}
196
197
}
198
+
199
+ #[ cfg( test) ]
200
+ mod test {
201
+ use super :: * ;
202
+ use bevy_ecs:: prelude:: * ;
203
+ use bevy_utils:: Instant ;
204
+ use std:: ops:: { Add , Mul } ;
205
+ use std:: time:: Duration ;
206
+
207
+ type Count = usize ;
208
+ const LABEL : & str = "test_step" ;
209
+
210
+ #[ test]
211
+ fn test ( ) {
212
+ let mut world = World :: default ( ) ;
213
+ let mut time = Time :: default ( ) ;
214
+ let instance = Instant :: now ( ) ;
215
+ time. update_with_instant ( instance) ;
216
+ world. insert_resource ( time) ;
217
+ world. insert_resource ( FixedTimesteps :: default ( ) ) ;
218
+ world. insert_resource :: < Count > ( 0 ) ;
219
+ let mut schedule = Schedule :: default ( ) ;
220
+
221
+ schedule. add_stage (
222
+ "update" ,
223
+ SystemStage :: parallel ( )
224
+ . with_run_criteria ( FixedTimestep :: step ( 0.5 ) . with_label ( LABEL ) )
225
+ . with_system ( fixed_update) ,
226
+ ) ;
227
+
228
+ // if time does not progress, the step does not run
229
+ schedule. run ( & mut world) ;
230
+ schedule. run ( & mut world) ;
231
+ assert_eq ! ( 0 , * world. get_resource:: <Count >( ) . unwrap( ) ) ;
232
+ assert_eq ! ( 0. , get_accumulator_deciseconds( & world) ) ;
233
+
234
+ // let's progress less than one step
235
+ advance_time ( & mut world, instance, 0.4 ) ;
236
+ schedule. run ( & mut world) ;
237
+ assert_eq ! ( 0 , * world. get_resource:: <Count >( ) . unwrap( ) ) ;
238
+ assert_eq ! ( 4. , get_accumulator_deciseconds( & world) ) ;
239
+
240
+ // finish the first step with 0.1s above the step length
241
+ advance_time ( & mut world, instance, 0.6 ) ;
242
+ schedule. run ( & mut world) ;
243
+ assert_eq ! ( 1 , * world. get_resource:: <Count >( ) . unwrap( ) ) ;
244
+ assert_eq ! ( 1. , get_accumulator_deciseconds( & world) ) ;
245
+
246
+ // runs multiple times if the delta is multiple step lengths
247
+ advance_time ( & mut world, instance, 1.7 ) ;
248
+ schedule. run ( & mut world) ;
249
+ assert_eq ! ( 3 , * world. get_resource:: <Count >( ) . unwrap( ) ) ;
250
+ assert_eq ! ( 2. , get_accumulator_deciseconds( & world) ) ;
251
+ }
252
+
253
+ fn fixed_update ( mut count : ResMut < Count > ) {
254
+ * count += 1 ;
255
+ }
256
+
257
+ fn advance_time ( world : & mut World , instance : Instant , seconds : f32 ) {
258
+ world
259
+ . get_resource_mut :: < Time > ( )
260
+ . unwrap ( )
261
+ . update_with_instant ( instance. add ( Duration :: from_secs_f32 ( seconds) ) ) ;
262
+ }
263
+
264
+ fn get_accumulator_deciseconds ( world : & World ) -> f64 {
265
+ world
266
+ . get_resource :: < FixedTimesteps > ( )
267
+ . unwrap ( )
268
+ . get ( LABEL )
269
+ . unwrap ( )
270
+ . accumulator
271
+ . mul ( 10. )
272
+ . round ( )
273
+ }
274
+ }
0 commit comments