Skip to main content

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_MoveShape is 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, the R3QueryOptions selecting these obstacles (see the filtering section), the timestep length, the shape of the character, and its current pose. The character’s shape is an R3SharedShape, e.g., created with r3BallSharedShape or cloned from a collider with r3Collider_CloneShape (and freed with r3FreeSharedShape once it is no longer needed).
  • r3KinematicCharacterController_Collisions and r3KinematicCharacterController_SolveCharacterCollisionImpulses are detailed in the collisions section.
// 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 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.
info

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.

warning

The built-in character controller does not support rotational movement. It only supports translations.