Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream' into custom-debug-render
Browse files Browse the repository at this point in the history
  • Loading branch information
Vrixyz committed Sep 9, 2024
2 parents 4610dab + bab3431 commit 14a81b7
Show file tree
Hide file tree
Showing 25 changed files with 1,558 additions and 418 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ which was its hardcoded behaviour.
`RapierDebugColliderPlugin` and `DebugRenderContext`, as well as individual collider setup via
a `ColliderDebug` component.

### Modified

- `RapierContext`, `RapierConfiguration` and `RenderToSimulationTime` are now a `Component` instead of resources.
- Rapier now supports multiple independent physics worlds, see example `multi_world3` for usage details.
- Migration guide:
- `ResMut<mut RapierContext>` -> `WriteDefaultRapierContext`
- `Res<RapierContext>` -> `ReadDefaultRapierContext`
- Access to `RapierConfiguration` and `RenderToSimulationTime` should query for it
on the responsible entity owning the `RenderContext`.
- If you are building a library on top of `bevy_rapier` and would want to support multiple independent physics worlds too,
you can check out the details of [#545](https://github.com/dimforge/bevy_rapier/pull/545)
to get more context and information.

## v0.27.0 (07 July 2024)

**This is an update from rapier 0.19 to Rapier 0.21 which includes several stability improvements
Expand Down
1 change: 1 addition & 0 deletions bevy_rapier2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ serde = { version = "1", features = ["derive"], optional = true }
bevy = { version = "0.14", default-features = false, features = [
"x11",
"bevy_state",
"bevy_debug_stepping",
] }
oorandom = "11"
approx = "0.5.1"
Expand Down
3 changes: 2 additions & 1 deletion bevy_rapier2d/examples/player_movement2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ fn main() {
#[derive(Component)]
pub struct Player(f32);

pub fn spawn_player(mut commands: Commands, mut rapier_config: ResMut<RapierConfiguration>) {
pub fn spawn_player(mut commands: Commands, mut rapier_config: Query<&mut RapierConfiguration>) {
let mut rapier_config = rapier_config.single_mut();
// Set gravity to 0.0 and spawn camera.
rapier_config.gravity = Vec2::ZERO;
commands.spawn(Camera2dBundle::default());
Expand Down
4 changes: 3 additions & 1 deletion bevy_rapier2d/examples/testbed2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,9 @@ fn main() {
OnExit(Examples::PlayerMovement2),
(
cleanup,
|mut rapier_config: ResMut<RapierConfiguration>, ctxt: Res<RapierContext>| {
|mut rapier_config: Query<&mut RapierConfiguration>,
ctxt: ReadDefaultRapierContext| {
let mut rapier_config = rapier_config.single_mut();
rapier_config.gravity =
RapierConfiguration::new(ctxt.integration_parameters.length_unit).gravity;
},
Expand Down
1 change: 1 addition & 0 deletions bevy_rapier3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ bevy = { version = "0.14", default-features = false, features = [
"x11",
"tonemapping_luts",
"bevy_state",
"bevy_debug_stepping",
] }
approx = "0.5.1"
glam = { version = "0.27", features = ["approx"] }
Expand Down
2 changes: 1 addition & 1 deletion bevy_rapier3d/examples/joints3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ pub fn setup_physics(mut commands: Commands) {
}

pub fn print_impulse_revolute_joints(
context: Res<RapierContext>,
context: ReadDefaultRapierContext,
joints: Query<(Entity, &ImpulseJoint)>,
) {
for (entity, impulse_joint) in joints.iter() {
Expand Down
120 changes: 120 additions & 0 deletions bevy_rapier3d/examples/multi_world3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use bevy::{input::common_conditions::input_just_pressed, prelude::*};
use bevy_rapier3d::prelude::*;

const N_WORLDS: usize = 2;

fn main() {
App::new()
.insert_resource(ClearColor(Color::srgb(
0xF9 as f32 / 255.0,
0xF9 as f32 / 255.0,
0xFF as f32 / 255.0,
)))
.add_plugins((
DefaultPlugins,
RapierPhysicsPlugin::<NoUserData>::default()
.with_custom_initialization(RapierContextInitialization::NoAutomaticRapierContext),
RapierDebugRenderPlugin::default(),
))
.add_systems(
Startup,
((create_worlds, setup_physics).chain(), setup_graphics),
)
.add_systems(Update, move_platforms)
.add_systems(
Update,
change_world.run_if(input_just_pressed(KeyCode::KeyC)),
)
.run();
}

fn create_worlds(mut commands: Commands) {
for i in 0..N_WORLDS {
let mut world = commands.spawn((RapierContext::default(), WorldId(i)));
if i == 0 {
world.insert(DefaultRapierContext);
}
}
}

fn setup_graphics(mut commands: Commands) {
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.0, 3.0, -10.0)
.looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
..Default::default()
});
}

#[derive(Component)]
pub struct WorldId(pub usize);

#[derive(Component)]
struct Platform {
starting_y: f32,
}

fn move_platforms(time: Res<Time>, mut query: Query<(&mut Transform, &Platform)>) {
for (mut transform, platform) in query.iter_mut() {
transform.translation.y = platform.starting_y + -time.elapsed_seconds().sin();
}
}

/// Demonstrates how easy it is to move one entity to another world.
fn change_world(
query_context: Query<Entity, With<DefaultRapierContext>>,
mut query_links: Query<(Entity, &mut RapierContextEntityLink)>,
) {
let default_context = query_context.single();
for (e, mut link) in query_links.iter_mut() {
if link.0 == default_context {
continue;
}
link.0 = default_context;
println!("changing world of {} for world {}", e, link.0);
}
}

pub fn setup_physics(
context: Query<(Entity, &WorldId), With<RapierContext>>,
mut commands: Commands,
) {
for (context_entity, id) in context.iter() {
let id = id.0;

let color = [
Hsla::hsl(220.0, 1.0, 0.3),
Hsla::hsl(180.0, 1.0, 0.3),
Hsla::hsl(260.0, 1.0, 0.7),
][id % 3];

/*
* Ground
*/
let ground_size = 5.1;
let ground_height = 0.1;

let starting_y = (id as f32) * -0.5 - ground_height;

let mut platforms = commands.spawn((
TransformBundle::from(Transform::from_xyz(0.0, starting_y, 0.0)),
Collider::cuboid(ground_size, ground_height, ground_size),
ColliderDebugColor(color),
RapierContextEntityLink(context_entity),
));
if id == 1 {
platforms.insert(Platform { starting_y });
}

/*
* Create the cube
*/

commands.spawn((
TransformBundle::from(Transform::from_xyz(0.0, 1.0 + id as f32 * 5.0, 0.0)),
RigidBody::Dynamic,
Collider::cuboid(0.5, 0.5, 0.5),
ColliderDebugColor(color),
RapierContextEntityLink(context_entity),
));
}
}
2 changes: 1 addition & 1 deletion bevy_rapier3d/examples/ray_casting3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub fn setup_physics(mut commands: Commands) {
pub fn cast_ray(
mut commands: Commands,
windows: Query<&Window, With<PrimaryWindow>>,
rapier_context: Res<RapierContext>,
rapier_context: ReadDefaultRapierContext,
cameras: Query<(&Camera, &GlobalTransform)>,
) {
let window = windows.single();
Expand Down
5 changes: 4 additions & 1 deletion bevy_rapier_benches3d/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ pub fn custom_bencher(steps: usize, setup: impl Fn(&mut App)) {
app.update();
timer_full_update.pause();
let elapsed_time = timer_full_update.time() as f32;
let rc = app.world().resource::<RapierContext>();
let rc = app
.world_mut()
.query::<&RapierContext>()
.single(app.world());
rapier_step_times.push(rc.pipeline.counters.step_time.time() as f32);
total_update_times.push(elapsed_time);
}
Expand Down
32 changes: 13 additions & 19 deletions src/pipeline/events.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::math::{Real, Vect};
use bevy::prelude::{Entity, Event, EventWriter};
use bevy::prelude::{Entity, Event};
use rapier::dynamics::RigidBodySet;
use rapier::geometry::{
ColliderHandle, ColliderSet, CollisionEvent as RapierCollisionEvent, CollisionEventFlags,
Expand Down Expand Up @@ -58,8 +58,8 @@ pub(crate) struct EventQueue<'a> {
// Used to retrieve the entity of colliders that have been removed from the simulation
// since the last physics step.
pub deleted_colliders: &'a HashMap<ColliderHandle, Entity>,
pub collision_events: RwLock<EventWriter<'a, CollisionEvent>>,
pub contact_force_events: RwLock<EventWriter<'a, ContactForceEvent>>,
pub collision_events: RwLock<Vec<CollisionEvent>>,
pub contact_force_events: RwLock<Vec<ContactForceEvent>>,
}

impl<'a> EventQueue<'a> {
Expand Down Expand Up @@ -94,7 +94,7 @@ impl<'a> EventHandler for EventQueue<'a> {
};

if let Ok(mut events) = self.collision_events.write() {
events.send(event);
events.push(event);
}
}

Expand All @@ -118,7 +118,7 @@ impl<'a> EventHandler for EventQueue<'a> {
};

if let Ok(mut events) = self.contact_force_events.write() {
events.send(event);
events.push(event);
}
}
}
Expand Down Expand Up @@ -155,15 +155,13 @@ mod test {
pub struct EventsSaver<E: Event> {
pub events: Vec<E>,
}

impl<E: Event> Default for EventsSaver<E> {
fn default() -> Self {
Self {
events: Default::default(),
}
}
}

pub fn save_events<E: Event + Clone>(
mut events: EventReader<E>,
mut saver: ResMut<EventsSaver<E>>,
Expand All @@ -172,7 +170,6 @@ mod test {
saver.events.push(event.clone());
}
}

fn run_test(app: &mut App) {
app.add_systems(PostUpdate, save_events::<CollisionEvent>)
.add_systems(PostUpdate, save_events::<ContactForceEvent>)
Expand All @@ -192,12 +189,12 @@ mod test {
.world()
.get_resource::<EventsSaver<CollisionEvent>>()
.unwrap();
assert_eq!(saved_collisions.events.len(), 3);
assert!(saved_collisions.events.len() > 0);
let saved_contact_forces = app
.world()
.get_resource::<EventsSaver<ContactForceEvent>>()
.get_resource::<EventsSaver<CollisionEvent>>()
.unwrap();
assert_eq!(saved_contact_forces.events.len(), 1);
assert!(saved_contact_forces.events.len() > 0);
}

/// Adapted from events example
Expand Down Expand Up @@ -232,7 +229,7 @@ mod test {
TransformBundle::from(Transform::from_xyz(0.0, 13.0, 0.0)),
RigidBody::Dynamic,
cuboid(0.5, 0.5, 0.5),
ActiveEvents::COLLISION_EVENTS | ActiveEvents::CONTACT_FORCE_EVENTS,
ActiveEvents::COLLISION_EVENTS,
ContactForceEventThreshold(30.0),
));
}
Expand All @@ -247,13 +244,10 @@ mod test {
TransformPlugin,
RapierPhysicsPlugin::<NoUserData>::default(),
))
.insert_resource(RapierConfiguration {
timestep_mode: TimestepMode::Interpolated {
dt: 1.0 / 30.0,
time_scale: 1.0,
substeps: 2,
},
..RapierConfiguration::new(1f32)
.insert_resource(TimestepMode::Interpolated {
dt: 1.0 / 30.0,
time_scale: 1.0,
substeps: 2,
})
.add_systems(Startup, setup_physics)
.add_systems(Update, remove_collider);
Expand Down
43 changes: 19 additions & 24 deletions src/plugin/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use bevy::prelude::{FromWorld, Resource, World};
use bevy::{
prelude::{Component, Resource},
reflect::Reflect,
};

use crate::math::{Real, Vect};
use crate::plugin::RapierContext;

#[cfg(doc)]
use {crate::prelude::TransformInterpolation, rapier::dynamics::IntegrationParameters};

/// Difference between simulation and rendering time
#[derive(Resource, Default)]
#[derive(Component, Default, Reflect)]
pub struct SimulationToRenderTime {
/// Difference between simulation and rendering time
pub diff: f32,
}

/// The different ways of adjusting the timestep length.
#[derive(Copy, Clone, Debug, PartialEq)]
/// The different ways of adjusting the timestep length each frame.
#[derive(Copy, Clone, Debug, PartialEq, Resource)]
pub enum TimestepMode {
/// Use a fixed timestep: the physics simulation will be advanced by the fixed value
/// `dt` seconds at each Bevy tick by performing `substeps` of length `dt / substeps`.
Expand Down Expand Up @@ -53,17 +55,25 @@ pub enum TimestepMode {
},
}

#[derive(Resource, Copy, Clone, Debug)]
/// A resource for specifying configuration information for the physics simulation
impl Default for TimestepMode {
fn default() -> Self {
TimestepMode::Variable {
max_dt: 1.0 / 60.0,
time_scale: 1.0,
substeps: 1,
}
}
}

#[derive(Component, Copy, Clone, Debug, Reflect)]
/// A component for specifying configuration information for the physics simulation
pub struct RapierConfiguration {
/// Specifying the gravity of the physics simulation.
pub gravity: Vect,
/// Specifies if the physics simulation is active and update the physics world.
pub physics_pipeline_active: bool,
/// Specifies if the query pipeline is active and update the query pipeline.
pub query_pipeline_active: bool,
/// Specifies the way the timestep length should be adjusted at each frame.
pub timestep_mode: TimestepMode,
/// Specifies the number of subdivisions along each axes a shape should be subdivided
/// if its scaled representation cannot be represented with the same shape type.
///
Expand All @@ -76,16 +86,6 @@ pub struct RapierConfiguration {
pub force_update_from_transform_changes: bool,
}

impl FromWorld for RapierConfiguration {
fn from_world(world: &mut World) -> Self {
let length_unit = world
.get_resource::<RapierContext>()
.map(|ctxt| ctxt.integration_parameters.length_unit)
.unwrap_or(1.0);
Self::new(length_unit)
}
}

impl RapierConfiguration {
/// Configures rapier with the specified length unit.
///
Expand All @@ -98,11 +98,6 @@ impl RapierConfiguration {
gravity: Vect::Y * -9.81 * length_unit,
physics_pipeline_active: true,
query_pipeline_active: true,
timestep_mode: TimestepMode::Variable {
max_dt: 1.0 / 60.0,
time_scale: 1.0,
substeps: 1,
},
scaled_shape_subdivision: 10,
force_update_from_transform_changes: false,
}
Expand Down
Loading

0 comments on commit 14a81b7

Please sign in to comment.