spaceship/tests/test_camera_settles.gd

98 lines
3.4 KiB
GDScript3
Raw Normal View History

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://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