character_controller_setup
The character controller implementation is exposed as the R3KinematicCharacterController object, created with its
default configuration by r3NewKinematicCharacterController, and freed by r3FreeKinematicCharacterController. This
object only contains information about the character controller’s behavior (as well as the collisions recorded by its
last movement calculation, see the collisions section). It does not contain
any collider-specific or rigid-body-specific information like handles, velocities, positions, etc. Therefore, the same
R3KinematicCharacterController can be used to control multiple rigid-bodies/colliders if they rely on the same set
of parameters. Its behavior is configured by its setters (detailed in the next sections), and it is used through the
following functions:
r3KinematicCharacterController_MoveShapeis responsible for calculating the possible movement of a character based on the desired movement, obstacles, and character controller options. It is given the world containing the obstacles, theR3QueryOptionsselecting these obstacles (see the filtering section), the timestep length, the shape of the character, and its current pose. The character’s shape is anR3SharedShape, e.g., created withr3BallSharedShapeor cloned from a collider withr3Collider_CloneShape(and freed withr3FreeSharedShapeonce it is no longer needed).r3KinematicCharacterController_Collisionsandr3KinematicCharacterController_SolveCharacterCollisionImpulsesare detailed in the collisions section.
- Example 2D
- Example 3D
// The translation we would like to apply if there were no obstacles.
R2Vector desired_translation = r2Vector(1.0, -2.0);
// Create the character controller, here with the default configuration.
R2KinematicCharacterController *character_controller = r2NewKinematicCharacterController();
// Init the query options.
R2QueryOptions options = r2DefaultQueryOptions();
// Make sure the character we are trying to move isn't considered an obstacle.
options.filter.exclude_rigid_body = rigid_body_handle;
// Calculate the possible movement.
R2CharacterMovement corrected_movement = r2KinematicCharacterController_MoveShape(
world, // The world containing the obstacles.
&options, // The query options (NULL for the default ones).
character_controller, // The character controller.
dt, // The timestep length (can be set to r2TimeStep(world)).
character_shape, // The character's shape.
character_pos, // The character's initial position.
desired_translation);
// TODO: apply the `corrected_movement.translation` to the rigid-body or collider based on the rules described below.
// Free the character controller once it is no longer needed.
r2FreeKinematicCharacterController(character_controller);
// The translation we would like to apply if there were no obstacles.
R3Vector desired_translation = r3Vector(1.0, -2.0, 3.0);
// Create the character controller, here with the default configuration.
R3KinematicCharacterController *character_controller = r3NewKinematicCharacterController();
// Init the query options.
R3QueryOptions options = r3DefaultQueryOptions();
// Make sure the character we are trying to move isn't considered an obstacle.
options.filter.exclude_rigid_body = rigid_body_handle;
// Calculate the possible movement.
R3CharacterMovement corrected_movement = r3KinematicCharacterController_MoveShape(
world, // The world containing the obstacles.
&options, // The query options (NULL for the default ones).
character_controller, // The character controller.
dt, // The timestep length (can be set to r3TimeStep(world)).
character_shape, // The character's shape.
character_pos, // The character's initial position.
desired_translation);
// TODO: apply the `corrected_movement.translation` to the rigid-body or collider based on the rules described below.
// Free the character controller once it is no longer needed.
r3FreeKinematicCharacterController(character_controller);
The obstacles are taken at the positions they had at the end of the last r3Step (or r3DetectCollisions). The
returned R3CharacterMovement contains the corrected movement (its translation field), as well as whether the
character touches the ground at its final position (its grounded field), and whether it is sliding down a slope that
is too steep to climb (its is_sliding_down_slope field). The corrected movement isn’t applied automatically: 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 (with
r3Collider_SetTranslation) to the corrected movement added to its current position. - A velocity-based kinematic rigid-body: set its velocity (with
r3RigidBody_SetLinvel) to the computed movement divided by the timestep length. - A position-based kinematic rigid-body: set its next kinematic position (with
r3RigidBody_SetNextKinematicTranslation) 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.