Skip to main content

avian3d/schedule/
time.rs

1//! Clocks used for tracking physics simulation time.
2
3use bevy::prelude::*;
4
5/// The clock representing physics time, following the [`Time`] clock used by the schedule that physics runs in.
6///
7/// In [`FixedPostUpdate`] and other fixed schedules, this uses [`Time<Fixed>`](Fixed), while in schedules such as [`Update`],
8/// a variable timestep following [`Time<Virtual>`](Virtual) is used.
9///
10/// [`Time<Physics>`](Physics) is automatically set as the generic [`Time`] resource for
11/// the [`PhysicsSchedule`].
12///
13/// [`PhysicsSchedule`]: crate::schedule::PhysicsSchedule
14///
15/// # Usage
16///
17/// ## Physics Speed
18///
19/// The relative speed of [`Time<Physics>`](Physics) can be configured at startup
20/// using [`with_relative_speed`], or when the app is running using [`set_relative_speed`]:
21///
22/// ```no_run
23#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
24#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
25/// use bevy::prelude::*;
26///
27/// fn main() {
28///     App::new()
29///         .add_plugins((DefaultPlugins, PhysicsPlugins::default()))
30///         // Run physics at 0.5 speed
31///         .insert_resource(Time::<Physics>::default().with_relative_speed(0.5))
32///         .run();
33/// }
34/// ```
35///
36/// [`with_relative_speed`]: PhysicsTime::with_relative_speed
37/// [`set_relative_speed`]: PhysicsTime::set_relative_speed
38///
39/// ## Pausing, Resuming, and Stepping Physics
40///
41/// [`Time<Physics>`](Physics) can be used to pause and resume the simulation:
42///
43/// ```
44#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
45#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
46/// use bevy::prelude::*;
47///
48/// fn pause(mut time: ResMut<Time<Physics>>) {
49///     time.pause();
50/// }
51///
52/// fn unpause(mut time: ResMut<Time<Physics>>) {
53///     time.unpause();
54/// }
55/// ```
56///
57/// To advance the simulation by a certain amount of time instantly, you can advance the
58/// [`Time<Physics>`](Physics) clock and manually run the [`PhysicsSchedule`] in an exclusive system:
59///
60/// ```
61#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
62#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
63/// use bevy::prelude::*;
64/// use core::time::Duration;
65///
66/// fn run_physics(world: &mut World) {
67///     // Advance the simulation by 10 steps at 120 Hz
68///     for _ in 0..10 {
69///         world
70///             .resource_mut::<Time<Physics>>()
71///             .advance_by(Duration::from_secs_f64(1.0 / 120.0));
72///         world.run_schedule(PhysicsSchedule);
73///     }
74/// }
75/// ```
76///
77/// ## When to Multiply by Delta Time?
78///
79/// Schedules like `Update` use a variable timestep, which can often cause frame rate dependent
80/// behavior when moving bodies. One way to help address the issue is by multiplying by delta time.
81///
82/// In general, if you're doing a *continuous* operation, you should always multiply by delta time,
83/// but for *instantaneous* operations it's not necessary.
84///
85/// Continuous operations move or accelerate bodies over time:
86///
87/// ```
88/// # use bevy::math::Vec3;
89/// #
90/// # let mut position = Vec3::default();
91/// # let mut velocity = Vec3::default();
92/// # let mut acceleration = Vec3::default();
93/// # let mut delta_time = 1.0 / 60.0;
94/// #
95/// // Move continuously over time
96/// position += velocity * delta_time;
97/// // Accelerate continuously
98/// velocity += acceleration * delta_time;
99/// ```
100///
101/// Instantaneous operations apply a singular sudden burst of velocity
102/// or set it to a specific value:
103///
104/// ```
105/// # use bevy::math::Vec3;
106/// #
107/// # let mut velocity = Vec3::default();
108/// # let mut impulse = Vec3::default();
109/// # let mut target_velocity = Vec3::default();
110/// #
111/// // Apply a burst of speed once (jumps, explosions and so on)
112/// velocity += impulse;
113/// // Set velocity to a specific value
114/// velocity = target_velocity;
115/// ```
116///
117/// For systems using a fixed timestep, using delta time is not necessary for frame rate
118/// independence, but it's still recommended so that the physical units are more logical.
119
120#[derive(Reflect, Clone, Copy, Debug, PartialEq)]
121#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
122#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
123#[reflect(Debug, PartialEq)]
124pub struct Physics {
125    paused: bool,
126    relative_speed: f64,
127}
128
129impl Default for Physics {
130    fn default() -> Self {
131        Self {
132            paused: false,
133            relative_speed: 1.0,
134        }
135    }
136}
137
138/// An extension trait for [`Time<Physics>`](Physics).
139pub trait PhysicsTime {
140    /// Returns the speed of physics relative to your system clock as an `f32`.
141    /// This is also known as "time scaling" or "time dilation" in other engines.
142    ///
143    /// The speed impacts the accuracy of the simulation, and large values may
144    /// cause jittering or missed collisions. You can improve simulation consistency
145    /// by adjusting your timestep at the cost of performance.
146    fn relative_speed(&self) -> f32;
147
148    /// Returns the speed of physics relative to your system clock as an `f64`.
149    /// This is also known as "time scaling" or "time dilation" in other engines.
150    ///
151    /// The speed impacts the accuracy of the simulation, and large values may
152    /// cause jittering or missed collisions. You can improve simulation consistency
153    /// by adjusting your timestep at the cost of performance.
154    fn relative_speed_f64(&self) -> f64;
155
156    /// Sets the speed of physics relative to your system clock, given as an `f32`.
157    ///
158    /// For example, setting this to `2.0` will make the physics clock advance twice
159    /// as fast as your system clock.
160    ///
161    /// The speed impacts the accuracy of the simulation, and large values may
162    /// cause jittering or missed collisions. You can improve simulation consistency
163    /// by adjusting your timestep at the cost of performance.
164    ///
165    /// # Panics
166    ///
167    /// Panics if `ratio` is negative or not finite.
168    fn with_relative_speed(self, ratio: f32) -> Self;
169
170    /// Sets the speed of physics relative to your system clock, given as an `f64`.
171    ///
172    /// For example, setting this to `2.0` will make the physics clock advance twice
173    /// as fast as your system clock.
174    ///
175    /// The speed impacts the accuracy of the simulation, and large values may
176    /// cause jittering or missed collisions. You can improve simulation consistency
177    /// by adjusting your timestep at the cost of performance.
178    ///
179    /// # Panics
180    ///
181    /// Panics if `ratio` is negative or not finite.
182    fn with_relative_speed_f64(self, ratio: f64) -> Self;
183
184    /// Sets the speed of physics relative to your system clock, given as an `f32`.
185    ///
186    /// For example, setting this to `2.0` will make the physics clock advance twice
187    /// as fast as your system clock.
188    ///
189    /// The speed impacts the accuracy of the simulation, and large values may
190    /// cause jittering or missed collisions. You can improve simulation consistency
191    /// by adjusting your timestep at the cost of performance.
192    ///
193    /// # Panics
194    ///
195    /// Panics if `ratio` is negative or not finite.
196    fn set_relative_speed(&mut self, ratio: f32);
197
198    /// Sets the speed of physics relative to your system clock, given as an `f64`.
199    ///
200    /// For example, setting this to `2.0` will make the physics clock advance twice
201    /// as fast as your system clock.
202    ///
203    /// The speed impacts the accuracy of the simulation, and large values may
204    /// cause jittering or missed collisions. You can improve simulation consistency
205    /// by adjusting your timestep at the cost of performance.
206    ///
207    /// # Panics
208    ///
209    /// Panics if `ratio` is negative or not finite.
210    fn set_relative_speed_f64(&mut self, ratio: f64);
211
212    /// Returns `true` if the physics clock is currently paused.
213    fn is_paused(&self) -> bool;
214
215    /// Stops the clock, preventing the physics simulation from advancing until resumed.
216    fn pause(&mut self);
217
218    /// Resumes the clock if paused.
219    #[doc(alias = "resume")]
220    fn unpause(&mut self);
221}
222
223impl PhysicsTime for Time<Physics> {
224    fn with_relative_speed(self, ratio: f32) -> Self {
225        self.with_relative_speed_f64(ratio as f64)
226    }
227
228    fn with_relative_speed_f64(mut self, ratio: f64) -> Self {
229        assert!(ratio.is_finite(), "tried to go infinitely fast");
230        assert!(ratio >= 0.0, "tried to go back in time");
231        self.context_mut().relative_speed = ratio;
232        self
233    }
234
235    fn relative_speed(&self) -> f32 {
236        self.relative_speed_f64() as f32
237    }
238
239    fn relative_speed_f64(&self) -> f64 {
240        self.context().relative_speed
241    }
242
243    fn set_relative_speed(&mut self, ratio: f32) {
244        self.set_relative_speed_f64(ratio as f64);
245    }
246
247    fn set_relative_speed_f64(&mut self, ratio: f64) {
248        assert!(ratio.is_finite(), "tried to go infinitely fast");
249        assert!(ratio >= 0.0, "tried to go back in time");
250        self.context_mut().relative_speed = ratio;
251    }
252
253    fn pause(&mut self) {
254        self.context_mut().paused = true;
255    }
256
257    fn unpause(&mut self) {
258        self.context_mut().paused = false;
259    }
260
261    fn is_paused(&self) -> bool {
262        self.context().paused
263    }
264}
265
266/// The clock representing physics substep time. It is updated based on
267/// [`Time<Physics>`](Physics) and the [`SubstepCount`] resource.
268///
269/// The clock is automatically set as the generic `Time` resource for
270/// the [`SubstepSchedule`].
271///
272/// [`SubstepCount`]: crate::dynamics::solver::schedule::SubstepCount
273/// [`SubstepSchedule`]: crate::schedule::SubstepSchedule
274#[derive(Reflect, Clone, Copy, Debug, Default, PartialEq)]
275pub struct Substeps;