Skip to content

character-controller-self-hit-skip overview


Table of contents


utils

characterControllerSelfHitSkip

Safe forward-skip distance, from origin along direction, to clear a character controller's own capsule when raycasting from a point on or inside it - e.g. a first-person camera, which sits inside or right at the surface of its own capsule - without reading an exit point off the raycast result itself.

A raycast whose origin already lies inside a shape has no reliable way to report where it exits that shape: an adapter using a "solid" ray mode reports the containing shape hit at distance 0, from the origin again, not its far boundary, and doing this on some adapters but not others (e.g. Rapier3d's castRay(..., solid: true, ...) vs. Ammo's rayTest, which simply can't see the shape containing its own origin at all) makes any retry built on that reported point adapter-dependent - see ObjectGrabController.tryGrab()'s own doc for a case where exactly this broke self-hit recovery on one adapter while appearing to work fine on another.

Computed by sphere-tracing against the capsule's own exact distance field instead of guessed from radius alone: radius - distanceToCapsuleAxis(point, ...) is the exact signed distance from any point to the capsule's surface (a capsule is exactly "every point within radius of its own medial segment"), so repeatedly advancing by that remaining distance converges tightly onto the real exit point along direction, for any pitch - not just a near-horizontal look direction. A flat radius-sized skip (this function's first implementation) only clears the capsule when origin sits in its cylindrical midsection and direction is close to horizontal; a real, reproduced regression (found by reproducing the reporter's own exact in-game position) picked a first-person camera above that midsection - eyeHeight (0.7 by default) taller than the capsule's own half-height, so the camera already sits in the rounded top cap - looking down at a low, close prop: the flat radius skip landed the retry still measurably inside the capsule (its horizontal travel per meter shrinks with a steeper pitch, exactly where the cap's own cross-section is smaller too), so the second cast self-hit again and pick-up silently failed at that exact range. Sphere-tracing has no separate "which part of the capsule" case to get wrong - the same distance field describes the cylindrical body and both rounded caps continuously.

skin (0.05 by default) is added on top of the traced distance for ordinary float/engine surface tolerance. The result is clamped to at most 90% of maxDistance (the full ray length in play at the call site) so a capsule large relative to a short ray can't consume the entire cast.

Signature

export declare function characterControllerSelfHitSkip(
  origin: Point3,
  direction: Point3,
  capsuleCenter: Point3,
  up: Point3,
  radius: number,
  centersDistance: number,
  maxDistance: number,
  skin = 0.05
): number