feat(menu): navegació del menú de servei amb sticks
This commit is contained in:
1 parent
2c1c1a442b
commit
fddea0c449
2 files changed
+76
No files matched your search
@@ -467,6 +467,63 @@ void ServiceMenu::playAcceptSound() {
|
|||||||
Audio::get()->playSound(UiConfig::get().menuAcceptSound(), Audio::Group::INTERFACE);
|
Audio::get()->playSound(UiConfig::get().menuAcceptSound(), Audio::Group::INTERFACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServiceMenu::handleGamepadAxisMotion(const SDL_GamepadAxisEvent& ev) {
|
||||||
|
// Llindars amb histèresi: cal travessar STICK_THRESHOLD per "entrar" a
|
||||||
|
// un extrem, però només es torna a la zona neutra quan baixa de
|
||||||
|
// STICK_RELEASE. Així evitem que petits tremolors al voltant del
|
||||||
|
// llindar facin spam d'events. Valors triats per donar la mateixa
|
||||||
|
// sensació que el stick del jugador (deadzone=12000) però una mica
|
||||||
|
// més estrictes per a la navegació discreta del menú.
|
||||||
|
constexpr Sint16 STICK_THRESHOLD = 16000;
|
||||||
|
constexpr Sint16 STICK_RELEASE = 8000;
|
||||||
|
|
||||||
|
std::int8_t* zone = nullptr;
|
||||||
|
bool horizontal = false;
|
||||||
|
switch (ev.axis) {
|
||||||
|
case SDL_GAMEPAD_AXIS_LEFTX:
|
||||||
|
zone = &lx_zone_;
|
||||||
|
horizontal = true;
|
||||||
|
break;
|
||||||
|
case SDL_GAMEPAD_AXIS_LEFTY:
|
||||||
|
zone = &ly_zone_;
|
||||||
|
horizontal = false;
|
||||||
|
break;
|
||||||
|
case SDL_GAMEPAD_AXIS_RIGHTX:
|
||||||
|
zone = &rx_zone_;
|
||||||
|
horizontal = true;
|
||||||
|
break;
|
||||||
|
case SDL_GAMEPAD_AXIS_RIGHTY:
|
||||||
|
zone = &ry_zone_;
|
||||||
|
horizontal = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // Ignorem L2/R2 i la resta.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Càlcul de la zona nova: si el valor està més enllà del llindar fort,
|
||||||
|
// entra a l'extrem; si està dins de la zona morta, torna a 0; altrament
|
||||||
|
// manté la zona prèvia (banda d'histèresi).
|
||||||
|
std::int8_t new_zone = *zone;
|
||||||
|
if (ev.value > STICK_THRESHOLD) {
|
||||||
|
new_zone = +1;
|
||||||
|
} else if (ev.value < -STICK_THRESHOLD) {
|
||||||
|
new_zone = -1;
|
||||||
|
} else if (std::abs(ev.value) < STICK_RELEASE) {
|
||||||
|
new_zone = 0;
|
||||||
|
}
|
||||||
|
if (new_zone == *zone) { return; }
|
||||||
|
*zone = new_zone;
|
||||||
|
if (new_zone == 0) { return; } // Soltar el stick no dispara res.
|
||||||
|
|
||||||
|
if (horizontal) {
|
||||||
|
activateCurrent(new_zone);
|
||||||
|
playAcceptSound();
|
||||||
|
} else {
|
||||||
|
moveCursor(new_zone);
|
||||||
|
playSelectSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ServiceMenu::handleGamepadButtonDown(const SDL_GamepadButtonEvent& ev) {
|
void ServiceMenu::handleGamepadButtonDown(const SDL_GamepadButtonEvent& ev) {
|
||||||
// El botó SERVICE (per defecte BACK; remapejable per dispositiu via
|
// El botó SERVICE (per defecte BACK; remapejable per dispositiu via
|
||||||
// `GamepadBindings`) tanca el menú sencer. Cada mando pot tenir el
|
// `GamepadBindings`) tanca el menú sencer. Cada mando pot tenir el
|
||||||
@@ -570,6 +627,11 @@ auto ServiceMenu::handleEvent(const SDL_Event& ev) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ev.type == SDL_EVENT_GAMEPAD_AXIS_MOTION) {
|
||||||
|
handleGamepadAxisMotion(ev.gaxis);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (ev.type != SDL_EVENT_KEY_DOWN) { return false; }
|
if (ev.type != SDL_EVENT_KEY_DOWN) { return false; }
|
||||||
|
|
||||||
const auto SC = ev.key.scancode;
|
const auto SC = ev.key.scancode;
|
||||||
|
|||||||
@@ -208,6 +208,12 @@ class ServiceMenu {
|
|||||||
// sota el llindar de clang-tidy.
|
// sota el llindar de clang-tidy.
|
||||||
void handleGamepadButtonDown(const SDL_GamepadButtonEvent& ev);
|
void handleGamepadButtonDown(const SDL_GamepadButtonEvent& ev);
|
||||||
|
|
||||||
|
// Navegació via sticks analògics. Treballa per edge-detection: cada
|
||||||
|
// eix recorda en quina "zona" està (negativa / neutra / positiva) i
|
||||||
|
// sols dispara una acció quan creua de neutra a un extrem, igual que
|
||||||
|
// un botó del DPAD. Aplicada tant al stick esquerre com al dret.
|
||||||
|
void handleGamepadAxisMotion(const SDL_GamepadAxisEvent& ev);
|
||||||
|
|
||||||
// Sons d'UI: SELECT acompanya navegació (amunt/avall) i back; ACCEPT
|
// Sons d'UI: SELECT acompanya navegació (amunt/avall) i back; ACCEPT
|
||||||
// acompanya modificació d'opció (esquerra/dreta/retorn). Els noms de
|
// acompanya modificació d'opció (esquerra/dreta/retorn). Els noms de
|
||||||
// recurs venen d'`UiConfig` i el preload el fa el Director.
|
// recurs venen d'`UiConfig` i el preload el fa el Director.
|
||||||
@@ -270,6 +276,14 @@ class ServiceMenu {
|
|||||||
float transition_progress_{0.0F}; // 0 → 1 durant la transició de pàgina.
|
float transition_progress_{0.0F}; // 0 → 1 durant la transició de pàgina.
|
||||||
bool capturing_{false}; // True mentre esperem una tecla per a un KEY_BIND.
|
bool capturing_{false}; // True mentre esperem una tecla per a un KEY_BIND.
|
||||||
|
|
||||||
|
// Estat per eix del stick per a edge-detection: -1, 0, +1 segons la
|
||||||
|
// zona on viu el valor actual. Un canvi de zona dispara una acció
|
||||||
|
// (només quan entra a un extrem); reset a 0 quan torna al centre.
|
||||||
|
std::int8_t lx_zone_{0};
|
||||||
|
std::int8_t ly_zone_{0};
|
||||||
|
std::int8_t rx_zone_{0};
|
||||||
|
std::int8_t ry_zone_{0};
|
||||||
|
|
||||||
// Sub-mòdul de captura de botons del mando. Quan està actiu absorbeix
|
// Sub-mòdul de captura de botons del mando. Quan està actiu absorbeix
|
||||||
// tots els events de mando (BUTTON_DOWN/UP, AXIS_MOTION) i, en acabar,
|
// tots els events de mando (BUTTON_DOWN/UP, AXIS_MOTION) i, en acabar,
|
||||||
// persisteix la nova configuració via `GamepadBindings`. Replica el
|
// persisteix la nova configuració via `GamepadBindings`. Replica el
|
||||||
|
|||||||
Reference in new issue
Block a user