ludic/packages/ludic.character/walk.ludic
Orkuncakilkaya e909ec122c feat(character): 16.8 - on land a physics walker moves the body (CharacterGround.walk); the package's own gravity, ballistic air and slope-probe refusal are gone
The package keeps the rules and hands them over each step: speed and heading, whether a jump
leaves, CHAR_STEP and the boots' slope limit. The walker (Jolt CharacterVirtual) does gravity,
landing, steps, slopes and following the ground down. Too steep is ground too steep facing the way
the body wanted to go; stepping off an edge is not. ludic.physics: phys_walker_move (follow the body
if something else moved it, then step), the slope limit, the jump always honoured. The character's
tests run on a real Jolt walker over the same fake world: 15 pass, a knee-high boulder now a step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 00:47:14 +03:00

65 lines
3.1 KiB
Text

# walk.ludic - the step itself: swimming, in the air, or on the ground; the distance, for the gait
function chr_travel(character_st: mut CharacterState, dx: float, dz: float, fx: float, fz: float, jump: bool, dt: float) -> float {
if character_st.chr_swim {
chr_swim_tick(character_st, dx, dz, jump, dt)
return character_st.chr_speed * dt
}
return chr_walk(character_st, fx, fz, dx, dz, jump, dt)
}
# on land the game's walker moves the body (CharacterGround.walk): gravity, landing, a step up to
# CHAR_STEP, a slope up to what the boots take. The rules stay here: how fast, where, when a jump
# leaves, when the lake takes the body, and what is said about it.
function chr_walk(character_st: mut CharacterState, fx: float, fz: float, dx: float, dz: float, jump: bool, dt: float) -> float {
var vx = fx * character_st.chr_speed
var vz = fz * character_st.chr_speed
var up = 0.0
if character_st.chr_air {
character_st.chr_air_vx = character_st.chr_air_vx + dx * (4.0 * dt)
character_st.chr_air_vz = character_st.chr_air_vz + dz * (4.0 * dt)
vx = character_st.chr_air_vx
vz = character_st.chr_air_vz
} else if jump and character_st.chr_can_run and character_st.chr_land < 0.05 {
up = 5.0
character_st.chr_air_vx = vx
character_st.chr_air_vz = vz
chr_say(character_st, CHAR_JUMPED, 0.0)
}
let slope = Math.atan2(CharacterGround.slope_limit(), 1.0) * 57.29578
let g = CharacterGround.walk(character_st.chr_x, character_st.chr_y, character_st.chr_z, vx, vz, up, CHAR_STEP, slope, dt)
return chr_walked(character_st, g, up > 0.0, dt)
}
# where the walker put the body, and what that means: the lake, a landing, a slope too steep
function chr_walked(character_st: mut CharacterState, g: int, jumped: bool, dt: float) -> float {
let nx = CharacterGround.walked_x()
let ny = CharacterGround.walked_y()
let nz = CharacterGround.walked_z()
if ny < CharacterGround.water(nx, nz) - CHAR_WADE_MAX {
chr_enter_water(character_st, nx, nz)
return character_st.chr_speed * dt
}
let was_air = character_st.chr_air
character_st.chr_air = g == CHAR_WALK_AIR or jumped
if was_air and not character_st.chr_air { chr_landed(character_st) }
if g == CHAR_WALK_STEEP and not character_st.chr_air {
if not (character_st.chr_steep > 0.0) { chr_say(character_st, CHAR_TOO_STEEP, ny - character_st.chr_y) }
character_st.chr_steep = 1.2
character_st.chr_speed = 0.0
}
let mx = nx - character_st.chr_x
let mz = nz - character_st.chr_z
character_st.chr_step = Math.sqrt(mx * mx + mz * mz)
character_st.chr_vy = (ny - character_st.chr_y) / Math.max(dt, 0.0001)
character_st.chr_x = nx
character_st.chr_y = ny
character_st.chr_z = nz
if character_st.chr_air { return character_st.chr_speed * (dt * 0.4) }
return character_st.chr_speed * dt
}
function chr_landed(character_st: mut CharacterState) -> void {
character_st.chr_land = 0.22
character_st.chr_speed = Math.sqrt(character_st.chr_air_vx * character_st.chr_air_vx + character_st.chr_air_vz * character_st.chr_air_vz)
chr_say(character_st, CHAR_LANDED, character_st.chr_speed)
}