Palanca de mandos
En esta página se describen los conceptos básicos de la programación para los stick piloto certificados para Xbox One mediante Windows.Gaming.Input.FlightStick y las API relacionadas para la Plataforma universal de Windows (UWP).
Al leer esta página, aprenderá lo siguiente:
- cómo recopilar una lista de los stick piloto conectados y sus usuarios
- cómo detectar que se ha agregado o quitado un stick piloto
- cómo leer la entrada de uno o varios stick piloto
- cómo se comportan los sticks piloto como dispositivos de navegación de la interfaz de usuario
Los stick piloto son dispositivos de entrada de juego que se valoran para reproducir la sensación de los stick piloto que se encuentran en una cabina de un avión o nave espacial. Son el dispositivo de entrada perfecto para un control rápido y preciso del vuelo. Los sticks piloto se admiten en aplicaciones de Windows 10 o Windows 11 y Xbox One a través del espacio de nombres Windows.Gaming.Input.
Los stick piloto certificados para Xbox One están equipados con los siguientes controles:
- Un joystick analógico capaz de girar (roll), rotar alrededor del eje x (pitch) y rotar alrededor del eje y (yaw)
- Una limitación analógica
- Dos botones de encendido
- Un botón de punto de mira (POV) digital de 8 vías
- Botones Ver y Menú
Nota
Los botones Ver y Menú se utilizan para admitir la navegación de la interfaz de usuario, no los comandos del juego y, por lo tanto, no se puede acceder a ellos fácilmente como botones de joystick.
Para facilitar la carga de admitir los diferentes dispositivos de entrada para la navegación de la interfaz de usuario y fomentar la coherencia entre juegos y dispositivos, la mayoría de los dispositivos de entrada físicos actúan simultáneamente como dispositivos de entrada lógicos independientes denominados controladores de navegación de la interfaz de usuario. El controlador de navegación de la interfaz de usuario proporciona un vocabulario común para los comandos de navegación de la interfaz de usuario en todos los dispositivos de entrada.
Como controlador de navegación de la interfaz de usuario, un stick piloto asigna el conjunto requirido de comandos de navegación al joystick y a los botones Ver, Menú, FirePrimary y FireSecondary.
Comando de navegación | Entrada del stick piloto |
---|---|
Up (Arriba) | Joystick hacia arriba |
Bajar | Joystick hacia abajo |
Izquierda | Joystick hacia la izquierda |
Right | Joystick hacia la derecha |
Ver | Botón Ver |
Menú | Botón Menú |
Aceptar | Botón FirePrimary |
Cancelar | Botón FireSecondary |
Los stick piloto no asignan ninguno de los conjuntos opcionales de comandos de navegación.
La detección y el seguimiento de los sticks piloto funcionan exactamente de la misma manera que para los controladores para juegos, excepto con la clase FlightStick en lugar de la clase Gamepad. Consulte Controlador para juegos y vibración para obtener más información.
Después de identificar el stick piloto que le interesa, está listo para recopilar las entradas. Sin embargo, a diferencia de otros tipos de entrada a los que podría estar acostumbrado, los stick piloto no comunican cambios de estado mediante la generación de eventos. En su lugar, se toman lecturas regulares de su estado actual sondeándolos.
El sondeo captura una instantánea del stick piloto en un momento dado preciso. Este enfoque para la recopilación de entradas es una buena opción para la mayoría de los juegos, ya que su lógica normalmente se ejecuta en un bucle determinista en lugar de estar controlado por eventos. También suele ser más sencillo interpretar los comandos de juego de la entrada recopiladas a la vez que de muchas entradas únicas recopiladas a lo largo del tiempo.
Sondea un stick piloto llamando a FlightStick.GetCurrentReading. Esta función devuelve un FlightStickReading que contiene el estado del stick piloto.
En el ejemplo siguiente se sondea un stick piloto por su estado actual:
auto flightStick = myFlightSticks->GetAt(0);
FlightStickReading reading = flightStick->GetCurrentReading();
Además del estado del stick piloto, cada lectura incluye una marca de tiempo que indica precisamente cuándo se recuperó el estado. La marca de tiempo es útil para relacionarse con el tiempo de las lecturas anteriores o con el tiempo de la simulación del juego.
El joystick proporciona una lectura analógica entre -1.0 y 1.0 en los ejes X, Y y Z (roll (girar), rotación alrededor del eje x (pitch) y rotación alrededor del eje y (yaw), respectivamente). Para roll, un valor de -1.0 corresponde a la posición del joystick más hacia la izquierda, mientras que un valor de 1.0 corresponde a la posición más hacia la derecha. En el caso de rotación alrededor del eje x (pitch), un valor de -1.0 corresponde a la posición del joystick inferior, mientras que un valor de 1.0 corresponde a la posición más alta. Para la rotación alrededor del eje y (yaw), un valor de -1.0 corresponde a la posición más contraria a las agujas del reloj, mientras que un valor de 1.0 corresponde a la posición más hacia el sentido de las agujas del reloj.
En todos los ejes, el valor es aproximadamente 0.0 cuando el joystick está en la posición central, pero es normal que el valor preciso varíe, incluso entre las lecturas posteriores. Las estrategias para mitigar esta variación se describen más adelante en esta sección.
El valor del balanceo del joystick se lee en la propiedad FlightStickReading.Roll, el valor de rotación alrededor del eje x (pitch) se lee en la propiedad FlightStickReading.Pitch y el valor de rotación alrededor del eje y (yaw) se lee en la propiedad 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;
Al leer los valores del joystick, observará que no producen una lectura neutra de 0.0 cuando el joystick está en reposo en la posición central; en su lugar, generarán valores diferentes cerca de 0.0 cada vez que el joystick se mueve y se devuelve a la posición central. Para mitigar estas variaciones, puede implementar una pequeña zona muerta, que es un intervalo de valores cerca de la posición central ideal que se omite.
Una manera de implementar una zona muerta es determinar hasta dónde se ha movido el joystick desde el centro y omitir las lecturas que están más cerca de alguna distancia que elija. Puede calcular la distancia de manera aproximada (no es exacta porque las lecturas del joystick son esencialmente valores polares, no planos) simplemente usando el teorema de Pitágoras. Esto produce una zona muerta radial.
El siguiente ejemplo demuestra una zona muerta radial básica utilizando el teorema de Pitágoras:
// 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.
}
Cada uno de los dos botones de disparo del stick piloto proporciona una lectura digital que indica si está presionado (hacia abajo) o se libera (hacia arriba). Para mayor eficiencia, las lecturas de los botones no se representan como valores booleanos individuales; en cambio, están todas empaquetadas en un único campo de bits representado por la enumeración FlightStickButtons. Además, el botón de punto de mira (POV) de 8 vías proporciona una dirección empaquetada en un único campo de bits representado por la enumeración GameControllerSwitchPosition.
Nota
Los sticks piloto están equipados con botones adicionales que se usan para la navegación de la interfaz de usuario, como los botones Ver y Menú. Estos botones no forman parte de la enumeración FlightStickButtons
y solo se pueden leer accediendo al stick piloto como un dispositivo de navegación de la interfaz de usuario. Para obtener más información, consulte Controlador de navegación de la interfaz de usuario.
Los valores del botón se leen desde la propiedad FlightStickReading.Buttons. Dado que esta propiedad es un campo de bits, el enmascaramiento de bits se usa para aislar el valor del botón que le interesa. El botón se presiona (abajo) cuando se establece el bit correspondiente; de lo contrario, se libera (arriba).
En el ejemplo siguiente se determina si se presiona el botón FirePrimary:
if (FlightStickButtons::FirePrimary == (reading.Buttons & FlightStickButtons::FirePrimary))
{
// FirePrimary is pressed.
}
En el ejemplo siguiente se determina si se libera el botón FirePrimary:
if (FlightStickButtons::None == (reading.Buttons & FlightStickButtons::FirePrimary))
{
// FirePrimary is released (not pressed).
}
A veces, es posible que desee determinar cuándo un botón cambia de presionado a liberado o de liberado a presionado, si se presionan o sueltan varios botones, o si un conjunto de botones se organizan de una manera determinada, algunos presionados y otros no. Para obtener información sobre cómo detectar cada una de estas condiciones, consulte Detección de transiciones de botón y Detección de arreglos de botón complejos.
El valor del botón de punto de mira (POV) se lee desde la propiedad FlightStickReading.HatSwitch. Dado que esta propiedad también es un campo de bits, el enmascaramiento bit a bit se usa de nuevo para aislar la posición del botón de punto de mira (POV).
En el ejemplo siguiente se determina si el botón de punto de mira (POV) está en la posición hacia arriba:
if (GameControllerSwitchPosition::Up == (reading.HatSwitch & GameControllerSwitchPosition::Up))
{
// The hat switch is in the up position.
}
En el ejemplo siguiente se determina si el botón de punto de mira (POV) está en la posición central:
if (GameControllerSwitchPosition::Center == (reading.HatSwitch & GameControllerSwitchPosition::Center))
{
// The hat switch is in the center position.
}