Files
Matteo Benedetto 2c39d6235f Add gamepad support: stick look, trigger fire, pad menu confirm
- project.godot: joypad events on the ten existing actions (left stick move,
  A jump, right trigger/RB fire, X reload, B/LB grenade, Start pause, Back
  fullscreen), four new look_* actions on the right stick (deadzone 0.2) and
  ui_accept/ui_cancel redefined with the pad buttons A/B while keeping
  Enter/KP Enter/Space/Esc: the 4.7.1 engine maps no pad button on those.
- scripts/player.gd: gamepad_mode turns on by itself on the first pad input;
  _can_aim() replaces the "mouse captured" gate of shoot and grenade (the pad
  never captures the pointer, same trap already fixed for touch);
  _handle_gamepad_look() converts the right stick into equivalent relative
  mouse pixels (900 px/s at full deflection, m^1.8 response) and still goes
  through apply_look(); restart accepts A/X and the death text follows the
  device in use.
- scripts/start_screen.gd: pad hint shown only when a controller is connected,
  refreshed on Input.joy_connection_changed.
- tools/test_gamepad.gd: 33 checks on map structure, keyboard preservation,
  real event pipeline, gamepad_mode and analog look.
- docs/GAMEPAD.md: mapping, code map, verification, known limit (kiosk name
  entry still needs a keyboard: on-screen keyboard is the next step).

Verified: test_gamepad 33/33, test_fullscreen_shortcut 8/8, test_touch_controls
14/14 (--touch), test_grenade 24/24, test_boss 50/50, test_rebalance_branding
14/14, test_player_profile 30/30. test_start_screen keeps its 2 pre-existing
headless failures (identical on HEAD).
2026-10-24 17:42:26 +02:00

3.7 KiB

Gamepad / controller

Supporto ai controller implementato il 2026-10-24. Il gameplay non è stato riscritto: tutte le azioni passano già dalla Input Map, quindi il lavoro è stato mappare i binding, aggiungere il ramo analogico della visuale e aprire i gate che prima pretendevano il mouse catturato.

Mappatura (layout SDL/Xbox)

Azione Tastiera/mouse Gamepad
move_forward / move_back W / S, frecce stick sinistro Y (asse 1)
move_left / move_right A / D, frecce stick sinistro X (asse 0)
jump Spazio A (pulsante 0)
shoot tasto sinistro del mouse grilletto destro (asse 5) · RB (10)
reload R X (pulsante 2)
grenade tasto destro del mouse B (1) · LB (9)
pause Esc Start (6)
toggle_fullscreen Alt+F Back/Select (4)
look_* (nuove) movimento del mouse stick destro (assi 2 e 3)

Tutti i binding joypad hanno device = -1, quindi funzionano con qualunque pad collegato, non solo con il primo.

Dove sta il codice

  • project.godot → [input]: eventi InputEventJoypadButton / InputEventJoypadMotion sulle azioni esistenti, quattro nuove azioni look_left/right/up/down (deadzone 0.2) e la ridefinizione di ui_accept/ui_cancel.
  • scripts/player.gd:
    • gamepad_mode: si accende da solo al primo pulsante/stick usato (_is_gamepad_activity);
    • _can_aim() sostituisce il gate touch_mode or mouse_mode == CAPTURED di sparo e granata: senza, col pad non si sarebbe potuto né sparare né lanciare;
    • _handle_gamepad_look(dt): converte lo stick destro in "pixel relativi equivalenti" (900 px/s a fondo corsa, curva m^1.8) e li passa ad apply_look(), che resta l'unico punto con sensibilità e limiti di inclinazione;
    • a partita finita ricomincia la partita anche con A/X, e il messaggio di morte cambia testo in base al dispositivo in uso.
  • scripts/start_screen.gd: riga di aiuto che compare solo se c'è un pad collegato (aggiornata in hotplug via Input.joy_connection_changed).

Perché ui_accept va ridefinito a mano

Nel motore 4.7.1 ui_accept è mappato su Invio, Invio del tastierino e Spazio, e ui_cancel solo su Esc: nessun pulsante di gamepad. Con il pad si poteva navigare fra i controlli (le ui_up/down/left/right hanno già dpad e stick) ma non confermare. La ridefinizione in project.godot rimette anche i tasti di tastiera: senza, Invio e Spazio avrebbero smesso di funzionare. Il test lo controlla.

Verifica

godot --headless --path . --script res://tools/test_gamepad.gd

33 controlli: struttura della mappa, conservazione dei tasti su ui_accept/ui_cancel, pipeline eventi reale (Input.parse_input_event con un pad su device 0), accensione di gamepad_mode, rotazione della visuale con lo stick destro e limiti di inclinazione.

Con un pad vero conviene rifare la stessa prova a schermo reale (--rendering-method gl_compatibility) perché il puntatore e il focus non sono verificabili in headless. Suite esistenti riverificate: test_fullscreen_shortcut, test_touch_controls -- --touch, test_grenade, test_boss, test_rebalance_branding, test_player_profile tutte verdi. test_start_screen ha 2 FAIL preesistenti (pulsante GIOCA in headless), identici su HEAD senza queste modifiche.

Limite noto: il nome del giocatore

La regola arcade/kiosk chiede il nome a ogni avvio, e il campo è un LineEdit con virtual_keyboard_enabled: la tastiera su schermo del motore però esiste solo su Android/iOS/Web. Con solo il pad, su desktop non c'è modo di scrivere il nome. Fase successiva: tastiera on-screen navigabile col dpad (griglia A-Z), oppure scelta del nome da una lista di profili recenti.