Skip to main content

Getting started

Bevy is an efficient, simple-to-use, and fast-to-compile data-driven game engine written in Rust. It is based on the ECS (Entity-Component-System) paradigm and allows the definition of plugins, i.e., sets of components, systems, and resources that share a common objective.

The bevy_rapier2d and bevy_rapier3d crates integrate Rapier to Bevy using its plugin system. Note that the development version of bevy_rapier tracks the main branch of Bevy, whereas each release of bevy_rapier targets one specific release of Bevy: make sure to pick the version of bevy_rapier matching the version of Bevy you are using.

The following features are enabled by default:

  • debug-render-2d/debug-render-3d: enables the debug-renderer plugin RapierDebugRenderPlugin, which draws what the physics engine sees with Bevy's gizmos. bevy_rapier2d enables debug-render-2d and bevy_rapier3d enables debug-render-3d. Both crates also have a debug-render feature, which is an alias of the one matching their dimension.
  • picking-backend: enables the RapierPickingPlugin, a backend of bevy_picking based on ray-casts against the colliders.
  • async-collider: enables the AsyncCollider and AsyncSceneCollider components (3D only) which compute colliders from Bevy meshes, or from the meshes of a Bevy scene, once they are loaded.
  • to-bevy-mesh: enables the conversion of a collider shape into a Bevy Mesh, e.g., with Mesh::try_from(&collider).

Note that these default features pull some rendering-related parts of Bevy. A headless application (e.g. a game server) can disable them with default-features = false.

To get the best of bevy_rapier multiple features can be enabled optionally:

  • parallel: enables parallelism of the physics pipeline with the rayon crate.
  • simd8: widens the SIMD of the solver from 4 to 8 lanes. Note that the compiler only emits actual 256-bit instructions on an AVX-enabled target (e.g. with RUSTFLAGS="-C target-cpu=native"); otherwise the 8-lanes path will be much slower (it will be emulated as two 128-bit halves).
  • serde-serialize: enables serialization of the physics contexts with serde.
  • enhanced-determinism: enables cross-platform determinism (assuming the rest of your code is also deterministic) across all 32-bit and 64-bit platforms that implements the IEEE 754-2008 standard strictly. This includes most modern processors as well as WASM targets. It cannot be enabled at the same time as simd8.
  • block-solver: couples the two normal constraints of a contact pair into a single 2x2 solve.
  • fem: adds an alternative FEM solver for the soft-bodies, selected body by body.
  • profiler: enables the internal profiler of Rapier, which gives the time spent by each stage of a timestep. This is needed for the timings measured by the RapierDiagnosticsPlugin, except for the total step time.
  • unsync-callbacks: drops the Sync requirement from the callbacks of Rapier. As a side effect, this removes the thread-pool API, therefore RapierConfiguration::num_threads is ignored.
  • solver-bounds-checks: adds bounds-checks to some unchecked accesses of the constraints solver. This is only meant for debugging.
  • rapier-debug-render: enables the debug-render pipeline of Rapier alone, without the Bevy rendering dependencies, e.g., to implement your own DebugRenderBackend.
  • urdf, mjcf, and meshloader (3D only): enable the scene loaders of robots described by URDF or MJCF files, and of colliders built from mesh files.

Cargo example​

To use these crates, the first step is to add a dependency to your Cargo.toml:

[dependencies]
# TODO: Replace the * by the latest version numbers.
bevy = "*"
bevy_rapier2d = "*"

If you need to enable some Rapier features like parallelism, serialization, or determinism, you can enable them on bevy_rapier directly.

[dependencies]
# TODO: Replace the * by the latest version numbers.
bevy = "*"
bevy_rapier2d = { version = "*", features = [ "parallel", "serde-serialize" ] }

Basic simulation example​

Here is a basic example of main.rs file. This creates a ball bouncing on a fixed ground. Details about the elements used in this examples are given in subsequent pages of this guide.

info

The use bevy_rapier2d::prelude::* or use bevy_rapier3d::prelude::* will import all the most common types needed to work with bevy_rapier.

use bevy::prelude::*;
use bevy_rapier2d::prelude::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
.add_plugins(RapierDebugRenderPlugin::default())
.add_systems(Startup, setup_graphics)
.add_systems(Startup, setup_physics)
.add_systems(Update, print_ball_altitude)
.run();
}

fn setup_graphics(mut commands: Commands) {
// Add a camera so we can see the debug-render.
commands.spawn(Camera2d::default());
}

fn setup_physics(mut commands: Commands) {
/* Create the ground. */
commands
.spawn(Collider::cuboid(500.0, 50.0))
.insert(Transform::from_xyz(0.0, -100.0, 0.0));

/* Create the bouncing ball. */
commands
.spawn(RigidBody::Dynamic)
.insert(Collider::ball(50.0))
.insert(Restitution::coefficient(0.7))
.insert(Transform::from_xyz(0.0, 400.0, 0.0));
}

fn print_ball_altitude(positions: Query<&Transform, With<RigidBody>>) {
for transform in positions.iter() {
println!("Ball altitude: {}", transform.translation.y);
}
}

Plugins​

The RapierPhysicsPlugin is the plugin responsible for the physics simulation. Its type parameter selects the physics hooks of the simulation (NoUserData when you don't need any). When it is added to the app, it spawns the default physics context (see the simulation structures page), and adds the systems synchronizing the components of your entities with Rapier, stepping the simulation, and writing the results back into the components. Its constructors and builder methods control how this is set up:

  • RapierPhysicsPlugin::pixels_per_meter (2D only) and RapierPhysicsPlugin::with_length_unit set the length unit of the default physics context.
  • RapierPhysicsPlugin::in_fixed_schedule and RapierPhysicsPlugin::in_schedule run the physics systems in FixedUpdate or in any other schedule instead of PostUpdate.
  • RapierPhysicsPlugin::with_custom_initialization changes the initial parameters of the default physics context (see the integration parameters page), or disables its creation (see the multiple physics contexts page).
  • RapierPhysicsPlugin::with_default_system_setup(false) doesn't add the physics systems at all, so you can add them yourself (e.g. to split them across different schedules) with RapierPhysicsPlugin::get_systems.

Other plugins are provided for optional features:

  • RapierDebugRenderPlugin enables the debug-renderer.
  • RapierDiagnosticsPlugin measures the simulation (step time, number of bodies, colliders, contacts, etc.) with Bevy's diagnostics. See the diagnostics section.
  • RapierPickingPlugin enables the picking backend (with the picking-backend feature).
  • MjcfPlugin drives the actuators of the models loaded from MJCF files (3D only, with the mjcf feature). See the scene loaders page.

For example, the following runs the physics in FixedUpdate (which is generally what a game with networking or replays needs, since the simulation then advances at the same rate whatever the frame rate), with the debug-renderer and the diagnostics enabled:

App::new()
.add_plugins(DefaultPlugins)
// Advance the simulation by the same dt at each run of the `FixedUpdate` schedule
// (which runs 64 times per second by default).
.insert_resource(TimestepMode::Fixed {
dt: 1.0 / 64.0,
substeps: 1,
})
.add_plugins((
// 100 pixels make one meter, and the physics systems run in `FixedUpdate` instead
// of `PostUpdate`.
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0).in_fixed_schedule(),
// Draw what the physics engine sees.
RapierDebugRenderPlugin::default(),
// Measure the simulation with Bevy's diagnostics (must run in the physics schedule).
RapierDiagnosticsPlugin::default().in_schedule(FixedUpdate),
))
info

When the physics runs in FixedUpdate, it is recommended to use a TimestepMode::Fixed timestep mode, so each run of the schedule advances the simulation by the same amount of time. See the integration parameters page for details about the timestep modes.

The debug renderer​

The bevy_rapier plugin comes with a debug-renderer to help visualize exactly what the physics-engine sees. This can help fixing some bugs like colliders not being properly aligned with your graphics representation. The debug-renderer is enabled by:

  1. Enabling the debug-render-2d or debug-render-3d cargo feature of bevy_rapier (they are enabled by default).
  2. Adding the plugin RapierDebugRenderPlugin to the Bevy app.

What it draws can be configured, as described in the debug-renderer page.

debug-render