Let the speed fader have the click it is under
Clicking the fader did nothing on a desktop: it fired the guns instead. Unhandled input reaches the last nodes in the tree first, and the fader's mouse handling lived in GameController - the script on Main, the ROOT, so it was served last of all. MouseCombatController is a child of it and marks every left press handled to fire, so the press never arrived. The fader asks for its own mouse events now, from the UI layer, which sits after the combat controllers: the control the pointer is actually on gets the press ahead of the guns behind it. The handlers themselves are the same wrappers #118 wrote. The test for #118 could not see any of this - it handed the event straight to Main._unhandled_input, which is precisely the delivery the real game never makes, so it passed against the bug it was written for. It pushes through the viewport now, with mouse aiming on, and checks the guns stay quiet. Confirmed it fails without the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QR2Mdk42ghEpeyXPe4UFyn
This commit is contained in:
parent
93bfe62e76
commit
a43fae5e28
3 changed files with 78 additions and 18 deletions
|
|
@ -10,16 +10,19 @@ extends SceneTree
|
|||
# The boost was unreachable on a desktop and the formation could not be
|
||||
# rearranged at all.
|
||||
#
|
||||
# Driven through the REAL routing in each case (GameController for the
|
||||
# fader, BuildController for the editor) rather than by calling the controls
|
||||
# directly, because the routing is what was missing - a test that called
|
||||
# handle_mouse_button() itself would have passed against both reports.
|
||||
# Driven through the REAL routing in each case - the viewport itself for the
|
||||
# fader, BuildController for the editor - rather than by calling the
|
||||
# controls directly, because the routing is what was missing: a test that
|
||||
# called handle_mouse_button() itself would have passed against both
|
||||
# reports. It did, in fact, and hid a second one: the fader was dispatched
|
||||
# from Main, which is the LAST node to see an unhandled press, so
|
||||
# MouseCombatController fired the guns with it and the knob never moved.
|
||||
#
|
||||
# Covers:
|
||||
# A. #118 - a click on the fader takes hold of it, dragging moves the
|
||||
# boost, and releasing lets go
|
||||
# B. the fader claims the press, so dragging the boost does not also zoom
|
||||
# the world behind it
|
||||
# B. the press stops at the fader: not the camera behind it, and not the
|
||||
# guns, which claim every other left press on a desktop
|
||||
# C. #121 - a click grabs a formation slot, moving drags it, and the
|
||||
# formation really changes
|
||||
# D. releasing drops the slot, and moving afterwards does not keep dragging
|
||||
|
|
@ -67,6 +70,31 @@ func _fail(message: String) -> bool:
|
|||
return true
|
||||
|
||||
|
||||
# Pushed through the viewport, not handed to a node's own _unhandled_input:
|
||||
# WHICH node sees a press first is the thing under test. #118 shipped a fader
|
||||
# that only worked when a test called it directly - MouseCombatController
|
||||
# claims every left press to fire the guns, and it is dispatched well before
|
||||
# Main's own handler, so on a real desktop the click never arrived.
|
||||
# `true` keeps the coordinates in viewport space, which is the space the
|
||||
# controls are laid out in.
|
||||
func _push(event: InputEvent) -> void:
|
||||
root.push_input(event, true)
|
||||
|
||||
|
||||
func _push_click(at: Vector2, pressed: bool) -> void:
|
||||
var event: InputEventMouseButton = InputEventMouseButton.new()
|
||||
event.button_index = MOUSE_BUTTON_LEFT
|
||||
event.pressed = pressed
|
||||
event.position = at
|
||||
_push(event)
|
||||
|
||||
|
||||
func _push_move(to: Vector2) -> void:
|
||||
var event: InputEventMouseMotion = InputEventMouseMotion.new()
|
||||
event.position = to
|
||||
_push(event)
|
||||
|
||||
|
||||
func _click(at: Vector2, pressed: bool, target: Node) -> void:
|
||||
var event: InputEventMouseButton = InputEventMouseButton.new()
|
||||
event.button_index = MOUSE_BUTTON_LEFT
|
||||
|
|
@ -112,22 +140,29 @@ func _process(delta: float) -> bool:
|
|||
return _fail("the boost has no range to move through")
|
||||
|
||||
# --- A. click, drag, release -----------------------------
|
||||
# With mouse aiming live, which is what a desktop always has:
|
||||
# the guns are the other thing a left press means, and they used
|
||||
# to take every one of them.
|
||||
var mouse_combat: Node = scene.get_node("MouseCombatController")
|
||||
mouse_combat.pointer_mode = mouse_combat.PointerMode.ON
|
||||
var top: Vector2 = fader.global_position + Vector2(fader.size.x * 0.5,
|
||||
fader.track_margin + 2.0)
|
||||
var bottom: Vector2 = fader.global_position + Vector2(fader.size.x * 0.5,
|
||||
fader.size.y - fader.track_margin - 2.0)
|
||||
_click(bottom, true, scene)
|
||||
_push_click(bottom, true)
|
||||
if not fader.is_active():
|
||||
return _fail("a click on the fader did not take hold of it")
|
||||
if mouse_combat.firing:
|
||||
return _fail("the click that grabbed the fader also fired the fleet's guns")
|
||||
var at_bottom: float = game_state.fleet_speed_multiplier
|
||||
_move(top, scene)
|
||||
_push_move(top)
|
||||
var at_top: float = game_state.fleet_speed_multiplier
|
||||
if at_top <= at_bottom:
|
||||
return _fail("dragging the fader from bottom to top left the boost at %.2f" % at_top)
|
||||
_click(top, false, scene)
|
||||
_push_click(top, false)
|
||||
if fader.is_active():
|
||||
return _fail("the fader is still held after the button came up")
|
||||
_move(bottom, scene)
|
||||
_push_move(bottom)
|
||||
if not is_equal_approx(game_state.fleet_speed_multiplier, at_top):
|
||||
return _fail("the fader kept following the pointer after release")
|
||||
print("fader: %.2fx at the bottom, %.2fx at the top, released cleanly" \
|
||||
|
|
@ -135,10 +170,13 @@ func _process(delta: float) -> bool:
|
|||
|
||||
# --- B. it claims the press ------------------------------
|
||||
var zoom_before: float = scene.get_node("Camera2D").zoom.x
|
||||
_click(bottom, true, scene)
|
||||
_click(bottom, false, scene)
|
||||
_push_click(bottom, true)
|
||||
_push_click(bottom, false)
|
||||
if not is_equal_approx(scene.get_node("Camera2D").zoom.x, zoom_before):
|
||||
return _fail("pressing the fader also moved the camera behind it")
|
||||
if mouse_combat.firing:
|
||||
return _fail("the fader's press reached the guns behind it")
|
||||
mouse_combat.pointer_mode = mouse_combat.PointerMode.AUTO
|
||||
print("the press stops at the fader; the world behind it is untouched")
|
||||
|
||||
# --- C/D/E. the formation editor -------------------------
|
||||
|
|
|
|||
Loading…
Reference in a new issue