Skip to main content

collider_creation_and_insertion

A collider is created by a ColliderBuilder structure that is based on the builder pattern. Then it needs to be inserted into the physics world, i.e., into its ColliderSet, which is processed by the physics-pipeline, collision-pipeline, and query-pipeline.

info

The following example shows several setters that can be called to customize the collider being built. The input values are just random so using this example as-is will not lead to a useful result.

use rapier2d::prelude::*;
use std::f32::consts::PI;

// The world that will contain our colliders.
let mut world = PhysicsWorld::new();

// Builder for a ball-shaped collider.
let _ = ColliderBuilder::ball(0.5);
// Builder for a cuboid-shaped collider.
let _ = ColliderBuilder::cuboid(0.5, 0.2);
// Builder for a capsule-shaped collider. The capsule principal axis is the `x` coordinate axis.
let _ = ColliderBuilder::capsule_x(0.5, 0.2);
// Builder for a capsule-shaped collider. The capsule principal axis is the `y` coordinate axis.
let _ = ColliderBuilder::capsule_y(0.5, 0.2);
// Builder for a triangle-mesh-shaped collider.
let _ = ColliderBuilder::trimesh(vertices, indices);
// Builder for a heightfield-shaped collider.
let _ = ColliderBuilder::heightfield(heights, scale);
// Builder for a collider with the given shape.
let collider = ColliderBuilder::new(SharedShape::ball(0.5))
// The collider translation wrt. the body it is attached to.
// Default: the zero vector.
.translation(Vector::new(1.0, 2.0))
// The collider rotation wrt. the body it is attached to.
// Default: the identity rotation.
.rotation(PI)
// The collider position wrt. the body it is attached to.
// Default: the identity isometry.
.position(Pose::new(Vector::new(1.0, 2.0), PI))
// The collider density. If non-zero the collider's mass and angular inertia will be added
// to the inertial properties of the body it is attached to.
// Default: 1.0
.density(1.3)
// The friction coefficient of this collider.
// Default: ColliderBuilder::default_friction() == 0.5
.friction(0.8)
// Whether this collider is a sensor.
// Default: false
.sensor(true)
// All done, actually build the collider.
.build();

// Insert the collider into the world, without attaching it to a rigid-body.
let collider_handle = world.insert_collider(collider.clone(), None);

let rigid_body_handle = world.insert_body(RigidBodyBuilder::dynamic().build());
// Or insert the collider into the world and attach it to a rigid-body.
let handle = world.insert_collider(collider, Some(rigid_body_handle));

A collider is created by adding the Collider component. Other components like Transform, Sensor, Friction, etc. can be added to customize the collider. Removing one of these optional components afterwards resets the corresponding property of the collider to its default value.

info

The following example shows several initializations of components to customize collider being built. The input values are just random so using this example as-is will not lead to a useful result.

use bevy_rapier2d::prelude::*;

commands
.spawn(Collider::cuboid(1.0, 2.0))
.insert(Sensor)
.insert(Transform::from_xyz(2.0, 0.0, 0.0))
.insert(Friction::coefficient(0.7))
.insert(Restitution::coefficient(0.3))
.insert(ColliderMassProperties::Density(2.0));

A collider can optionally be attached to a rigid-body. Attaching a collider to a rigid-body will result in the rigid-body being affected by collisions. The collider's position will be automatically updated from the position of the rigid-body it is attached to. There are two ways of attaching a collider to a rigid-body. The second way allows you to attach multiple colliders to the same rigid-body:

  1. Attach the Collider to the same entity as the RigidBody.
  2. Attach the Collider to an entity that is a child of the entity containing the RigidBody.
// Attach a single collider to a rigid-body.
commands
.spawn(RigidBody::Dynamic)
.insert(Collider::ball(0.5));

// Attach a multiple colliders to a rigid-body.
commands
.spawn((RigidBody::Dynamic, GlobalTransform::default()))
.with_children(|children| {
children
.spawn(Collider::ball(0.5))
// Position the collider relative to the rigid-body.
.insert(Transform::from_xyz(0.0, 0.0, -1.0));
children
.spawn(Collider::ball(0.5))
// Position the collider relative to the rigid-body.
.insert(Transform::from_xyz(0.0, 0.0, 1.0));
});

A collider is created by a World.createCollider method. The initial state of the collider to create is described by an instance of the ColliderDesc class.

Each collider create by the physics world is given an integer identifier. This identifier is guaranteed to the different from any identifier of colliders still existing in the physics world. However, the identifier may be equal to the identifier of an older collider that has already been removed from the physics world with World.removeCollider.

info

The following example shows several setters that can be called to customize the collider being built. The input values are just random so using this example as-is will not lead to a useful result.

// The physics world.
let world = new RAPIER.World({ x: 0.0, y: -9.81 });

// Builder for a ball-shaped collider.
let example1 = RAPIER.ColliderDesc.ball(0.5);
// Builder for a cuboid-shaped collider.
let example2 = RAPIER.ColliderDesc.cuboid(0.5, 0.2);
// Builder for a capsule-shaped collider. The capsule principal axis is the `y` coordinate axis.
let example3 = RAPIER.ColliderDesc.capsule(0.5, 0.2);
// Builder for a triangle-mesh-shaped collider.
let example4 = RAPIER.ColliderDesc.trimesh(vertices, indices);
// Builder for a heightfield-shaped collider.
let example5 = RAPIER.ColliderDesc.heightfield(heights, scale);
// Builder for a collider with the given shape.
let colliderDesc = new RAPIER.ColliderDesc(new RAPIER.Ball(0.5))
// The collider translation wrt. the body it is attached to.
// Default: the zero vector.
.setTranslation(1.0, 2.0)
// The collider rotation wrt. the body it is attached to.
// Default: the identity rotation.
.setRotation(3.14)
// The collider density. If non-zero the collider's mass and angular inertia will be added
// to the inertial properties of the body it is attached to.
// Default: 1.0
.setDensity(1.3)
// The friction coefficient of this collider.
// Default: 0.5
.setFriction(0.8)
// Whether this collider is a sensor.
// Default: false
.setSensor(true);

// Create the collider, without attaching it to a rigid-body.
let handle = world.createCollider(colliderDesc);
// Or create the collider and attach it to a rigid-body.
let rigidBody = world.createRigidBody(RAPIER.RigidBodyDesc.dynamic());
let collider = world.createCollider(colliderDesc, rigidBody);

A collider is described by a R3ColliderDesc structure, initialized by one of its constructors (e.g. r3BallColliderDesc, r3CuboidColliderDesc, r3CapsuleYColliderDesc, or r3DefaultColliderDesc) which set meaningful default values to all its fields. Its geometric shape is given by its shape field, a R3ShapeDesc whose kind (e.g. R3_SHAPE_DESC_CUBOID) selects which of its fields are actually read. Then it needs to be inserted into the physics world: with r3InsertCollider to attach it to a rigid-body, or with r3InsertColliderWithoutParent otherwise. Both return the R3ColliderHandle identifying the new collider.

The arrays referenced by a description (vertex buffers, index buffers, compound children, etc.) are only borrowed until its insertion returns: they can be freed or reused right after. This is also the case of the shared shapes (R3SharedShape) a description can point to, with the R3_SHAPE_DESC_SHARED kind. A shared shape is an immutable geometry created by one of the r3...SharedShape functions (e.g. r3BallSharedShape), which can be given to any number of colliders, and must be freed with r3FreeSharedShape. Some shapes, like convex decompositions or voxels, can only be created as shared shapes.

info

The following example shows several fields that can be set to customize the collider being described. The input values are just random so using this example as-is will not lead to a useful result.

// The world that will contain our colliders.
R2World *world = r2NewWorld();

// Description of a ball-shaped collider.
R2ColliderDesc ball = r2BallColliderDesc(0.5);
// Description of a cuboid-shaped collider.
R2ColliderDesc cuboid = r2CuboidColliderDesc(r2Vector(0.5, 0.2));
// Description of a capsule-shaped collider. The capsule principal axis is the `x` coordinate axis.
R2ColliderDesc capsule_x = r2CapsuleXColliderDesc(0.5, 0.2);
// Description of a capsule-shaped collider. The capsule principal axis is the `y` coordinate axis.
R2ColliderDesc capsule_y = r2CapsuleYColliderDesc(0.5, 0.2);
// Description of a triangle-mesh-shaped collider.
R2ColliderDesc trimesh = r2DefaultColliderDesc();
r2ShapeDesc_SetTrimesh(&trimesh.shape, (R2VectorView){vertices, 3}, (R2TriangleView){indices, 1}, 0);
// Description of a heightfield-shaped collider.
R2ColliderDesc heightfield = r2DefaultColliderDesc();
heightfield.shape.kind = R2_SHAPE_DESC_HEIGHTFIELD;
heightfield.shape.heights = (R2RealView){heights, 4};
heightfield.shape.rows = 4;
heightfield.shape.columns = 1;
heightfield.shape.scale = scale;
// Description of a collider with the given shared shape.
R2SharedShape *shape = r2BallSharedShape(0.5);
R2ColliderDesc collider = r2DefaultColliderDesc();
collider.shape.kind = R2_SHAPE_DESC_SHARED;
collider.shape.sharedShape = shape;
// The collider translation wrt. the body it is attached to.
// Default: the zero vector.
collider.position.translation = r2Vector(1.0, 2.0);
// The collider rotation wrt. the body it is attached to.
// Default: the identity rotation.
collider.position.rotation = r2Rotation(R2_PI);
// The collider position wrt. the body it is attached to.
// Default: the identity pose.
collider.position = r2Pose(r2Vector(1.0, 2.0), r2Rotation(R2_PI));
// The collider density. If non-zero the collider's mass and angular inertia will be added
// to the inertial properties of the body it is attached to.
// Default: 1.0
collider.density = 1.3;
// The friction coefficient of this collider.
// Default: 0.5
collider.friction = 0.8;
// Whether this collider is a sensor.
// Default: 0
collider.isSensor = 1;

// Insert the collider into the world, without attaching it to a rigid-body.
R2ColliderHandle collider_handle = r2InsertColliderWithoutParent(world, &collider);

R2RigidBodyDesc rigid_body = r2DynamicRigidBodyDesc();
R2RigidBodyHandle rigid_body_handle = r2InsertRigidBody(world, &rigid_body);
// Or insert the collider into the world and attach it to a rigid-body.
R2ColliderHandle handle = r2InsertCollider(rigid_body_handle, &collider);
// The descriptions only borrow the shared shape: free it once it is no longer needed.
r2FreeSharedShape(shape);

A collider can also be disabled, by setting the enabled field of its description to 0 or, after its creation, with r3Collider_SetEnabled. A disabled collider is excluded from all the collision-detection and physics until it is enabled again, which is useful to "turn off" a collider temporarily without removing it (a collider is removed from the world with r3RemoveCollider).

A collider is created by a ColliderBuilder that is based on the builder pattern: it is returned by one of the shape constructors of the Collider class (e.g. Collider.ball, Collider.cuboid, or Collider.new which takes any SharedShape), each of its methods returns a builder with the corresponding property set, and its build method returns the Collider. These properties can also be given as keyword arguments of the shape constructors, e.g., Collider.ball(0.5, density=2.0, friction=0.3). Then it needs to be inserted into the physics world with PhysicsWorld.add_collider, which attaches it to the rigid-body given as its optional parent argument, and returns the ColliderHandle identifying the new collider. Colliders can also be inserted together with the rigid-body they are attached to with the colliders argument of PhysicsWorld.add_body. Once inserted, the collider is accessed with world.colliders[handle], which returns a live view: assigning one of its properties modifies the collider of the physics world directly.

info

The following example shows several setters that can be called to customize the collider being built. The input values are just random so using this example as-is will not lead to a useful result.

import math

import rapier3d as rp

# The world that will contain our colliders.
world = rp.PhysicsWorld()

# Builder for a ball-shaped collider.
_ = rp.Collider.ball(0.5)
# Builder for a cuboid-shaped collider.
_ = rp.Collider.cuboid(0.5, 0.2, 0.1)
# Builder for a capsule-shaped collider. The capsule principal axis is the `x` coordinate axis.
_ = rp.Collider.capsule_x(0.5, 0.2)
# Builder for a capsule-shaped collider. The capsule principal axis is the `y` coordinate axis.
_ = rp.Collider.capsule_y(0.5, 0.2)
# Builder for a capsule-shaped collider. The capsule principal axis is the `z` coordinate axis.
_ = rp.Collider.capsule_z(0.5, 0.2)
# Builder for a triangle-mesh-shaped collider.
_ = rp.Collider.trimesh(vertices, indices)
# Builder for a heightfield-shaped collider.
_ = rp.Collider.heightfield(heights, scale)
# Builder for a collider with the given shape.
collider = (
rp.Collider.new(rp.SharedShape.ball(0.5))
# The collider translation wrt. the body it is attached to.
# Default: the zero vector.
.translation((1.0, 2.0, 3.0))
# The collider rotation wrt. the body it is attached to, as a rotation vector (axis * angle).
# Default: the identity rotation.
.rotation((0.0, math.pi, 0.0))
# The collider position wrt. the body it is attached to.
# Default: the identity isometry.
.position(rp.Isometry3((1.0, 2.0, 3.0), rp.Rotation3.from_scaled_axis((0.0, math.pi, 0.0))))
# The collider density. If non-zero the collider's mass and angular inertia will be added
# to the inertial properties of the body it is attached to.
# Default: 1.0
.density(1.3)
# The friction coefficient of this collider.
# Default: 0.5
.friction(0.8)
# Whether this collider is a sensor.
# Default: False
.sensor(True)
# All done, actually build the collider.
.build()
)

# Insert the collider into the world, without attaching it to a rigid-body.
collider_handle = world.add_collider(collider)

rigid_body_handle = world.add_body(rp.RigidBody.dynamic())
# Or insert the collider into the world and attach it to a rigid-body.
handle = world.add_collider(collider, parent=rigid_body_handle)

A collider can also be disabled, with ColliderBuilder.enabled(False) or, after its creation, by setting its is_enabled property to False. A disabled collider is excluded from all the collision-detection and physics until it is enabled again, which is useful to "turn off" a collider temporarily without removing it (a collider is removed from the world with PhysicsWorld.remove_collider).