Make the Controls options menu device-aware
Showing both a keyboard key and a gamepad button on every ability row (and WASD movement rows that never had a gamepad equivalent anyway) cluttered the list once a controller is in play. The rebind list now shows only the relevant set for whichever device the player is actually holding: on a gamepad, movement rows disappear entirely (the D-pad/stick isn't individually remapped, so there's nothing to show) and each ability shows only its gamepad button; on keyboard, the reverse. Uses the same Controls.using_gamepad() last-input heuristic as the HUD's ability keycaps, not mere connection presence, so a controller left plugged in but unused doesn't hide keyboard binds from a mouse-and-keyboard player. The list (and its hint text) also swaps live if the player switches device while the panel is open, skipped while a rebind capture is in progress so it can't be torn out from under them. Verified headlessly: keyboard mode shows all 8 rows, gamepad mode shows only the 4 ability rows, and the hint text swaps between them — confirmed with a real screenshot of both states. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MXBNaEBmrYDSMcv4NgUWtV
This commit is contained in:
+46
-9
@@ -82,6 +82,9 @@ var _listening_action: StringName = &""
|
|||||||
var _listening_button: Button = null
|
var _listening_button: Button = null
|
||||||
var _listening_joy_action: StringName = &""
|
var _listening_joy_action: StringName = &""
|
||||||
var _listening_joy_button: Button = null
|
var _listening_joy_button: Button = null
|
||||||
|
# Cached so the rebind list only rebuilds on an actual keyboard<->gamepad switch, not
|
||||||
|
# every frame the Options panel is open.
|
||||||
|
var _rebind_rows_show_gamepad: bool = false
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@@ -186,6 +189,7 @@ func _plaque(hot: bool) -> StyleBoxFlat:
|
|||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
|
_update_rebind_rows_for_device()
|
||||||
if not main_panel.visible or video.stream == null:
|
if not main_panel.visible or video.stream == null:
|
||||||
return
|
return
|
||||||
var frame_count := CAPE_POS.size()
|
var frame_count := CAPE_POS.size()
|
||||||
@@ -294,10 +298,24 @@ func _add_toggle_row(label_text: String, value: bool, setter: Callable, at_index
|
|||||||
options_vbox.move_child(row, at_index)
|
options_vbox.move_child(row, at_index)
|
||||||
|
|
||||||
|
|
||||||
|
## Rebuilds the Controls rebind list for whichever device the player is actually holding
|
||||||
|
## (Controls.using_gamepad(), the same last-input heuristic the HUD's ability keycaps use —
|
||||||
|
## not mere connection presence, so a controller left plugged in but unused doesn't hide
|
||||||
|
## keyboard rebinds from a mouse-and-keyboard player). On a gamepad: movement rows drop
|
||||||
|
## entirely (the D-pad/stick isn't individually remapped, so there's nothing to show), and
|
||||||
|
## each ability shows only its gamepad button. On keyboard: the reverse — WASD-style
|
||||||
|
## keyboard binds only, no gamepad buttons cluttering the list.
|
||||||
func _build_rebind_rows() -> void:
|
func _build_rebind_rows() -> void:
|
||||||
for child in rebind_list.get_children():
|
for child in rebind_list.get_children():
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
|
var gamepad := Controls.using_gamepad()
|
||||||
|
_rebind_rows_show_gamepad = gamepad
|
||||||
|
_update_rebind_hint(gamepad)
|
||||||
for action: StringName in ACTION_LABELS:
|
for action: StringName in ACTION_LABELS:
|
||||||
|
var is_joy_rebindable := Controls.JOY_REBINDABLE_ACTIONS.has(String(action))
|
||||||
|
if gamepad and not is_joy_rebindable:
|
||||||
|
continue # movement: nothing to show/rebind on a gamepad
|
||||||
|
|
||||||
var row := HBoxContainer.new()
|
var row := HBoxContainer.new()
|
||||||
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
|
||||||
@@ -312,16 +330,15 @@ func _build_rebind_rows() -> void:
|
|||||||
name_label.add_theme_constant_override("outline_size", 5)
|
name_label.add_theme_constant_override("outline_size", 5)
|
||||||
row.add_child(name_label)
|
row.add_child(name_label)
|
||||||
|
|
||||||
var key_button := Button.new()
|
if not gamepad:
|
||||||
key_button.custom_minimum_size = Vector2(160, 0)
|
var key_button := Button.new()
|
||||||
key_button.text = Controls.get_key_label(action)
|
key_button.custom_minimum_size = Vector2(160, 0)
|
||||||
_style_button(key_button, false)
|
key_button.text = Controls.get_key_label(action)
|
||||||
key_button.pressed.connect(_on_rebind_pressed.bind(action, key_button))
|
_style_button(key_button, false)
|
||||||
row.add_child(key_button)
|
key_button.pressed.connect(_on_rebind_pressed.bind(action, key_button))
|
||||||
|
row.add_child(key_button)
|
||||||
|
|
||||||
# Movement stays on the D-pad/stick (standard, not individually remapped) — only the
|
if gamepad and is_joy_rebindable:
|
||||||
# face-button abilities get a gamepad rebind button, alongside the keyboard one.
|
|
||||||
if Controls.JOY_REBINDABLE_ACTIONS.has(String(action)):
|
|
||||||
var joy_button := Button.new()
|
var joy_button := Button.new()
|
||||||
joy_button.custom_minimum_size = Vector2(72, 0)
|
joy_button.custom_minimum_size = Vector2(72, 0)
|
||||||
joy_button.text = Controls.get_joy_button_label(action)
|
joy_button.text = Controls.get_joy_button_label(action)
|
||||||
@@ -332,6 +349,26 @@ func _build_rebind_rows() -> void:
|
|||||||
rebind_list.add_child(row)
|
rebind_list.add_child(row)
|
||||||
|
|
||||||
|
|
||||||
|
func _update_rebind_hint(gamepad: bool) -> void:
|
||||||
|
var hint := get_node_or_null("OptionsPanel/VBox/Hint") as Label
|
||||||
|
if hint != null:
|
||||||
|
hint.text = "Click a button, then press a new one on your controller. Esc cancels." \
|
||||||
|
if gamepad else "Click a key, then press a new key. Esc cancels."
|
||||||
|
|
||||||
|
|
||||||
|
# Live-swaps the rebind list if the player switches device while the Options panel is open
|
||||||
|
# (e.g. they were clicking through with a mouse, then pick up a controller). Skipped while
|
||||||
|
# actively listening for a rebind so an in-progress capture never gets torn out from under
|
||||||
|
# the player.
|
||||||
|
func _update_rebind_rows_for_device() -> void:
|
||||||
|
if not options_panel.visible:
|
||||||
|
return
|
||||||
|
if _listening_action != &"" or _listening_joy_action != &"":
|
||||||
|
return
|
||||||
|
if Controls.using_gamepad() != _rebind_rows_show_gamepad:
|
||||||
|
_build_rebind_rows()
|
||||||
|
|
||||||
|
|
||||||
func _on_play_pressed() -> void:
|
func _on_play_pressed() -> void:
|
||||||
_set_buttons_disabled(true)
|
_set_buttons_disabled(true)
|
||||||
Run.start_new_run() # fresh map for this run; the arena is the intro fight
|
Run.start_new_run() # fresh map for this run; the arena is the intro fight
|
||||||
|
|||||||
Reference in New Issue
Block a user