Fix 354 gdlint warnings across 65 files: 194 class-definitions-order (reorder declarations), 138 max-line-length (split long lines), 22 code issues (unused args, no-else-return, naming). Update .gdlintrc to exclude addons/ and raise max-public-methods for test files. No logic changes — declaration order, whitespace, and naming only. Ticket: #783 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
150 lines
4.7 KiB
GDScript
150 lines
4.7 KiB
GDScript
## Tests for camera anchor behavior — the camera must show the player's
|
|
## position from the very first rendered frame, with no visible drift from (0,0).
|
|
##
|
|
## These tests verify the full pipeline: SimBridge → GameState → Camera2D.
|
|
## The player starts at (10,10) in test mode, so the expected camera position
|
|
## is (10,10) * TILE_SIZE = (320, 320).
|
|
class_name TestCameraAnchor
|
|
extends GdUnitTestSuite
|
|
|
|
const EXPECTED_PLAYER_POS := Vector2(10, 10)
|
|
const EXPECTED_CAMERA_POS := Vector2(320, 320) # 10 * 32, 10 * 32
|
|
const MAIN_SCENE = preload("res://scenes/main.tscn")
|
|
|
|
var _instance: Node = null
|
|
|
|
|
|
func before_test() -> void:
|
|
SimBridge.reset_test_state()
|
|
GameState.current_tick = 0
|
|
GameState.player_position = Vector2.ZERO
|
|
GameState.visible_entities = []
|
|
GameState.visible_tiles = []
|
|
GameState.visible_positions = {}
|
|
GameState.current_monologue = null
|
|
GameState.current_dialogue = null
|
|
|
|
|
|
func after_test() -> void:
|
|
if _instance and is_instance_valid(_instance):
|
|
_instance.queue_free()
|
|
_instance = null
|
|
|
|
|
|
# --- Pipeline precondition tests ---
|
|
|
|
func test_simbridge_connected_in_test_mode() -> void:
|
|
SimBridge.state = SimBridge.ConnectionState.DISCONNECTED
|
|
SimBridge.connect_to_sim()
|
|
assert_that(SimBridge.state).is_equal(SimBridge.ConnectionState.CONNECTED)
|
|
|
|
|
|
func test_poll_snapshot_returns_data_when_connected() -> void:
|
|
SimBridge.connect_to_sim()
|
|
var snapshot: Variant = SimBridge.poll_snapshot()
|
|
assert_that(snapshot).is_not_null()
|
|
assert_that(snapshot is Dictionary).is_true()
|
|
|
|
|
|
func test_snapshot_has_player_at_10_10() -> void:
|
|
var snap := SimBridge._test_snapshot()
|
|
var player_x: float = -1.0
|
|
var player_y: float = -1.0
|
|
for entity in snap.entities:
|
|
if entity.kind.variant == "Player":
|
|
player_x = entity.x
|
|
player_y = entity.y
|
|
break
|
|
assert_that(player_x).is_equal(10.0)
|
|
assert_that(player_y).is_equal(10.0)
|
|
|
|
|
|
func test_apply_snapshot_sets_player_position() -> void:
|
|
var snap := SimBridge._test_snapshot()
|
|
GameState.apply_snapshot(snap)
|
|
assert_that(GameState.player_position).is_equal(EXPECTED_PLAYER_POS)
|
|
|
|
|
|
# --- Camera anchor after _ready() ---
|
|
|
|
func test_camera_position_after_ready() -> void:
|
|
var scene := MAIN_SCENE
|
|
_instance = scene.instantiate()
|
|
auto_free(_instance)
|
|
add_child(_instance)
|
|
|
|
var camera: Camera2D = _instance.get_node("Camera2D")
|
|
assert_that(camera.global_position).is_equal(EXPECTED_CAMERA_POS)
|
|
|
|
|
|
func test_camera_anchored_flag_after_ready() -> void:
|
|
var scene := MAIN_SCENE
|
|
_instance = scene.instantiate()
|
|
auto_free(_instance)
|
|
add_child(_instance)
|
|
|
|
assert_that(_instance._camera_anchored).is_true()
|
|
|
|
|
|
func test_camera_smoothing_off_after_ready() -> void:
|
|
# Camera smoothing must be disabled during init to prevent lerp from (0,0).
|
|
# If this test fails, the camera will visibly drift from origin to player.
|
|
var scene := MAIN_SCENE
|
|
_instance = scene.instantiate()
|
|
auto_free(_instance)
|
|
add_child(_instance)
|
|
|
|
var camera: Camera2D = _instance.get_node("Camera2D")
|
|
assert_that(camera.position_smoothing_enabled).is_false()
|
|
|
|
|
|
func test_camera_smoothing_stays_off_with_manual_lerp() -> void:
|
|
# #117: Manual lerp approach — Godot's built-in smoothing must stay OFF always.
|
|
# CAMERA_SMOOTHING_SPEED is used as the lerp weight, not Godot's position_smoothing_speed.
|
|
var scene := MAIN_SCENE
|
|
_instance = scene.instantiate()
|
|
auto_free(_instance)
|
|
add_child(_instance)
|
|
|
|
_instance._process(0.016)
|
|
|
|
var camera: Camera2D = _instance.get_node("Camera2D")
|
|
assert_that(camera.position_smoothing_enabled).is_false()
|
|
|
|
|
|
# --- Camera behavior across frames ---
|
|
|
|
func test_camera_tracks_player_after_process() -> void:
|
|
var scene := MAIN_SCENE
|
|
_instance = scene.instantiate()
|
|
auto_free(_instance)
|
|
add_child(_instance)
|
|
|
|
# Simulate one game frame
|
|
_instance._process(0.016)
|
|
|
|
var camera: Camera2D = _instance.get_node("Camera2D")
|
|
var expected := GameState.player_position * Constants.TILE_SIZE
|
|
assert_that(camera.global_position).is_equal(expected)
|
|
|
|
|
|
func test_camera_lerps_toward_player_movement() -> void:
|
|
# #117: With manual lerp, camera moves TOWARD player position (not snapping).
|
|
# After one 16ms frame the camera should be partway between old and new position.
|
|
var scene := MAIN_SCENE
|
|
_instance = scene.instantiate()
|
|
auto_free(_instance)
|
|
add_child(_instance)
|
|
|
|
var camera: Camera2D = _instance.get_node("Camera2D")
|
|
var initial_pos := camera.global_position # anchored at (320, 320)
|
|
|
|
# Move player north via SimBridge test mode
|
|
SimBridge._test_input_queue.append("MoveNorth")
|
|
_instance._process(0.016)
|
|
|
|
var new_target := GameState.player_position * Constants.TILE_SIZE # (320, 288)
|
|
# Camera should have moved north (lower y) but NOT reached the target yet
|
|
assert_that(camera.global_position.y).is_less(initial_pos.y)
|
|
assert_that(camera.global_position.y).is_greater(new_target.y)
|