character_controller_setup
The character controller implementation is exposed as the KinematicCharacterController structure. This structure only
contains information about the character controller’s behavior. It does not contain any collider-specific or
rigid-body-specific information like handles, velocities, positions, etc. Therefore, the same instance of KinematicCharacterController
can be used to control multiple rigid-bodies/colliders if they rely on the same set of parameters.
The KinematicCharacterController exposes only two methods:
move_shapeis responsible for calculating the possible movement of a character based on the desired movement, obstacles, and character controller options.solve_character_collision_impulsesis detailed in the collisions section.
- Example 2D
- Example 3D
// The translation we would like to apply if there were no obstacles.
let desired_translation = vector![1.0, -2.0];
// Create the character controller, here with the default configuration.
let character_controller = KinematicCharacterController::default();
// Init the query pipeline.
let filter = QueryFilter::default()
// Make sure the character we are trying to move isn’t considered an obstacle.
.exclude_rigid_body(rigid_body_handle);
let query_pipeline = broad_phase.as_query_pipeline(
narrow_phase.query_dispatcher(),
&bodies,
&colliders,
filter,
);
// Calculate the possible movement.
let corrected_movement = character_controller.move_shape(
dt, // The timestep length (can be set to SimulationSettings::dt).
&query_pipeline, // The query pipeline.
character_shape, // The character’s shape.
character_pos, // The character’s initial position.
desired_translation,
|_| {}, // We don’t care about events in this example.
);
// TODO: apply the `corrected_movement.translation` to the rigid-body or collider based on the rules described below.
// The translation we would like to apply if there were no obstacles.
let desired_translation = vector![1.0, -2.0, 3.0];
// Create the character controller, here with the default configuration.
let character_controller = KinematicCharacterController::default();
// Init the query pipeline.
let filter = QueryFilter::default()
// Make sure the character we are trying to move isn’t considered an obstacle.
.exclude_rigid_body(rigid_body_handle);
let query_pipeline = broad_phase.as_query_pipeline(
narrow_phase.query_dispatcher(),
&bodies,
&colliders,
filter,
);
// Calculate the possible movement.
let corrected_movement = character_controller.move_shape(
dt, // The timestep length (can be set to SimulationSettings::dt).
&query_pipeline, // The query pipelien.
character_shape, // The character’s shape.
character_pos, // The character’s initial position.
desired_translation,
|_| {}, // We don’t care about events in this example.
);
// TODO: apply the `corrected_movement.translation` to the rigid-body or collider based on the rules described bellow.
The recommended way to update the character’s position depends on its representation:
- A collider not attached to any rigid-body: set the collider’s position directly to the corrected movement added to its current position.
- A velocity-based kinematic rigid-body: set its velocity to the computed movement divided by the timestep length.
- A position-based kinematic rigid-body: set its next kinematic position to the corrected movement added to its current position.
The character’s shape may be any shape supported by Rapier. However, it is recommended to either use a cuboid, a ball, or a capsule since they involve less computations and less numerical approximations.
The built-in character controller does not support rotational movement. It only supports translations.