- Replace raw KEY_F4 check with Input.is_action_just_pressed("free_camera") to
consume the registered project action (matches F3/F12 dev toggle pattern)
- Reset camera.zoom to Vector2.ONE when toggling free camera off so zoom does
not bleed into normal gameplay
- Add free_camera_mode guard to InputMapper._unhandled_input() so discrete
actions (INTERACT, stance, pause) are suppressed alongside movement
- Add client/tests/test_free_camera.gd: flag default, movement suppression,
discrete action suppression, zoom constant contracts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
89 lines
3.2 KiB
GDScript
89 lines
3.2 KiB
GDScript
## Free camera mode tests (#898).
|
||
## Covers GameState flag default, InputMapper suppression, and zoom clamping.
|
||
class_name TestFreeCamera
|
||
extends GdUnitTestSuite
|
||
|
||
|
||
func before_test() -> void:
|
||
GameState.free_camera_mode = false
|
||
|
||
|
||
func after_test() -> void:
|
||
GameState.free_camera_mode = false
|
||
|
||
|
||
# -- GameState.free_camera_mode default ----------------------------------------
|
||
|
||
func test_free_camera_mode_starts_false() -> void:
|
||
## #898: Free camera is off by default — normal gameplay on startup.
|
||
assert_bool(GameState.free_camera_mode).override_failure_message(
|
||
"GameState.free_camera_mode must default to false"
|
||
).is_false()
|
||
|
||
|
||
# -- InputMapper suppression ---------------------------------------------------
|
||
|
||
func test_input_mapper_suppresses_movement_in_free_camera_mode() -> void:
|
||
## #898: While free camera is active, InputMapper._process() returns early so
|
||
## no movement actions enter the queue.
|
||
GameState.free_camera_mode = true
|
||
var before := InputMapper.input_queue.size()
|
||
InputMapper._process(0.016)
|
||
var after := InputMapper.input_queue.size()
|
||
assert_int(after).override_failure_message(
|
||
"InputMapper must not enqueue movement while free_camera_mode is true"
|
||
).is_equal(before)
|
||
InputMapper.input_queue.clear()
|
||
|
||
|
||
func test_input_mapper_suppresses_discrete_actions_in_free_camera_mode() -> void:
|
||
## #898: _unhandled_input returns early in free camera — INTERACT and stance
|
||
## actions must not be queued.
|
||
GameState.free_camera_mode = true
|
||
var before := InputMapper.input_queue.size()
|
||
var fake_event := InputEventAction.new()
|
||
fake_event.action = "interact"
|
||
fake_event.pressed = true
|
||
InputMapper._unhandled_input(fake_event)
|
||
assert_int(InputMapper.input_queue.size()).override_failure_message(
|
||
"InputMapper must not enqueue discrete actions while free_camera_mode is true"
|
||
).is_equal(before)
|
||
InputMapper.input_queue.clear()
|
||
|
||
|
||
func test_input_mapper_resumes_after_free_camera_off() -> void:
|
||
## Turning free camera off lifts the suppression — _process runs normally again.
|
||
GameState.free_camera_mode = true
|
||
GameState.free_camera_mode = false
|
||
## _process should no longer return early (queue may or may not grow depending
|
||
## on held keys, but no crash and guard is lifted).
|
||
InputMapper._process(0.016)
|
||
assert_bool(true).is_true() # no crash = pass
|
||
InputMapper.input_queue.clear()
|
||
|
||
|
||
# -- Zoom clamp contract -------------------------------------------------------
|
||
|
||
func test_zoom_min_constant_is_0_5() -> void:
|
||
## #898: Minimum zoom keeps the world recognisable.
|
||
var main_script = load("res://scripts/main.gd")
|
||
assert_float(main_script.FREE_CAMERA_ZOOM_MIN).override_failure_message(
|
||
"FREE_CAMERA_ZOOM_MIN must be 0.5"
|
||
).is_equal_approx(0.5, 0.001)
|
||
|
||
|
||
func test_zoom_max_constant_is_8() -> void:
|
||
## #898: Maximum zoom must not exceed 8× per spec.
|
||
var main_script = load("res://scripts/main.gd")
|
||
assert_float(main_script.FREE_CAMERA_ZOOM_MAX).override_failure_message(
|
||
"FREE_CAMERA_ZOOM_MAX must be 8.0"
|
||
).is_equal_approx(8.0, 0.001)
|
||
|
||
|
||
func test_zoom_step_is_positive() -> void:
|
||
## Zoom step must be > 0 so scroll wheel does something.
|
||
var main_script = load("res://scripts/main.gd")
|
||
assert_float(main_script.FREE_CAMERA_ZOOM_STEP).override_failure_message(
|
||
"FREE_CAMERA_ZOOM_STEP must be positive"
|
||
).is_greater(0.0)
|