Skip to content

Commit

Permalink
Add PhysicsTimescale resource for slow-motion or fast-forward simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
dasisdormax committed Jul 17, 2023
1 parent 61e6b20 commit 836f1cc
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
//! - Debug rendering [colliders](Collider), [AABBs](ColliderAabb), [contacts](Contact), [joints] and axes
//! (with `debug-plugin` feature)
//! - Automatically deactivating bodies with [sleeping](Sleeping)
//! - Configurable [timesteps](PhysicsTimestep) and [substepping](SubstepCount)
//! - Configurable [timesteps](PhysicsTimestep), [time scale](PhysicsTimescale) and [substepping](SubstepCount)
//! - `f32`/`f64` precision (`f32` by default)
//!
//! ## Getting started
Expand Down Expand Up @@ -177,6 +177,7 @@
//! - [Point projection](spatial_query#point-projection)
//! - [Intersection tests](spatial_query#intersection-tests)
//! - [Configure the physics timestep](PhysicsTimestep)
//! - [Configure the time scale](PhysicsTimescale)
//! - [Configure the substep count](SubstepCount)
//! - [Configure the schedule for running physics](PhysicsPlugins#custom-schedule)
//! - [Usage on servers](#can-the-engine-be-used-on-servers)
Expand Down
7 changes: 5 additions & 2 deletions src/plugins/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl Plugin for PhysicsSetupPlugin {
fn build(&self, app: &mut App) {
// Init resources and register component types
app.init_resource::<PhysicsTimestep>()
.init_resource::<PhysicsTimescale>()
.init_resource::<DeltaTime>()
.init_resource::<SubDeltaTime>()
.init_resource::<SubstepCount>()
Expand Down Expand Up @@ -212,13 +213,15 @@ fn run_physics_schedule(world: &mut World) {
let delta_seconds = world.resource::<Time>().delta_seconds_f64();

let time_step = *world.resource::<PhysicsTimestep>();
let time_scale = world.resource::<PhysicsTimescale>().0;

// Update `DeltaTime` according to the `PhysicsTimestep` configuration
let (dt, accumulate) = match time_step {
let (raw_dt, accumulate) = match time_step {
PhysicsTimestep::Fixed(fixed_delta_seconds) => (fixed_delta_seconds, true),
PhysicsTimestep::FixedOnce(fixed_delta_seconds) => (fixed_delta_seconds, false),
PhysicsTimestep::Variable { max_dt } => (delta_seconds.min(max_dt), true),
};
let dt = raw_dt * time_scale;
world.resource_mut::<DeltaTime>().0 = dt;

match accumulate {
Expand All @@ -236,7 +239,7 @@ fn run_physics_schedule(world: &mut World) {
physics_loop.accumulator += dt * physics_loop.queued_steps as Scalar;
physics_loop.queued_steps = 0;
} else {
physics_loop.accumulator += delta_seconds;
physics_loop.accumulator += delta_seconds * time_scale;
}

// Step the simulation until the accumulator has been consumed.
Expand Down
43 changes: 43 additions & 0 deletions src/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,49 @@ impl Default for PhysicsTimestep {
}
}

/// Configures the ratio of physics seconds per real second.
///
/// The default time scale is 1.0, meaning the simulation runs in real time.
/// Reduce this for slow motion, increase for fast forward.
///
/// This changes the [`DeltaTime`] that the simulation is advanced by for each
/// iteration. The frequency of physics updates, set using [`PhysicsTimestep`],
/// remains unchanged.
///
/// The time scale impacts the accuracy of the simulation and large values may
/// cause jittering or missed collisions. You may keep a consistent simulation
/// behaviour by adjusting your [timestep](`PhysicsTimestep::Fixed`)
/// at the cost of performance.
///
/// ## Example
///
/// You can change the time scale by inserting the [`PhysicsTimescale`] resource:
///
/// ```no_run
/// use bevy::prelude::*;
/// # #[cfg(feature = "2d")]
/// # use bevy_xpbd_2d::prelude::*;
/// # #[cfg(feature = "3d")]
/// use bevy_xpbd_3d::prelude::*;
///
/// fn main() {
/// App::new()
/// .add_plugins((DefaultPlugins, PhysicsPlugins::default()))
/// // Run the simulation at half speed, in slow motion
/// .insert_resource(PhysicsTimescale(0.5))
/// .run();
/// }
/// ```
#[derive(Reflect, Resource)]
#[reflect(Resource)]
pub struct PhysicsTimescale(pub Scalar);

impl Default for PhysicsTimescale {
fn default() -> Self {
Self(1.0)
}
}

/// How much time the previous physics frame took. The timestep can be configured with the [`PhysicsTimestep`] resource.
#[derive(Reflect, Resource, Default)]
#[reflect(Resource)]
Expand Down

0 comments on commit 836f1cc

Please sign in to comment.