From ff6c337e1d74bfb157487df2409a73b123861937 Mon Sep 17 00:00:00 2001 From: VinPropane Date: Sun, 12 Apr 2026 17:02:17 -0400 Subject: [PATCH] NEON-29: Hysteresis for nav column steering (walk ping-pong) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single-radius switch at DIRECT_APPROACH_RADIUS let horiz_dist cross every frame between direct-to-goal and nav-path steering, flipping velocity ~180°. Schmitt band NAV_COLUMN_STEER_ENTER/EXIT with latched _walk_nav_column_steering; reset on new goal, snap, arrival, clear. --- client/scripts/player.gd | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/client/scripts/player.gd b/client/scripts/player.gd index a18a2a2..baac815 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -16,6 +16,12 @@ const FLOOR_ANGLE_LOOSE_TICKS_AFTER_STOP: int = 96 const ARRIVE_EPS: float = 0.35 const VERT_ARRIVE_EPS: float = 0.055 const DIRECT_APPROACH_RADIUS: float = 0.85 +## Hysteresis for nav-path column steering (see `_physics_process`). At exactly +## [member DIRECT_APPROACH_RADIUS] the old test flipped every frame: path nudges +## tangentially → [code]horiz_dist[/code] crosses the radius → direct vs path +## alternates → velocity sign flips (Jolt ping-pong while [code]has_goal[/code]). +const NAV_COLUMN_STEER_ENTER_DIST: float = 0.74 +const NAV_COLUMN_STEER_EXIT_DIST: float = 0.97 const FLOOR_SNAP_MOVING: float = 0.32 ## Idle floor snap length (stronger to pin rim contacts). const FLOOR_SNAP_IDLE: float = 0.11 @@ -76,6 +82,8 @@ var _debug_last_idle_xz: Vector2 = Vector2.INF var _debug_idle_heartbeat: int = 0 var _debug_last_transform_xz: Vector2 = Vector2.INF var _debug_trace_frame: int = 0 +## True while we use [method _set_horizontal_velocity_from_nav_path_or_goal] for vertical routing. +var _walk_nav_column_steering: bool = false @onready var _nav_agent: NavigationAgent3D = $NavigationAgent3D @@ -95,6 +103,7 @@ func set_authoritative_nav_goal(world_pos: Vector3) -> void: _step_assist_active = false _idle_anchor_active = false _idle_manual_correction_ticks = 0 + _walk_nav_column_steering = false _nav_agent.set_target_position(world_pos) @@ -105,6 +114,7 @@ func clear_nav_goal() -> void: _step_assist_active = false _idle_anchor_active = false _idle_manual_correction_ticks = 0 + _walk_nav_column_steering = false _nav_agent.set_target_position(global_position) @@ -141,6 +151,7 @@ func snap_to_server(world_pos: Vector3) -> void: _step_assist_active = false _idle_anchor_active = false _idle_manual_correction_ticks = 0 + _walk_nav_column_steering = false _nav_agent.set_target_position(settled) reset_physics_interpolation() @@ -674,6 +685,7 @@ func _physics_process(delta: float) -> void: _step_assist_active = false _idle_anchor_active = false _idle_manual_correction_ticks = 0 + _walk_nav_column_steering = false _nav_agent.set_target_position(global_position) _physics_idle_tick(delta) if _stable_idle_support(): @@ -708,7 +720,13 @@ func _physics_process(delta: float) -> void: _auth_walk_goal.y > feet_y + DESCEND_GOAL_Y_MARGIN or _auth_walk_goal.y < feet_y - DESCEND_GOAL_Y_MARGIN ) - if needs_vertical_routing and horiz_dist <= DIRECT_APPROACH_RADIUS: + if not needs_vertical_routing: + _walk_nav_column_steering = false + elif horiz_dist <= NAV_COLUMN_STEER_ENTER_DIST: + _walk_nav_column_steering = true + elif horiz_dist >= NAV_COLUMN_STEER_EXIT_DIST: + _walk_nav_column_steering = false + if needs_vertical_routing and _walk_nav_column_steering: _set_horizontal_velocity_from_nav_path_or_goal(want_goal_h) else: _set_horizontal_velocity_toward(_auth_walk_goal, want_goal_h)