diff --git a/client/scripts/player.gd b/client/scripts/player.gd index bcf4e10..dae6c64 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -14,8 +14,13 @@ const VERT_ARRIVE_EPS: float = 0.055 const DIRECT_APPROACH_RADIUS: float = 0.85 const FLOOR_PROBE_DOWN: float = 4.0 const STEP_OFF_FLOOR_MARGIN: float = 0.04 -const STEP_OFF_MAX_DROP: float = 0.55 -const STEP_OFF_MAX_HORIZ: float = 1.05 +## Only NS-19-sized step downs (not cliffs); allows a wider horiz cap without bee-lining big drops. +const STEP_OFF_MIN_DROP: float = 0.055 +const STEP_OFF_MAX_DROP: float = 0.24 +const STEP_OFF_MAX_HORIZ: float = 3.0 +const FLOOR_PROBE_BODY_Y_OFFSET: float = -0.55 +## If next waypoint is within this xz of us, steer to goal (rim / underfoot waypoints). +const NEXT_WAYPOINT_MIN_HORIZ_SQ: float = 0.01 var _has_walk_goal: bool = false var _auth_walk_goal: Vector3 = Vector3.ZERO @@ -46,20 +51,26 @@ func snap_to_server(world_pos: Vector3) -> void: _nav_agent.set_target_position(world_pos) -func _floor_y_under_body() -> float: +func _ray_floor_y_at(from: Vector3) -> float: var space: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state - var from: Vector3 = global_position var to: Vector3 = from + Vector3(0.0, -FLOOR_PROBE_DOWN, 0.0) var q: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(from, to) q.collision_mask = 1 q.exclude = [get_rid()] var hit: Dictionary = space.intersect_ray(q) if hit.is_empty(): - return global_position.y + return from.y var pv: Variant = hit.get("position") if pv is Vector3: return (pv as Vector3).y - return global_position.y + return from.y + + +func _floor_y_under_body() -> float: + var y_center: float = _ray_floor_y_at(global_position) + var lower: Vector3 = global_position + Vector3(0.0, FLOOR_PROBE_BODY_Y_OFFSET, 0.0) + var y_lower: float = _ray_floor_y_at(lower) + return maxf(y_center, y_lower) func _nav_short_step_down_use_goal_direct() -> bool: @@ -67,7 +78,7 @@ func _nav_short_step_down_use_goal_direct() -> bool: if _auth_walk_goal.y >= floor_y - STEP_OFF_FLOOR_MARGIN: return false var drop: float = floor_y - _auth_walk_goal.y - if drop > STEP_OFF_MAX_DROP: + if drop < STEP_OFF_MIN_DROP or drop > STEP_OFF_MAX_DROP: return false var hd: float = Vector2( _auth_walk_goal.x - global_position.x, _auth_walk_goal.z - global_position.z @@ -120,8 +131,7 @@ func _physics_process(_delta: float) -> void: var to_next_h: Vector3 = Vector3( next_path_position.x - global_position.x, 0.0, next_path_position.z - global_position.z ) - # “goal Y < body Y” skips nav wrongly: pick is floor height, body origin is higher. - if to_next_h.length_squared() > 0.0025: + if to_next_h.length_squared() > NEXT_WAYPOINT_MIN_HORIZ_SQ: _set_horizontal_velocity_toward(next_path_position) else: _set_horizontal_velocity_toward(_auth_walk_goal)