Builtin Library
README.md
ground
Ground-probing and slope-math helpers for the character controller. A downward raycast helper plus two pure vector helpers (slope angle, plane projection). No state.
Exports
M.cast(x: number, y: number, z: number, skinWidth: number, maxDist: number, selfId: string, riseDist: number?) -> hit?— cast a ray downward from(x, y + riseDist + skinWidth, z), reachingmaxDistbelow the feet. The returned hit'sdistanceis adjusted to be relative to the feet, not the ray origin, and is negative for ground standing above them. The ray passes through the colliders the body carries (selfIdand every entity parented under it), so a prop held at the feet is never the ground.M.slopeAngle(nx: number, ny: number, nz: number) -> number— degrees between the supplied normal and world up. Returns 0 on a zero-length normal.M.projectOnSlope(moveX, moveY, moveZ, normalX, normalY, normalZ) -> (number, number, number)— project a movement vector onto the plane perpendicular to a normal:v - (v . n) * n.
Usage
local Ground = require("@builtin::systems.characterController.characterController.physics.ground")
local hit = Ground.cast(px, py, pz, 0.01, 0.2, selfId)
if hit then
local angle = Ground.slopeAngle(hit.normal.x, hit.normal.y, hit.normal.z)
if angle <= 45 then
-- walkable
end
end
local px, py, pz = Ground.projectOnSlope(dx, 0, dz, nx, ny, nz)
Notes
castshifts the origin up byskinWidthto avoid starting the ray inside the ground when the character is sitting on a contact, then subtractsskinWidthback offhit.distanceso callers see the true distance from the feet.riseDistraises the origin further, so the ray also covers ground that stands above the feet — the ground a walking character climbs into. A hit up there reports a negativedistance: how far the character rises to stand on it.slopeAngleclampscos(angle)into[-1, 1]beforeacos— callers don't need to normalise the input.projectOnSlopedoes not normalise the surface normal; callers should pass a unit normal (raycast normals already are).