Skip to content

Commit

Permalink
add documentation for multiple pysics contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
Vrixyz committed Jan 14, 2025
1 parent 573658b commit 29a9f74
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 0 deletions.
126 changes: 126 additions & 0 deletions docs-examples/2d/bevy/examples/multiple_contexts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use bevy::{input::common_conditions::input_just_pressed, prelude::*};
use bevy_rapier2d::prelude::*;

const N_CONTEXTS: 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,
// DOCUSAURUS: MultipleContexts_no_default start
RapierPhysicsPlugin::<NoUserData>::default()
.with_custom_initialization(RapierContextInitialization::NoAutomaticRapierContext),
// DOCUSAURUS: MultipleContexts_no_default stop
RapierDebugRenderPlugin::default(),
))
.add_systems(
Startup,
((create_contexts, setup_physics).chain(), setup_graphics),
)
.add_systems(Update, move_platforms)
.add_systems(
Update,
change_context.run_if(input_just_pressed(KeyCode::KeyC)),
)
.run();
}

fn create_contexts(mut commands: Commands) {
for i in 0..N_CONTEXTS {
// DOCUSAURUS: MultipleContexts_new start
let mut context = commands.spawn(RapierContext::default());
// DOCUSAURUS: MultipleContexts_new stop
context.insert(ContextId(i));
if i == 0 {
// DOCUSAURUS: MultipleContexts_custom_default start
context.insert(DefaultRapierContext);
// DOCUSAURUS: MultipleContexts_custom_default stop
}
}
}

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

#[derive(Component)]
pub struct ContextId(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_secs().sin();
}
}

/// Demonstrates how easy it is to move one entity to another context.
fn change_context(
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 context of {} for context {}", e, link.0);
}
}

pub fn setup_physics(
context: Query<(Entity, &ContextId), 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((
Transform::from_xyz(0.0, starting_y, 0.0),
Collider::cuboid(ground_size, ground_height),
ColliderDebugColor(color),
RapierContextEntityLink(context_entity),
));
if id == 1 {
platforms.insert(Platform { starting_y });
}

/*
* Create the cube
*/

commands.spawn((
Transform::from_xyz(0.0, 1.0 + id as f32 * 5.0, 0.0),
RigidBody::Dynamic,
Collider::cuboid(0.5, 0.5),
ColliderDebugColor(color),
RapierContextEntityLink(context_entity),
));
}
}
41 changes: 41 additions & 0 deletions docs/user_guides/templates/multiple_contexts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
id: multiple_contexts
title: Multiple physics contexts
sidebar_label: Multiple physics contexts
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Some projects may require multiple physics contexts. For example, a game with multiple levels may want to have a
different physics context for each level. An AI-training project may want to simulate multiple physics contexts in parallel.

This page explains how to manage multiple physics contexts in Rapier.

## Components

By default, on `PreStartup`, `bevy_rapier` spawns a `RapierContext`, marked by a `DefaultRapierContext` component,
so most users can forget about multiple contexts support and use "easy" accessors such as `ReadDefaultRapierContext`.

If you don't want a default context to be spawned,
you can disable it using `RapierContextInitialization`:

```rust
<load path='/2d/bevy/examples/multiple_contexts.rs' marker='MultipleContexts_no_default' />
```

If you need multiple physics contexts, you can spawn them manually. Here is an example of how to spawn a new
physics context:

```rust
<load path='/2d/bevy/examples/multiple_contexts.rs' marker='MultipleContexts_new' />
```

Any entity managed by a `RapierContext` (colliders, joints, rigidbodies) has a `RapierContextEntityLink` component attached to it. This component
can be used to retrieve its corresponding physics context.

## Resources

`bevy_rapier` uses a `schedule` to parameterize its execution, this means all physics contexts share the same `TimestepMode` resource:

all physics contexts execute at the same time, at the same rate.
3 changes: 3 additions & 0 deletions sidebar_docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ let specialized_guides = {
'user_guides/bevy_plugin/character_controller',
'user_guides/bevy_plugin/scene_queries',
'user_guides/bevy_plugin/advanced_collision_detection',

// bevy specific
'user_guides/bevy_plugin/multiple_contexts',
'user_guides/bevy_plugin/common_mistakes',
],
'JavaScript': [
Expand Down

0 comments on commit 29a9f74

Please sign in to comment.