Rigid-body simulation
Once the Rapier WASM module has been loaded asynchronously, we can create and populate a physics world. There are
a few significant differences between the Rust API of Rapier and the JS API. The most notable difference is that the
JS version of Rapier does not split the physics simulation into multiple components. Instead, it is only needed to
instantiate one World
class to obtain a fully functional physics pipeline. It is then possible to advance the simulation
step by step inside of the game loop using its world.step()
method:
- Example 2D
- Example 3D
info
Note that the use of RAPIER.Vector2
and RAPIER.Vector3
is not mandatory. Any
object with fields x, y
(for 2D), and z
(for 3D) will work as well.
This World
class is responsible for creating/deleting rigid bodies, colliders, and joints, advancing the simulation, retrieving
contact events, etc. Now that it is created, the next step is to create rigid-bodies and colliders.
#
Creating rigid-bodiesA rigid-body is the simplest type of body supported by Rapier. It can be seen as the aggregation of a position, orientation, and mass properties (rotational inertia tensor, mass, and center of mass). It does not hold any information regarding its shape which can optionally be specified by attaching one or multiple colliders to it. A rigid-body with no collider will be affected by all the forces the world is aware of, including joints attached to it, but not by contacts (because it does not have any shape that can be collided to).
To create a rigid-body, we must first initialize its RigidBodyDesc
descriptor:
- Example 2D
- Example 3D
The RigidBodyDesc
allows us to define the initial state of the rigid-body, including its initial position, orientation,
velocity, etc. This descriptor is then passed to the physics World
to actually create the rigid-body and add it to the
world. The world.createRigidBody(desc)
returns a reference to the newly created rigid-body.
note
The RigidBodyDesc
and the ColliderDesc
will will see afterwards follow the builder pattern.
If you run this example, you will see that the rigid-body position is always equal to (0.0, 1.0, 0.0)
. It is not
affected by the gravity because it does not have any mass yet. The mass of a rigid-body is automatically computed
from the colliders attached to it.
#
Creating collidersColliders represent the geometric shapes that generate contacts and proximity events when they touch. They are also used to automatically compute the mass and angular inertia of the rigid-body they are attached to.
Similarly to the rigid-bodies, the creation of a collider required the initialization of a ColliderDesc
class. This
collider description contains the shape, position, density, etc., of the collider to be created. This description
can then be passed to the world.createCollider(desc, parentHandle)
function to create the actual collider and attach it to
the given rigidBody
:
- Example 2D
- Example 3D
With this collider created and attached to our rigidBody
, we can see that the position printed in the console
changes as the simulation progresses. Because our collider has a non-zero density, the rigid-body it is attached
to will have a non-zero mass, which makes it affected by gravity.
What if we don't want our object to fall down indefinitely? We can easily add another rigid-body for it to collide with. This other rigid-body will be static and represent the ground. A static rigid-body isn't affected by any forces so it won't fall because of gravity:
- Example 2D
- Example 3D
Now that the ground exists, the position of our dynamic rigid-body will stop decreasing once it hits the ground.
#
Applying forces and impulsesSo far the only force affecting our rigid-bodies were the gravity and the contact forces created by Rapier when their colliders collide. It is possible to apply manual forces and impulses to a rigid-body in order to alter its trajectory:
- Example 2D
- Example 3D
A force or torque applied this way will affect the acceleration of the rigid-body during the next timestep according to the usual equation where is the acceleration and the force.
info
All forces and torques applied to a rigid-body are cleared at the end of each timestep. To apply a continuous force
or torque to rigid-body, it is necessary to call .applyForce
and .applyTorque
before each world.step
.
An impulse or torque impulse on the other hand induce an instantaneous velocity change where is the impulse and the rigid-body velocity.
#
Removing a rigid-bodyOnce we are done with a rigid-body, it is possible to remove it from the physics world. doing so is as simple as calling
world.removeRigidBody(rigidBody);
. However, we need to be careful afterwards because:
- The
rigidBody
JS object will become invalid: most of its method will crash if called. - All the joints and colliders attached to
rigidBody
will automatically be removed from theWorld
. This implies that their corresponding JS objects will also become invalid and will lead to crashes if they are used any further. - The handle of this removed rigid-body may be re-used for another newly created rigid-body. In the future, we may change this behavior to only return unique handles.