NEON-29: Idle gravity + snap when airborne (ledge / step drop)

_physics_idle_tick zeroed velocity with no gravity, so after walking off a
terrace or arriving slightly above the floor FLOOR_SNAP_IDLE could not reach
the ground and the body hovered until a new walk goal. Apply get_gravity()*delta
and FLOOR_SNAP_MOVING while !is_on_floor(). Budgeted idle branch now runs the
same physics when airborne instead of returning without move_and_slide.
pull/41/head
VinPropane 2026-04-11 23:51:25 -04:00
parent 6b471b2102
commit 2a25a24e0b
1 changed files with 26 additions and 8 deletions

View File

@ -279,9 +279,17 @@ static func vertical_arrival_error(
return absf(goal_y - capsule_feet_y(body_origin_y, capsule_half_height)) return absf(goal_y - capsule_feet_y(body_origin_y, capsule_half_height))
func _physics_idle_tick() -> void: func _physics_idle_tick(delta: float) -> void:
velocity = Vector3.ZERO if is_on_floor():
floor_snap_length = FLOOR_SNAP_IDLE velocity = Vector3.ZERO
floor_snap_length = FLOOR_SNAP_IDLE
else:
# Ledge / post-arrival hover: without gravity, vy stays 0 and FLOOR_SNAP_IDLE (0.11 m)
# cannot reach the lower floor — the capsule idles in mid-air until a new walk goal runs.
velocity.x = 0.0
velocity.z = 0.0
velocity += get_gravity() * delta
floor_snap_length = FLOOR_SNAP_MOVING
move_and_slide() move_and_slide()
@ -535,17 +543,27 @@ func _physics_process(delta: float) -> void:
_snap_capsule_upright() _snap_capsule_upright()
return return
if _idle_manual_correction_ticks >= IDLE_MANUAL_CORRECTION_MAX_TICKS: if _idle_manual_correction_ticks >= IDLE_MANUAL_CORRECTION_MAX_TICKS:
velocity = Vector3.ZERO if is_on_floor():
floor_snap_length = FLOOR_SNAP_IDLE velocity = Vector3.ZERO
floor_snap_length = FLOOR_SNAP_IDLE
if _floor_angle_loose_ticks > 0:
_floor_angle_loose_ticks -= 1
_hold_idle_anchor()
_debug_trace_idle_state("budgeted")
_debug_trace_transform("physics")
_snap_capsule_upright()
return
# Airborne: do not freeze XZ without a physics step — same mid-air hang as idle tick.
_idle_anchor_active = false
_physics_idle_tick(delta)
if _floor_angle_loose_ticks > 0: if _floor_angle_loose_ticks > 0:
_floor_angle_loose_ticks -= 1 _floor_angle_loose_ticks -= 1
_hold_idle_anchor()
_debug_trace_idle_state("budgeted") _debug_trace_idle_state("budgeted")
_debug_trace_transform("physics") _debug_trace_transform("physics")
_snap_capsule_upright() _snap_capsule_upright()
return return
_idle_anchor_active = false _idle_anchor_active = false
_physics_idle_tick() _physics_idle_tick(delta)
if _apply_idle_manual_correction(): if _apply_idle_manual_correction():
_idle_manual_correction_ticks += 1 _idle_manual_correction_ticks += 1
else: else:
@ -576,7 +594,7 @@ func _physics_process(delta: float) -> void:
_idle_anchor_active = false _idle_anchor_active = false
_idle_manual_correction_ticks = 0 _idle_manual_correction_ticks = 0
_nav_agent.set_target_position(global_position) _nav_agent.set_target_position(global_position)
_physics_idle_tick() _physics_idle_tick(delta)
if _apply_idle_manual_correction(): if _apply_idle_manual_correction():
_idle_manual_correction_ticks += 1 _idle_manual_correction_ticks += 1
_debug_trace_transform("physics") _debug_trace_transform("physics")