NEON-29: Reject 180° walk steering flips on stair edges.

Path lookahead vs direct goal could reverse horizontal velocity every physics
tick on treads (NEON-16), driving slide/snap Y jitter. Clamp new steer to
prior bearing when dot < -0.35 and speed is above a small threshold.

Widen NAV_COLUMN_STEER_EXIT_DIST (0.97→1.12) to reduce path/direct mode
chatter when horiz_dist wobbles near the old band.
pull/41/head
VinPropane 2026-04-12 19:07:15 -04:00
parent 038505ea3e
commit bfc70678c4
1 changed files with 22 additions and 1 deletions

View File

@ -21,13 +21,18 @@ const DIRECT_APPROACH_RADIUS: float = 0.85
## 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 NAV_COLUMN_STEER_EXIT_DIST: float = 1.12
## First path waypoint used for column steer must be at least this far in XZ. [method NavigationAgent3D.get_next_path_position]
## can sit ~4 cm from the capsule; Jolt slides ~4 cm/tick → the “toward next” vector flips 180° every frame
## (`vlat && ncol` NEON-16 traces). A 22 cm gate matches foot-scale probes and stays stable on treads.
const NAV_PATH_STEER_MIN_LOOKAHEAD: float = 0.22
## If lookahead steering points more than ~105° from the click direction (XZ), use direct goal steer instead.
const NAV_PATH_STEER_MIN_GOAL_DOT: float = -0.25
## On tread edges, path vs direct or waypoint lookahead can flip the horizontal seek vector ~180° each
## physics tick → [method move_and_slide] + snap Y noise (~7 cm, NEON-16). Keep prior bearing if the new
## direction is more than ~110° from current horizontal [member velocity].
const WALK_STEER_REVERSE_REJECT_DOT: float = -0.35
const WALK_STEER_MIN_CUR_SPEED_SQ: float = 0.16
## While [code]vlat && ncol[/code], ledge peel + zero floor snap fight [method move_and_slide] on approach treads
## (3-cycle NEON-16 traces: same XZ triplet, Y/feet_y ping-pong). Suspend peel and allow normal snap when the
## feet are within this vertical distance of the goal **surface** (m).
@ -358,6 +363,20 @@ func _clear_step_assist_after_walk_move() -> void:
_step_assist_active = false
func _walk_clamp_steering_reverse(desired_dir_xz: Vector3) -> Vector3:
var d2 := Vector2(desired_dir_xz.x, desired_dir_xz.z)
if d2.length_squared() < 1e-10:
return desired_dir_xz
d2 = d2.normalized()
var cur := Vector2(velocity.x, velocity.z)
if cur.length_squared() < WALK_STEER_MIN_CUR_SPEED_SQ:
return Vector3(d2.x, 0.0, d2.y)
var cur_n := cur.normalized()
if d2.dot(cur_n) < WALK_STEER_REVERSE_REJECT_DOT:
return Vector3(cur_n.x, 0.0, cur_n.y)
return Vector3(d2.x, 0.0, d2.y)
func _set_horizontal_velocity_toward(
point: Vector3, fallback_dir_xz: Vector3 = Vector3.ZERO
) -> void:
@ -372,6 +391,7 @@ func _set_horizontal_velocity_toward(
dh = Vector3(1.0, 0.0, 0.0)
else:
dh = dh.normalized()
dh = _walk_clamp_steering_reverse(dh)
velocity = dh * MOVE_SPEED
velocity.y = 0.0
@ -643,6 +663,7 @@ func _set_horizontal_velocity_from_nav_path_or_goal(fallback_goal_xz: Vector3) -
if dir.dot(gh) < NAV_PATH_STEER_MIN_GOAL_DOT:
_set_horizontal_velocity_toward(_auth_walk_goal, fallback_goal_xz)
return
dir = _walk_clamp_steering_reverse(dir)
velocity = dir * MOVE_SPEED
velocity.y = 0.0