Rigid-bodies
The real-time simulation of rigid-bodies subjected to forces and contacts is the main feature of a physics engine for video-games, robotics, or animation. Rigid-bodies are typically used to simulate the dynamics of non-deformable solids as well as to integrate the trajectory of solids which velocities are controlled by the user (e.g. moving platforms). On the other hand, rigid-bodies are not enough to simulate, e.g., cars, ragdolls, or robotic systems, as those use-cases require adding restrictions on the relative motion between their parts using joints.
Note that rigid-bodies are only responsible for the dynamics and kinematics of the solid. Colliders can be attached to a rigid-body to specify its shape and enable collision-detection. A rigid-body without collider attached to it will not be affected by contacts (because there is no shape to compute contact against).
Creation and insertion
A rigid-body is created by adding the RigidBody
component to an entity. Other components
like Transform
, Velocity
, Ccd
, etc. can be added for further customization of the
rigid-body.
The following example shows several initialization of components to customize rigid-body being built. The input values are just random so using this example as-is will not lead to a useful result.
- Example 2D
- Example 3D
use bevy::prelude::*;
use bevy_rapier2d::prelude::*;
commands
.spawn(RigidBody::Dynamic)
.insert(Transform::from_xyz(0.0, 5.0, 0.0))
.insert(Velocity {
linvel: Vec2::new(1.0, 2.0),
angvel: 0.2,
})
.insert(GravityScale(0.5))
.insert(Sleeping::disabled())
.insert(Ccd::enabled());
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
commands
.spawn(RigidBody::Dynamic)
.insert(Transform::from_xyz(0.0, 0.0, 0.0))
.insert(Velocity {
linvel: Vec3::new(0.0, 2.0, 0.0),
angvel: Vec3::new(0.2, 0.0, 0.0),
})
.insert(GravityScale(0.5))
.insert(Sleeping::disabled())
.insert(Ccd::enabled());
Typically, the inertia and center of mass are automatically set to the inertia and center of mass resulting from the shapes of the colliders attached to the rigid-body. But they can also be set manually.
Rigid-body type
There are four types of rigid-bodies, identified by the RigidBody
component:
RigidBodyType::Dynamic
: Indicates that the body is affected by external forces and contacts.RigidBodyType::Fixed
: Indicates the body cannot move. It acts as if it has an infinite mass and will not be affected by any force. It will continue to collide with dynamic bodies but not with fixed nor with kinematic bodies. This is typically used for the ground or for temporarily freezing a body.RigidBodyType::KinematicPositionBased
: Indicates that the body position must not be altered by the physics engine. The user is free to set its next position and the body velocity will be deduced at each update accordingly to ensure a realistic behavior of dynamic bodies in contact with it. This is typically used for moving platforms, elevators, etc.RigidBodyType::KinematicVelocityBased
: Indicates that the body velocity must not be altered by the physics engine. The user is free to set its velocity and the next body position will be deduced at each update accordingly to ensure a realistic behavior of dynamic bodies in contact with it. This is typically used for moving platforms, elevators, etc.
Both position-based and velocity-based kinematic bodies are mostly the same. Choosing between both is mostly a matter of preference between position-based control and velocity-based control.
The whole point of kinematic bodies is to let the user have total control over their trajectory. This means that kinematic bodies will simply ignore any contact force and go through walls and the ground. In other words: if you tell the kinematic to go somewhere, it will go there, no questions asked.
Taking obstacles into account needs to be done manually either by using scene queries to detect nearby obstacles, or by using the built-in character controller.
Position
The position of a rigid-body represents its location (translation) in 2D or 3D world-space, as well as its orientation (rotation).
stored in the standard Bevy Transform
component.
The position of a rigid-body can be set when creating it. It can also be set after its creation as illustrated below.
Directly changing the position of a rigid-body is equivalent to teleporting it: this is a not a physically realistic action! Teleporting a dynamic or kinematic bodies may result in odd behaviors especially if it teleports into a space occupied by other objects. For dynamic bodies, forces, impulses, or velocity modification should be preferred. For kinematic bodies, see the discussion after the examples below.
- Example 2D
- Example 3D
commands
.spawn(RigidBody::Dynamic)
.insert(Transform::from_xyz(0.0, 5.0, 0.0))
/* Change the position inside of a system. */
fn modify_body_translation(mut positions: Query<&mut Transform, With<RigidBody>>) {
for mut position in positions.iter_mut() {
position.translation.y += 0.1;
}
}
commands
.spawn(RigidBody::Dynamic)
.insert(Transform::from_xyz(0.0, 0.0, 0.0))
/* Change the position inside of a system. */
fn modify_body_translation(mut positions: Query<&mut Transform, With<RigidBody>>) {
for mut position in positions.iter_mut() {
position.translation.y += 0.1;
}
}
In order to move a dynamic rigid-body it is strongly discouraged to set its position directly as it may results in weird behaviors: it's as if the rigid-body teleports itself, which is a non-physical behavior. For dynamic bodies, it is recommended to either set its velocity or to apply forces or impulses.
For velocity-based kinematic bodies, it is recommended to set its velocity instead of setting its position directly.
For position-based kinematic bodies, it is recommended to modify its Transform
(changing its velocity won’t have
any effect). This will let the physics engine compute the fictitious velocity of the kinematic body for more
realistic intersections with other rigid-bodies.