Skip to content

Commit 95562e9

Browse files
committed
multiple worlds working + example
example from dimforge#328 Co-authored-by: Anthony Tornetta <[email protected]>
1 parent 7a4ba5e commit 95562e9

File tree

11 files changed

+661
-415
lines changed

11 files changed

+661
-415
lines changed

Diff for: CHANGELOG.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
- `RapierContext` is now a `Component`
88
- Rapier now supports multiple worlds.
99
- Migration guide:
10-
- `ResMut<mut RapierContext>` -> `RapierContextAccessMut`
11-
- `Res<RapierContext>` -> `Query<&RapierContext>`
12-
- `ResMut<RapierConfiguration>` -> `Query<&mut RapierConfiguration>`
13-
- `Res<RapierConfiguration>` -> `Query<&RapierConfiguration>`
14-
- you can reach out for the underlying configuration via .single
10+
- `ResMut<mut RapierContext>` -> `DefaultRapierContextAccessMut`
11+
- `Res<RapierContext>` -> `DefaultRapierContextAccess`
12+
- `ResMut<RapierConfiguration>` -> `DefaultRapierConfigurationMut`
13+
- `Res<RapierConfiguration>` -> `DefaultRapierConfiguration`
1514

1615
## v0.27.0-rc.1 (18 June 2024)
1716

Diff for: bevy_rapier3d/examples/multi_world3.rs

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use bevy::prelude::*;
2+
use bevy_rapier3d::prelude::*;
3+
4+
const N_WORLDS: usize = 2;
5+
6+
fn main() {
7+
App::new()
8+
.insert_resource(ClearColor(Color::rgb(
9+
0xF9 as f32 / 255.0,
10+
0xF9 as f32 / 255.0,
11+
0xFF as f32 / 255.0,
12+
)))
13+
.add_plugins((
14+
DefaultPlugins,
15+
RapierPhysicsPlugin::<NoUserData>::default().with_default_world(None),
16+
RapierDebugRenderPlugin::default(),
17+
))
18+
.add_systems(
19+
Startup,
20+
((create_worlds, setup_physics).chain(), setup_graphics),
21+
)
22+
.add_systems(Update, move_platforms)
23+
// .add_systems(Update, change_world)
24+
// .add_systems(Update, despawn_last)
25+
.run();
26+
}
27+
28+
fn create_worlds(mut commands: Commands) {
29+
for i in 0..N_WORLDS {
30+
commands.spawn((RapierContext::default(), WorldId(i)));
31+
}
32+
}
33+
34+
fn setup_graphics(mut commands: Commands) {
35+
commands.spawn(Camera3dBundle {
36+
transform: Transform::from_xyz(0.0, 3.0, -10.0)
37+
.looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
38+
..Default::default()
39+
});
40+
}
41+
42+
#[derive(Component)]
43+
pub struct WorldId(pub usize);
44+
45+
#[derive(Component)]
46+
struct Platform {
47+
starting_y: f32,
48+
}
49+
50+
fn move_platforms(time: Res<Time>, mut query: Query<(&mut Transform, &Platform)>) {
51+
for (mut transform, platform) in query.iter_mut() {
52+
transform.translation.y = platform.starting_y + -time.elapsed_seconds().sin();
53+
}
54+
}
55+
56+
/// Demonstrates despawning an entity removing it from its world
57+
// fn despawn_last(query: Query<(&PhysicsWorld, Entity)>, mut commands: Commands) {
58+
// for (bw, entity) in query.iter() {
59+
// if bw.world_id == N_WORLDS - 1 {
60+
// commands.entity(entity).despawn_recursive();
61+
// }
62+
// }
63+
// }
64+
65+
/// Demonstrates how easy it is to move one entity to another world.
66+
// fn change_world(mut query: Query<&mut PhysicsWorld>) {
67+
// for mut bw in query.iter_mut() {
68+
// if bw.world_id == 1 {
69+
// bw.world_id = 0;
70+
// }
71+
// }
72+
// }
73+
74+
pub fn setup_physics(
75+
context: Query<(Entity, &WorldId), With<RapierContext>>,
76+
mut commands: Commands,
77+
) {
78+
for (context_entity, id) in context.iter() {
79+
let id = id.0;
80+
81+
let color = [
82+
Hsla::hsl(220.0, 1.0, 0.3),
83+
Hsla::hsl(180.0, 1.0, 0.3),
84+
Hsla::hsl(260.0, 1.0, 0.7),
85+
][id % 3];
86+
87+
/*
88+
* Ground
89+
*/
90+
let ground_size = 5.1;
91+
let ground_height = 0.1;
92+
93+
let starting_y = (id as f32) * -0.5 - ground_height;
94+
95+
let mut platforms = commands.spawn((
96+
TransformBundle::from(Transform::from_xyz(0.0, starting_y, 0.0)),
97+
Collider::cuboid(ground_size, ground_height, ground_size),
98+
ColliderDebugColor(color),
99+
RapierContextEntityLink(context_entity),
100+
));
101+
if id == 1 {
102+
platforms.insert(Platform { starting_y });
103+
}
104+
105+
/*
106+
* Create the cube
107+
*/
108+
109+
commands.spawn((
110+
TransformBundle::from(Transform::from_xyz(0.0, 1.0 + id as f32 * 5.0, 0.0)),
111+
RigidBody::Dynamic,
112+
Collider::cuboid(0.5, 0.5, 0.5),
113+
ColliderDebugColor(color),
114+
RapierContextEntityLink(context_entity),
115+
));
116+
}
117+
}

Diff for: src/plugin/context/systemparams/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
mod rapier_context_access;
2+
3+
use bevy::{ecs::query::QueryData, prelude::Entity};
4+
pub use rapier_context_access::*;
5+
6+
use super::RapierContextEntityLink;
7+
8+
#[derive(QueryData)]
9+
pub struct RapierEntity {
10+
pub entity: Entity,
11+
pub rapier_context_link: &'static RapierContextEntityLink,
12+
}

Diff for: src/plugin/context/systemparams.rs renamed to src/plugin/context/systemparams/rapier_context_access.rs

+5-28
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use bevy::ecs::system::SystemParam;
22
use bevy::prelude::*;
33
use std::ops::{Deref, DerefMut};
44

5-
use super::{DefaultRapierContext, RapierContext, RapierContextEntityLink};
6-
5+
use super::super::{DefaultRapierContext, RapierContext, RapierContextEntityLink};
76
/// Utility [`SystemParam`] to easily access the default world [`RapierContext`] immutably
87
#[derive(SystemParam)]
98
pub struct DefaultRapierContextAccess<'w, 's> {
@@ -50,25 +49,14 @@ impl<'w, 's> DerefMut for DefaultRapierContextAccessMut<'w, 's> {
5049
#[derive(SystemParam)]
5150
pub struct RapierContextAccess<'w, 's> {
5251
rapier_context: Query<'w, 's, &'static RapierContext>,
53-
rapier_context_link: Query<'w, 's, &'static RapierContextEntityLink>,
5452
}
5553

5654
impl<'w, 's> RapierContextAccess<'w, 's> {
57-
pub fn link(&self, entity: Entity) -> &RapierContextEntityLink {
58-
self.rapier_context_link
59-
.get(entity)
60-
.expect("RapierContextAccess.link called on an entity without RapierContextEntityLink.")
61-
}
62-
pub fn follow_link(&self, link: RapierContextEntityLink) -> &'_ RapierContext {
55+
pub fn context(&self, link: RapierContextEntityLink) -> &'_ RapierContext {
6356
self.rapier_context
6457
.get(link.0)
6558
.expect("RapierContextEntityLink.0 refers to an entity without RapierContext.")
6659
}
67-
68-
pub fn context(&self, entity: Entity) -> &'_ RapierContext {
69-
let context_link = self.link(entity);
70-
self.follow_link(*context_link)
71-
}
7260
}
7361

7462
impl<'w, 's> Deref for RapierContextAccess<'w, 's> {
@@ -83,35 +71,24 @@ impl<'w, 's> Deref for RapierContextAccess<'w, 's> {
8371
#[derive(SystemParam)]
8472
pub struct RapierContextAccessMut<'w, 's> {
8573
pub rapier_context: Query<'w, 's, &'static mut RapierContext>,
86-
pub rapier_context_link: Query<'w, 's, &'static RapierContextEntityLink>,
8774
}
8875

8976
impl<'w, 's> RapierContextAccessMut<'w, 's> {
90-
pub fn link(&self, entity: Entity) -> &RapierContextEntityLink {
91-
self.rapier_context_link.get(entity).expect(
92-
"RapierContextAccessMut.link called on an entity without RapierContextEntityLink.",
93-
)
94-
}
95-
pub fn follow_link(&mut self, link: RapierContextEntityLink) -> &'_ mut RapierContext {
77+
pub fn context(&mut self, link: RapierContextEntityLink) -> &'_ mut RapierContext {
9678
self.rapier_context
9779
.get_mut(link.0)
9880
.expect("RapierContextEntityLink.0 refers to an entity without RapierContext.")
9981
.into_inner()
10082
}
101-
102-
pub fn context(&mut self, entity: Entity) -> &'_ mut RapierContext {
103-
let context_link = self.link(entity);
104-
self.follow_link(*context_link)
105-
}
10683
}
10784

10885
pub fn try_retrieve_context<'a>(
10986
link: Option<&RapierContextEntityLink>,
110-
context: &Query<(Entity, &mut RapierContext)>,
87+
context: &Query<Entity, With<RapierContext>>,
11188
) -> Result<Entity, Entity> {
11289
link.map_or_else(
11390
|| {
114-
let context_entity = context.iter().next().unwrap().0;
91+
let context_entity = context.iter().next().unwrap();
11592
Err(context_entity)
11693
},
11794
|link| Ok(link.0),

Diff for: src/plugin/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use self::context::{
44
DefaultRapierContextAccess, DefaultRapierContextAccessMut, RapierContextAccess,
55
RapierContextAccessMut,
66
},
7-
RapierContext,
7+
RapierContext, RapierContextEntityLink,
88
};
99
pub use self::plugin::{NoUserData, PhysicsSet, RapierPhysicsPlugin, RapierTransformPropagateSet};
1010

Diff for: src/plugin/plugin.rs

+13
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ where
4444
});
4545
self
4646
}
47+
/// Specifies a default configuration for the default `RapierContext`
48+
///
49+
/// If [`None`], no world will be initialized, you are responsible of creating and maintaining
50+
/// a [`RapierContext`] before creating any rapier entities (rigidbodies, colliders, joints),
51+
/// and as long as any [`RapierContextEntityLink`] has a reference to its [`RapierContext`].
52+
pub fn with_default_world(
53+
mut self,
54+
default_world_initialization: Option<RapierContextInitialization>,
55+
) -> Self {
56+
self.default_world_setup = default_world_initialization;
57+
self
58+
}
4759

4860
/// Specifies whether the plugin should setup each of its [`PhysicsStages`]
4961
/// (`true`), or if the user will set them up later (`false`).
@@ -244,6 +256,7 @@ where
244256
}
245257
}
246258

259+
#[derive(Resource)]
247260
pub struct RapierContextInitialization {
248261
pub length_unit: f32,
249262
}

Diff for: src/plugin/systems/character_controller.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::control::CharacterCollision;
22
use crate::dynamics::RapierRigidBodyHandle;
33
use crate::geometry::RapierColliderHandle;
4+
use crate::plugin::context::RapierContextEntityLink;
45
use crate::plugin::RapierConfiguration;
56
use crate::plugin::RapierContextAccessMut;
67
use crate::prelude::KinematicCharacterController;
@@ -19,6 +20,7 @@ pub fn update_character_controls(
1920
mut context_access: RapierContextAccessMut,
2021
mut character_controllers: Query<(
2122
Entity,
23+
&RapierContextEntityLink,
2224
&mut KinematicCharacterController,
2325
Option<&mut KinematicCharacterControllerOutput>,
2426
Option<&RapierColliderHandle>,
@@ -27,12 +29,18 @@ pub fn update_character_controls(
2729
)>,
2830
mut transforms: Query<&mut Transform>,
2931
) {
30-
for (entity, mut controller, output, collider_handle, body_handle, glob_transform) in
31-
character_controllers.iter_mut()
32+
for (
33+
entity,
34+
rapier_context_link,
35+
mut controller,
36+
output,
37+
collider_handle,
38+
body_handle,
39+
glob_transform,
40+
) in character_controllers.iter_mut()
3241
{
33-
let link = *context_access.link(entity);
34-
let context = context_access.follow_link(link);
35-
let config = config.get(link.0).unwrap();
42+
let context = context_access.context(*rapier_context_link);
43+
let config = config.get(rapier_context_link.0).unwrap();
3644
if let (Some(raw_controller), Some(translation)) =
3745
(controller.to_raw(), controller.translation)
3846
{

0 commit comments

Comments
 (0)