diff --git a/client/scripts/player.gd b/client/scripts/player.gd index 057f2ad..5d347af 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -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