extends SceneTree # Headless gameplay test: run with # godot --headless -s res://tests/test_camera_settles.gd # Regression test for a permanently-drifting camera. GameController followed # the fleet with an exponential lerp and no snap threshold, so it approached # the fleet centroid asymptotically and NEVER arrived - the camera kept # moving by a fraction of a pixel every single frame, forever, even with the # fleet completely stationary. That kept the background shaders' camera_pos # uniform changing every frame, which made screen tearing permanently visible # as horizontal bands of the background sliding sideways against each other. # # Verifies the camera reaches an EXACTLY stable position (bit-identical # frame to frame) once the fleet has stopped, not merely a nearly-stable one. var main_scene: Node var fleet: Node var camera: Camera2D var elapsed: float = 0.0 var stage: int = 0 var last_pos: Vector2 var identical_frames: int = 0 func _initialize() -> void: var packed: PackedScene = load("res://world/Main.tscn") main_scene = packed.instantiate() root.add_child(main_scene) fleet = main_scene.get_node("Fleet") camera = main_scene.get_node("Camera2D") func _process(delta: float) -> bool: elapsed += delta match stage: 0: main_scene.get_node("AsteroidField").set_process(false) main_scene.get_node("EnemySpawner").set_process(false) # Send the fleet somewhere well away from the camera so the # follow actually has distance to close. fleet.move_to(Vector2(1500, 900)) elapsed = 0.0 stage = 1 return false 1: # Wait for the fleet to genuinely arrive AND the camera to close # the remaining distance - a fixed delay is unreliable here, since # the trip length depends on the ships' braking curve. if elapsed > 30.0: print("TEST_CAMERA_SETTLES: FAIL (fleet/camera never arrived)") quit(1) return true for ship in fleet.ships: if ship.position.distance_to(ship.move_target) > ship.arrive_radius: return false # Wait for the snap itself to fire, not merely for the camera to # get close: the final approach is still an active lerp, and # sampling during it would just measure normal convergence rather # than the perpetual drift this test is about. if camera.global_position.distance_to(fleet.get_centroid()) > 0.0001: return false last_pos = camera.global_position identical_frames = 0 elapsed = 0.0 stage = 2 return false 2: # With the fleet settled, the camera must be BIT-IDENTICAL frame # to frame. Any residual drift (however small) means the lerp is # still creeping and the tearing-visibility bug is back. if camera.global_position == last_pos: identical_frames += 1 else: print("camera still drifting: %s -> %s (delta=%.9f)" % [ last_pos, camera.global_position, last_pos.distance_to(camera.global_position) ]) print("TEST_CAMERA_SETTLES: FAIL (camera never stops moving)") quit(1) return true last_pos = camera.global_position if identical_frames < 30: return false var centroid: Vector2 = fleet.get_centroid() var on_target: bool = camera.global_position.distance_to(centroid) <= 1.0 print("camera stable for %d frames at %s (fleet centroid %s)" % [ identical_frames, camera.global_position, centroid ]) if on_target: print("TEST_CAMERA_SETTLES: PASS") quit(0) else: print("TEST_CAMERA_SETTLES: FAIL (settled, but not on the fleet)") quit(1) return true return false