diff --git a/client/scripts/player.gd b/client/scripts/player.gd index f7f9ad2..edecf6e 100644 --- a/client/scripts/player.gd +++ b/client/scripts/player.gd @@ -374,34 +374,27 @@ func _maybe_idle_bump_proximity_escape() -> bool: var radial: Vector3 = Vector3(dx / d, 0.0, dz / d) var away: Vector3 = radial * IDLE_BUMP_ESCAPE_STEP var wall_band_outer: float = col_r + PLAYER_CAPSULE_RADIUS + 0.22 - # Outside visual disc but inside fat collision — clear the invisible lip. - if d > r_mesh * 0.9 and d < col_r + 0.32: - if not test_move(global_transform, away, null, safe_margin): - global_position += away - return true - return false + var should_escape: bool = d > r_mesh * 0.9 and d < col_r + 0.32 # On / above the disc, hugging the **visual** rim — step onto open slab. - if ( + should_escape = should_escape or ( feet_y >= bottom_y - 0.06 and feet_y <= top_y + 0.1 and d >= r_mesh * 0.86 and d <= r_mesh + 0.14 - ): - if not test_move(global_transform, away, null, safe_margin): - global_position += away - return true - return false + ) # Beside vertical cylinder: axis distance may exceed **`col_r`** while capsule still touches wall. - if ( + should_escape = should_escape or ( feet_y <= top_y + 0.14 and d > r_mesh * 0.82 and d < wall_band_outer and (is_on_wall() or _idle_ridged_floor_contacts()) - ): - if not test_move(global_transform, away, null, safe_margin): - global_position += away - return true + ) + if not should_escape: + continue + if test_move(global_transform, away, null, safe_margin): return false + global_position += away + return true return false @@ -497,7 +490,8 @@ func _physics_process(_delta: float) -> void: _snap_capsule_upright() return - if _auth_walk_goal.y < capsule_feet_y(global_position.y, CAPSULE_HALF_HEIGHT) - DESCEND_GOAL_Y_MARGIN: + var feet_y: float = capsule_feet_y(global_position.y, CAPSULE_HALF_HEIGHT) + if _auth_walk_goal.y < feet_y - DESCEND_GOAL_Y_MARGIN: _set_horizontal_velocity_toward(_auth_walk_goal) floor_snap_length = FLOOR_SNAP_MOVING move_and_slide() diff --git a/client/test/player_test.gd b/client/test/player_test.gd index bd294dd..80a7793 100644 --- a/client/test/player_test.gd +++ b/client/test/player_test.gd @@ -1,13 +1,15 @@ # Tests for res://scripts/player.gd (minimal tree: CharacterBody3D + NavigationAgent3D). extends GdUnitTestSuite +const PLAYER_SCRIPT: Script = preload("res://scripts/player.gd") + func _make_player() -> CharacterBody3D: var body := CharacterBody3D.new() var nav := NavigationAgent3D.new() nav.name = "NavigationAgent3D" body.add_child(nav) - body.set_script(load("res://scripts/player.gd")) + body.set_script(PLAYER_SCRIPT) auto_free(body) add_child(body) return body @@ -48,7 +50,7 @@ func test_clear_nav_goal_clears_velocity_and_nav_target() -> void: func test_idle_support_is_stable_on_flat_floor_without_wall_contacts() -> void: var slide_normals: Array[Vector3] = [Vector3.UP] - var stable: bool = load("res://scripts/player.gd").idle_support_is_stable( + var stable: bool = PLAYER_SCRIPT.idle_support_is_stable( true, Vector3.UP, slide_normals, @@ -59,7 +61,7 @@ func test_idle_support_is_stable_on_flat_floor_without_wall_contacts() -> void: func test_idle_support_is_stable_false_when_floor_is_not_flat_enough() -> void: var slide_normals: Array[Vector3] = [Vector3.UP] - var stable: bool = load("res://scripts/player.gd").idle_support_is_stable( + var stable: bool = PLAYER_SCRIPT.idle_support_is_stable( true, Vector3(0.02, 0.995, 0.0).normalized(), slide_normals, @@ -70,7 +72,7 @@ func test_idle_support_is_stable_false_when_floor_is_not_flat_enough() -> void: func test_idle_support_is_stable_true_when_flat_floor_has_extra_contacts() -> void: var slide_normals: Array[Vector3] = [Vector3.UP, Vector3(0.0, 0.6, 0.8).normalized()] - var stable: bool = load("res://scripts/player.gd").idle_support_is_stable( + var stable: bool = PLAYER_SCRIPT.idle_support_is_stable( true, Vector3.UP, slide_normals, @@ -81,7 +83,7 @@ func test_idle_support_is_stable_true_when_flat_floor_has_extra_contacts() -> vo func test_idle_support_is_stable_false_when_loose_ticks_active() -> void: var slide_normals: Array[Vector3] = [Vector3.UP] - var stable: bool = load("res://scripts/player.gd").idle_support_is_stable( + var stable: bool = PLAYER_SCRIPT.idle_support_is_stable( true, Vector3.UP, slide_normals, @@ -92,7 +94,7 @@ func test_idle_support_is_stable_false_when_loose_ticks_active() -> void: func test_idle_support_is_stable_false_when_not_on_floor() -> void: var slide_normals: Array[Vector3] = [Vector3.UP] - var stable: bool = load("res://scripts/player.gd").idle_support_is_stable( + var stable: bool = PLAYER_SCRIPT.idle_support_is_stable( false, Vector3.UP, slide_normals, @@ -122,33 +124,29 @@ func test_snap_to_server_clears_idle_anchor() -> void: func test_capsule_feet_y_uses_body_origin_minus_half_height() -> void: - var script := load("res://scripts/player.gd") - var feet_y: float = script.capsule_feet_y(0.545678, 0.5) + var feet_y: float = PLAYER_SCRIPT.capsule_feet_y(0.545678, 0.5) assert_that(absf(feet_y - 0.045678)).is_less(0.000001) func test_vertical_arrival_error_uses_capsule_feet_height() -> void: - var script := load("res://scripts/player.gd") var goal_y := 0.045678 var body_origin_y := 0.545678 - var err: float = script.vertical_arrival_error(goal_y, body_origin_y, 0.5) + var err: float = PLAYER_SCRIPT.vertical_arrival_error(goal_y, body_origin_y, 0.5) assert_that(absf(err)).is_less(0.000001) func test_vertical_arrival_error_stays_large_for_origin_height_only_match() -> void: - var script := load("res://scripts/player.gd") var goal_y := 0.545678 var body_origin_y := 0.545678 - var err: float = script.vertical_arrival_error(goal_y, body_origin_y, 0.5) + var err: float = PLAYER_SCRIPT.vertical_arrival_error(goal_y, body_origin_y, 0.5) assert_that(absf(err - 0.5)).is_less(0.000001) func test_flat_floor_goal_is_not_below_feet_height_margin() -> void: - var script := load("res://scripts/player.gd") var goal_y := 0.0 var body_origin_y := 0.4 - var descend_margin := script.get("DESCEND_GOAL_Y_MARGIN") as float + var descend_margin := PLAYER_SCRIPT.get("DESCEND_GOAL_Y_MARGIN") as float var below_feet_margin: bool = ( - goal_y < script.capsule_feet_y(body_origin_y, 0.5) - descend_margin + goal_y < PLAYER_SCRIPT.capsule_feet_y(body_origin_y, 0.5) - descend_margin ) assert_that(below_feet_margin).is_false()