NEON-29: Reliable descend lip peel + capped floor snap

Wall/slide heuristics missed many step→floor stalls (e.g. far floor clicks).
While descending with is_on_floor, always add gravity to vy before move_and_slide.
Cap floor_snap_length when feet stay meaningfully above the goal so strong snap
cannot yank the capsule back onto the step internal edge; cap lifts near landing
(feet within 8 cm of goal Y). Apply snap helper on nomap + descend branches.
pull/41/head
VinPropane 2026-04-11 23:58:09 -04:00
parent f70dbe8f88
commit cc63e9bdd7
1 changed files with 26 additions and 17 deletions

View File

@ -28,6 +28,9 @@ const IDLE_MANUAL_CORRECTION_MAX_TICKS: int = 8
## Horizontal nudge per tick for rim / straddle settle (**`_maybe_idle_rim_settle_nudge`**).
const IDLE_RIM_SETTLE_STEP: float = 0.004
const DESCEND_GOAL_Y_MARGIN: float = 0.06
## Cap floor snap while descending from a step so Jolt cannot snap the capsule back onto the
## upper surface across an internal edge (lip hang). Relaxed once feet are near the goal height.
const DESCEND_LIP_SNAP_CAP: float = 0.12
## Y lift when blocked by wall-ish slide but nav goal is higher (stepped bumps).
const WALK_STEP_ASSIST_DELTA: float = 0.11
## Skip assist when horizontal velocity already aligns enough with want-dir (corners slide slowly).
@ -254,24 +257,28 @@ func _apply_walk_air_gravity(delta: float) -> void:
if not is_on_floor():
velocity += g_step
return
# Descending toward a lower surface (e.g. first terrace step → main floor): rim / internal
# edge contact can keep `is_on_floor()` true on the upper surface while the step's vertical
# face zeros horizontal motion. With vy forced to 0 by `_set_horizontal_velocity_toward`,
# no gravity ran and the capsule could hang until a new click retargeted. Shallow 0.3 m
# drops hit this more often than taller platform→floor descents.
var feet_on_floor: float = capsule_feet_y(global_position.y, CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS)
# Descending toward a lower surface: `is_on_floor()` can stay true on the upper step while
# horizontal motion is blocked (internal edge / lip). `is_on_wall()` is unreliable here, and
# a far floor click keeps large horiz delta so wall heuristics never ran. Always integrate
# downward acceleration while on the upper surface; `move_and_slide` + floor collision
# absorbs it on flat spans, and it peels the capsule off the lip when forward motion stalls.
var feet_y: float = capsule_feet_y(global_position.y, CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS)
var descending: bool = (
_has_walk_goal and _auth_walk_goal.y < feet_on_floor - DESCEND_GOAL_Y_MARGIN
_has_walk_goal and _auth_walk_goal.y < feet_y - DESCEND_GOAL_Y_MARGIN
)
if descending and g_step.y < 0.0:
var wallish: bool = is_on_wall()
if not wallish:
for i: int in get_slide_collision_count():
if get_slide_collision(i).get_normal().y < 0.55:
wallish = true
break
if wallish:
velocity.y += g_step.y
velocity.y += g_step.y
func _walk_floor_snap_length(feet_y: float) -> float:
var fl: float = WALK_STEP_ASSIST_SNAP if _step_assist_active else FLOOR_SNAP_MOVING
if (
_has_walk_goal
and _auth_walk_goal.y < feet_y - DESCEND_GOAL_Y_MARGIN
and feet_y > _auth_walk_goal.y + 0.08
):
fl = minf(fl, DESCEND_LIP_SNAP_CAP)
return fl
## When the authoritative goal shares XZ with the capsule (e.g. terrace above), horizontal
@ -626,7 +633,9 @@ func _physics_process(delta: float) -> void:
if NavigationServer3D.map_get_iteration_id(nav_map) == 0:
_set_horizontal_velocity_toward(_auth_walk_goal, want_goal_h)
_apply_walk_air_gravity(delta)
floor_snap_length = WALK_STEP_ASSIST_SNAP if _step_assist_active else FLOOR_SNAP_MOVING
floor_snap_length = _walk_floor_snap_length(
capsule_feet_y(global_position.y, CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS)
)
move_and_slide()
_after_walk_move_and_slide()
if _step_assist_active and (
@ -647,7 +656,7 @@ func _physics_process(delta: float) -> void:
if _auth_walk_goal.y < feet_y - DESCEND_GOAL_Y_MARGIN:
_set_horizontal_velocity_toward(_auth_walk_goal, want_goal_h)
_apply_walk_air_gravity(delta)
floor_snap_length = WALK_STEP_ASSIST_SNAP if _step_assist_active else FLOOR_SNAP_MOVING
floor_snap_length = _walk_floor_snap_length(feet_y)
move_and_slide()
_after_walk_move_and_slide()
if _step_assist_active and (