From 2a25a24e0bc74908ffe72e064485ae15a94a73c2 Mon Sep 17 00:00:00 2001 From: VinPropane Date: Sat, 11 Apr 2026 23:51:25 -0400 Subject: [PATCH] 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. --- client/scripts/player.gd | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/client/scripts/player.gd b/client/scripts/player.gd index 8cdb13a..e69497a 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -279,9 +279,17 @@ static func vertical_arrival_error( return absf(goal_y - capsule_feet_y(body_origin_y, capsule_half_height)) -func _physics_idle_tick() -> void: - velocity = Vector3.ZERO - floor_snap_length = FLOOR_SNAP_IDLE +func _physics_idle_tick(delta: float) -> void: + if is_on_floor(): + 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() @@ -535,17 +543,27 @@ func _physics_process(delta: float) -> void: _snap_capsule_upright() return if _idle_manual_correction_ticks >= IDLE_MANUAL_CORRECTION_MAX_TICKS: - velocity = Vector3.ZERO - floor_snap_length = FLOOR_SNAP_IDLE + if is_on_floor(): + 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: _floor_angle_loose_ticks -= 1 - _hold_idle_anchor() _debug_trace_idle_state("budgeted") _debug_trace_transform("physics") _snap_capsule_upright() return _idle_anchor_active = false - _physics_idle_tick() + _physics_idle_tick(delta) if _apply_idle_manual_correction(): _idle_manual_correction_ticks += 1 else: @@ -576,7 +594,7 @@ func _physics_process(delta: float) -> void: _idle_anchor_active = false _idle_manual_correction_ticks = 0 _nav_agent.set_target_position(global_position) - _physics_idle_tick() + _physics_idle_tick(delta) if _apply_idle_manual_correction(): _idle_manual_correction_ticks += 1 _debug_trace_transform("physics")