Joystick volo

Questa pagina descrive le nozioni di base della programmazione per le levette di volo certificate per Xbox One usando Windows.Gaming.Input.FlightStick e le API correlate per la piattaforma UWP (Universal Windows Platform).

Leggendo questa pagina, si apprenderà quanto segue:

  • come raccogliere un elenco di levette di volo connesse e i relativi utenti
  • come rilevare che una levetta di volo è stata aggiunta o rimossa
  • come leggere l'input da una o più levetta di volo
  • come conoscere il comportamento delle levette di volo in quanto dispositivi di spostamento di interfaccia utente

Panoramica

Le levette di volo sono dispositivi di input di gioco apprezzate per riprodurre l'aspetto dei controlli di volo di un aereo o nella cabina di pilotaggio di un'astronave. Sono il dispositivo di input perfetto per un controllo rapido e accurato del volo. Le levette di volo sono supportate nelle app Windows 10 o Windows 11 e Xbox One tramite lo spazio dei nomi Windows.Gaming.Input.

Le levette di volo certificate Xbox One sono dotate dei controlli seguenti:

  • Un joystick analogico torcibile in grado di eseguire roll, pitch e yaw
  • Un limitatore analogico
  • Due pulsanti di sparo
  • Un hat switch digitale a 8 vie
  • Pulsanti Visualizza e Menu

Nota

I pulsanti Visualizza e Menu vengono usati per supportare lo spostamento dell'interfaccia utente, non i comandi di gioco, e pertanto non sono essere facilmente accessibili come pulsanti joystick.

Esplorazione dell'interfaccia utente

Al fine di semplificare l'onere di supportare dispositivi di input diversi per lo spostamento nell'interfaccia utente e per incoraggiare la coerenza tra giochi e dispositivi, la maggior parte dei dispositivi di input fisici agisce simultaneamente come un dispositivo di input logico separato, chiamato controller di spostamento dell'interfaccia utente. Il controller di spostamento interfaccia utente fornisce un vocabolario comune ai comandi di spostamento interfaccia utente tra i vari dispositivi di input.

Come controller di spostamento interfaccia utente, una levetta di volo esegue il mapping del set necessario di comandi di spostamento al joystick e ai pulsanti Visualizza, Menu, FirePrimary e FireSecondary.

Comando Navigazione Input della levetta di volo
Attivo Joystick su
Giù Joystick giù
Sinistra Joystick a sinistra
Right Joystick a destra
Visualizza Pulsante Visualizza
Menu Pulsante Menu
Accetta Pulsante FirePrimary
Annulla Pulsante FireSecondary

Le levette di volo non eseguono nessun mapping facoltativo di comandi di spostamento.

Rilevare e tenere traccia delle levette di volo

Il rilevamento e il tracciamento delle levette di volo funziona esattamente come per i gamepad, ma con la classe FlightStick anziché con la classe Gamepad. Per maggiori informazioni, vedere Gamepad e vibrazione.

Lettura della levetta di volo

Dopo avere identificato la levetta di volo, sarà possibile raccoglierne l'input. Tuttavia, a differenza di altri tipi di input più comuni, le levette di volo non comunicano la modifica dello stato generando eventi. È invece possibile leggere regolarmente lo stato corrente eseguendo il polling.

Polling della levetta di volo

Il polling acquisisce uno snapshot della levetta di volo in un momento preciso. Questo approccio alla raccolta di input è ideale per la maggior parte dei giochi, perché la logica viene in genere eseguita in un ciclo deterministico anziché essere basata su eventi. In genere è anche più semplice interpretare i comandi del gioco dall'input raccolto in una sola volta rispetto a molti input singoli raccolti nel corso del tempo.

Si esegue il polling di una levetta di volo chiamando FlightStick.GetCurrentReading. Questa funzione restituisce un FlightStickReading che contiene lo stato della levetta di volo.

Nell'esempio seguente viene eseguito il polling di una levetta di volo per il relativo stato corrente.

auto flightStick = myFlightSticks->GetAt(0);
FlightStickReading reading = flightStick->GetCurrentReading();

Oltre allo stato della levetta di volo, ogni lettura include un timestamp che indica esattamente quando è stato recuperato lo stato. Il timestamp è utile per la correlazione tra la tempistica delle letture precedenti o la tempistica della simulazione del gioco.

Lettura del joystick e dell'input del limitatore

Il joystick fornisce una lettura analogica tra -1.0 e 1.0 rispettivamente negli assi X, Y e Z (roll, pitch e yaw). Per il roll, il valore -1.0 corrisponde alla posizione del joystick più a sinistra, mentre il valore 1.0 corrisponde alla posizione più a destra. Per il pitch, il valore -1.0 corrisponde alla posizione del joystick più in basso, mentre il valore 1.0 corrisponde alla posizione più in alto. Per yaw (imbardata), il valore -1.0 corrisponde alla posizione più in senso antiorario, ruotata, mentre il valore 1.0 corrisponde alla posizione più in senso orario.

In tutti gli assi, il valore è circa 0.0 quando il joystick si trova nella posizione centrale, ma è normale che il valore preciso possa variare, anche tra letture successive. Le strategie per ridurre questa variante sono illustrate più avanti in questa sezione.

Il valore di roll del joystick viene letto dalla proprietà FlightStickReading.Roll, il valore di pitch viene letto dalla proprietà FlightStickReading.Pitch e il valore di yaw viene letto dalla proprietà FlightStickReading.Yaw:

// Each variable will contain a value between -1.0 and 1.0.
float roll = reading.Roll;
float pitch = reading.Pitch;
float yaw = reading.Yaw;

Quando si leggono i valori del joystick, si noterà che non producono in modo affidabile una lettura neutra di 0,0 quando il joystick è inattivo nella posizione centrale; producono invece valori diversi vicino a 0,0 ogni volta che il joystick viene spostato e restituito alla posizione centrale. Per attenuare queste variazioni, è possibile implementare una piccola zona morta, ovvero un intervallo di valori vicino alla posizione centrale ideale che viene ignorato.

Un modo per implementare una zona morta consiste nel determinare quanto lontano il joystick si è spostato dal centro e ignorare le letture che sono più vicine a una distanza scelta. È possibile calcolare la distanza approssimativamente; la distanza non è esatta perché le letture del joystick sono essenzialmente polari, e non planari, solo usando il teorema di Pitagora. In questo modo viene generato un zona morta radiale.

L'esempio seguente illustra una zona morta radiale di base usando il teorema di Pitagora:

// Choose a deadzone. Readings inside this radius are ignored.
const float deadzoneRadius = 0.1f;
const float deadzoneSquared = deadzoneRadius * deadzoneRadius;

// Pythagorean theorem: For a right triangle, hypotenuse^2 = (opposite side)^2 + (adjacent side)^2
float oppositeSquared = pitch * pitch;
float adjacentSquared = roll * roll;

// Accept and process input if true; otherwise, reject and ignore it.
if ((oppositeSquared + adjacentSquared) < deadzoneSquared)
{
    // Input accepted, process it.
}

Lettura di pulsanti e hat switch

Ognuno dei due pulsanti di sparo della levetta di volo fornisce una lettura digitale che indica se è premuto (giù) o rilasciato (su). Per una questione di efficienza, le letture dei pulsanti non sono rappresentate come singoli valori booleani, bensì sono tutti compressi in un singolo campo di bit rappresentato dall'enumerazione FlightStickButtons. Inoltre, l'hat switch a 8 vie fornisce una direzione compressa in un singolo campo di bit rappresentato dall'enumerazione GameControllerSwitchPosition.

Nota

Le levette di volo sono dotate di pulsanti aggiuntivi per lo spostamento nell'interfaccia utente, ad esempio i pulsanti Visualizza e Menu. Questi pulsanti non fanno parte dell'enumerazione FlightStickButtons e possono essere letti solo accedendo alla levetta di volo come dispositivo di spostamento dell'interfaccia utente. Per maggiori informazioni, vedere Dispositivo di navigazione dell'interfaccia.

I valori del pulsante vengono letti dalla proprietà FlightStickReading.Buttons. Poiché questa proprietà è un campo di bit, viene usata la maschera bit per bit per isolare il valore del pulsante a cui si è interessati. Il pulsante viene premuto (giù) quando viene impostato il bit corrispondente; in caso contrario, viene rilasciato (su).

L'esempio seguente determina se viene premuto il pulsante FirePrimary.

if (FlightStickButtons::FirePrimary == (reading.Buttons & FlightStickButtons::FirePrimary))
{
    // FirePrimary is pressed.
}

L'esempio seguente determina se viene rilasciato il pulsante FirePrimary.

if (FlightStickButtons::None == (reading.Buttons & FlightStickButtons::FirePrimary))
{
    // FirePrimary is released (not pressed).
}

Talvolta si potrebbe voler determinare se un pulsante passa da premuto a rilasciato o da rilasciato a premuto, se più pulsanti vengono premuti o rilasciati o se un set di pulsanti è disposto in un modo particolare (alcuni premuti, altri no). Per informazioni su come rilevare queste condizioni, vedere Rilevamento delle transizioni dei pulsanti e Rilevamento di disposizioni complesse dei pulsanti.

Il valore dell'hat switch viene letto dalla proprietà FlightStickReading.HatSwitch. Poiché questa proprietà è anche un campo di bit, il mascheramento bit per bit viene usato di nuovo per isolare la posizione dell'hat switch.

L'esempio seguente determina se l'hat switch si trova in posizione su:

if (GameControllerSwitchPosition::Up == (reading.HatSwitch & GameControllerSwitchPosition::Up))
{
    // The hat switch is in the up position.
}

L'esempio seguente determina se l'hat switch si trova in posizione centrale:

if (GameControllerSwitchPosition::Center == (reading.HatSwitch & GameControllerSwitchPosition::Center))
{
    // The hat switch is in the center position.
}

Vedi anche