diff --git a/client/scenes/main.tscn b/client/scenes/main.tscn index 7c592e5..7a25b54 100644 --- a/client/scenes/main.tscn +++ b/client/scenes/main.tscn @@ -201,7 +201,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 0.9, -5) collision_layer = 2 collision_mask = 1 floor_max_angle = 0.872665 -floor_snap_length = 0.38 +floor_snap_length = 0.28 safe_margin = 0.045 script = ExtResource("2_player") diff --git a/client/scripts/player.gd b/client/scripts/player.gd index b3cc6c6..1449e61 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -2,15 +2,19 @@ extends CharacterBody3D ## NS-23: Follow server move target on walkable geometry. ## -## Plain Godot pattern: horizontal `velocity` toward `NavigationAgent3D`’s next path point (or the -## goal when finishing / final approach). `velocity.y` stays 0; height comes from `move_and_slide` -## and floor handling. No custom step-down / bump heuristics — obstacle pathing is best-effort; -## small steps rely on the engine + scene (snap, collider shapes). Move **legality** is server-only. +## Horizontal velocity toward nav waypoint or goal only; `velocity.y` stays 0. Height along ramps +## and steps comes from `move_and_slide` + floor_* on CharacterBody3D. Move **legality** (step, +## distance, bounds) is server MoveCommand only — not reimplemented here. +## +## Nav detours except when goal Y is below us: then xz toward goal (waypoints sit under bump rims). const MOVE_SPEED: float = 5.0 const ARRIVE_EPS: float = 0.35 -## Stop when close in xz only; server `y` may be surface or capsule center. +const VERT_ARRIVE_EPS: float = 0.055 const DIRECT_APPROACH_RADIUS: float = 0.85 +## Server goal clearly below us (descending). Nav mesh waypoints are often under the rim first; +## steering at next gives almost no horizontal speed — walk out on xz toward the authorized goal. +const DESCEND_GOAL_Y_MARGIN: float = 0.06 var _has_walk_goal: bool = false var _auth_walk_goal: Vector3 = Vector3.ZERO @@ -58,7 +62,8 @@ func _physics_process(_delta: float) -> void: var full_to_goal: Vector3 = _auth_walk_goal - global_position var horiz_dist: float = Vector2(full_to_goal.x, full_to_goal.z).length() - if horiz_dist <= ARRIVE_EPS: + var vert_err: float = absf(full_to_goal.y) + if horiz_dist <= ARRIVE_EPS and vert_err <= VERT_ARRIVE_EPS: velocity = Vector3.ZERO _has_walk_goal = false _nav_agent.set_target_position(global_position) @@ -71,9 +76,21 @@ func _physics_process(_delta: float) -> void: move_and_slide() return - if _nav_agent.is_navigation_finished() or horiz_dist <= DIRECT_APPROACH_RADIUS: + if _auth_walk_goal.y < global_position.y - DESCEND_GOAL_Y_MARGIN: + _set_horizontal_velocity_toward(_auth_walk_goal) + move_and_slide() + return + + if horiz_dist <= DIRECT_APPROACH_RADIUS: _set_horizontal_velocity_toward(_auth_walk_goal) else: - _set_horizontal_velocity_toward(_nav_agent.get_next_path_position()) + var next_path_position: Vector3 = _nav_agent.get_next_path_position() + var to_next_h: Vector3 = Vector3( + next_path_position.x - global_position.x, 0.0, next_path_position.z - global_position.z + ) + if to_next_h.length_squared() > 0.0025: + _set_horizontal_velocity_toward(next_path_position) + else: + _set_horizontal_velocity_toward(_auth_walk_goal) move_and_slide()