▣
module · drop-in viewer
machine
State machine helper for the builtin character controller. Owns the state table shape (grounded / falling / sliding / wall contact / blocked / jump counts / moving-platform tracking) and the timing rules (coyote time, jump buffering, multi-jump cap) that the controller consumes e…
by·posted 2mo ago
What it does
machine
State machine helper for the builtin character controller. Owns the
state table shape (grounded / falling / sliding / wall contact /
blocked / jump counts / moving-platform tracking) and the timing rules
(coyote time, jump buffering, multi-jump cap) that the controller
consumes each tick.
Pure logic — no engine globals beyond entity() for platform position
lookups.
Exports
M.new() -> State— allocate a fresh state with default values.M.update(state: State, groundHit, wallHit, ceilHit, vel, config, dt, now)— run ground/wall sensors and update grounding, timing, and moving-platform fields.M.shouldJump(state: State, config: Config, now: number) -> boolean— decide whether a queued jump should fire this tick.M.executeJump(state: State, config: Config) -> number— mutate state for a jump and return the Y velocity to apply.M.requestJump(state: State, now: number)— register a jump press (may be deferred via jump buffer).M.clearJumpRequest(state: State)— drop any pending jump request.
Types:
Vec3 = { x: number, y: number, z: number }RaycastHit = { point?, normal: Vec3, entityId?, _sliding?, _blocked? }— shape ofPhysics.raycast-style hits the controller produces.State = { grounded, falling, sliding, wallContact, blocked, wallNormal, velocity, groundNormal, slopeAngle, jumpCount, timeSinceGrounded, timeSinceWallContact, onMovingPlatform, platformEntity, ...internal timing fields }Config = { maxJumps?, coyoteTime?, jumpBuffer?, jumpForce? }— character tuning fields read each tick.
Usage
local State = require("@builtin::systems.characterController.characterController.state.machine")
local s = State.new()
State.update(s, groundHit, wallHit, ceilHit, vel, config, dt, now)
if State.shouldJump(s, config, now) then
local jumpY = State.executeJump(s, config)
end
Notes
updateis destructive — it mutatesstatein place. The state table is the single source of truth; callers should not rebuild it each tick.- The jump-buffer window persists across frames;
shouldJumpconsumes it via the_jumpBufferTime/_jumpRequestedpair. - Moving-platform detection relies on the platform entity's
localPosition— non-entity hits leaveonMovingPlatform = false. blockedis true on a frame the wall pass left the character with none of the horizontal movement it asked for —wallHit._blocked, whichVelocity.resolvemarks. It is what tells a character standing still apart from one whose walk is being refused.ceilHitis accepted for API symmetry but currently unused; future ceiling-bump handling will read it without changing the signature.
Discussion
Scoped to this part · feeds back into the world's score.
Sign in to post.sign in
No comments yet. Be the first.