Volante y retroalimentación de fuerza

En esta página se describen los conceptos básicos de la programación para los volantes de Xbox One con Windows.Gaming.Input.RacingWheel y las API relacionadas para la Plataforma universal de Windows (UWP).

En esta página encontrarás información sobre:

  • cómo recopilar una lista de volantes conectados y sus usuarios
  • cómo detectar que se ha agregado o quitado un volante
  • cómo leer la entrada de uno o varios volantes
  • Cómo enviar comandos de fuerza de respuesta
  • cómo se comportan los volantes como dispositivos de navegación de la interfaz de usuario

Información general sobre los volantes

Los volantes son dispositivos de entrada cuya apariencia se parece mucho a la cabina de un coche de carreras real. Los volantes son el dispositivo de entrada perfecto para los juegos de carreras de estilo Arcade y simulación que representan coches o camiones. Los volantes son compatibles con aplicaciones para UWP de Windows 10 y Xbox One en el espacio de nombres Windows.Gaming.Input.

Los volantes de Xbox One se ofrecen a una variedad de puntos de precio, generalmente tienen más y mejores capacidades de entrada y fuerza de comentarios a medida que sus puntos de precio aumentan. Todos los volantes están equipados con un volante analógico, controles analógicos de acelerador y freno, y algunos botones en la rueda. Algunos volantes están equipados además con controles analógicos de embrague y freno de mano, cambios de patrón y capacidades de respuesta de fuerza. No todos los volantes están equipados con los mismos conjuntos de características, y también pueden variar en su compatibilidad con ciertas características; por ejemplo, los volantes pueden admitir diferentes rangos de rotación y cambios de patrón podrían admitir diferentes números de engranajes.

Funcionalidades del dispositivo

Diferentes volantes de Xbox One ofrecen diferentes conjuntos de funcionalidades de dispositivo opcionales y diferentes niveles de soporte para esas funcionalidades; este nivel de variación entre un solo tipo de dispositivo de entrada es único entre los dispositivos admitidos por la API Windows.Gaming.Input . Además, la mayoría de los dispositivos disponibles admiten como mínimo algunas de las funcionalidades opcionales u otras variaciones. Por este motivo, es importante determinar las funcionalidades de cada volante conectado individualmente y admitir la variación completa de las funcionalidades que tiene sentido para tu juego.

Para obtener más información, consulta Determinar las funcionalidades del volante.

Fuerza de respuesta

Algunos volantes de Xbox One ofrecen verdaderos comentarios de fuerza, es decir, pueden aplicar fuerzas reales en un eje de control, como su volante, no solo vibración simple. Los juegos usan esta capacidad para crear una mayor sensación de inmersión (daño simulado del accidente, "sensación de carretera") y para aumentar el desafío de conducir bien.

Para obtener más información, consulta Información general sobre la fuerza de respuesta.

Navegación de la interfaz de usuario

Para aliviar la carga de la compatibilidad con los diferentes dispositivos de entrada para la navegación de la interfaz de usuario y fomentar la coherencia entre dispositivos y juegos, la mayoría de dispositivos de entrada física actúan simultáneamente como dispositivo independiente de entrada lógica, llamado controlador 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 entre los dispositivos de entrada.

Debido a su enfoque único en los controles analógicos y el grado de variación entre diferentes volantes, normalmente están equipados con un panel D digital, Vista, Menú, A, B, X e Y botones que se asemejan a los de un controlador para juegos; estos botones no están diseñados para admitir comandos de juego y no se puede acceder fácilmente a ellos como botones del volante.

Como controlador de navegación de la interfaz de usuario, los volantes asignan el conjunto necesario de comandos de navegación al stick analógico izquierdo, el panel D, la vista, el menú, los botones A y B .

Comando de navegación Entrada del volante
Subir Cruceta hacia arriba
Bajar Cruceta hacia abajo
Izquierda Cruceta hacia la izquierda
Derecha Cruceta hacia la derecha
Ver Botón de vista
Menú Botón de menú
Aceptar Botón A
Cancelar Botón B

Además, algunos volantes pueden asignar algún conjunto opcional de comandos de navegación a otras entradas que admiten, pero las asignaciones de comandos pueden variar de un dispositivo a otro. Considera la posibilidad de admitir también estos comandos, pero asegúrate de que no son esenciales para navegar por la interfaz del juego.

Comando de navegación Entrada del volante
Re Pág varía
Av Pág varía
Página a la izquierda varía
Página a la derecha varía
Desplazar hacia arriba varía
Desplazar hacia abajo varía
Desplazar a la izquierda varía
Desplazar a la derecha varía
Contexto 1 Botón X (normalmente)
Contexto 2 Botón Y (normalmente)
Contexto 3 varía
Contexto 4 varía

Detectar y realizar un seguimiento de los volantes

La detección y el seguimiento de volantes funciona exactamente de la misma manera que para los controladores para juegos, excepto con la clase RacingWheel en lugar de la clase Gamepad . Consulta Controlador para juegos y vibración para obtener más información.

Lectura del volante

Después de identificar los volantes que le interesan, está listo para recopilar información de ellos. Sin embargo, a diferencia de algunos otros tipos de entrada con los que puedes estar familiarizado, los volantes no comunican el cambio de estado mediante la generación de eventos. En su lugar, se toman lecturas normales de sus estados actuales sondeándolos .

Sondeo del volante

El sondeo captura una instantánea del volante en un momento preciso en el tiempo. Este enfoque para la recopilación de entradas es una buena opción para la mayoría de los juegos porque su lógica normalmente se ejecuta en un bucle determinista en lugar de ser 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 con el tiempo.

Sondeas un volante llamando a GetCurrentReading; esta función devuelve un RacingWheelReading que contiene el estado del volante.

En el siguiente ejemplo se realiza el sondeo del estado actual de un volante.

auto racingwheel = myRacingWheels[0];

RacingWheelReading reading = racingwheel->GetCurrentReading();

Además del estado del volante, cada lectura incluye una marca de tiempo que indica con precisión cuándo se recuperó el estado. La marca de tiempo es útil para establecer una relación con los intervalos de lecturas anteriores o la duración de la simulación de juego.

Determinar las funcionalidades del volante

Muchos de los controles del volante son opcionales o admiten diferentes variaciones incluso en los controles necesarios, por lo que tienes que determinar individualmente las funcionalidades de cada volante para poder procesar la entrada que se recopila en cada lectura del volante.

Los controles opcionales son el freno de mano, el embrague y las palancas de cambios; puedes determinar si un volante conectado admite estos controles mediante la lectura de las propiedades HasHandbrake, HasClutch y HasPatternShifter del volante, respectivamente. El control se admite si el valor de la propiedad es true; de lo contrario, no se admite.

if (racingwheel->HasHandbrake)
{
    // the handbrake is supported
}

if (racingwheel->HasClutch)
{
    // the clutch is supported
}

if (racingwheel->HasPatternShifter)
{
    // the pattern shifter is supported
}

Además, los controles que pueden variar son el volante y la palanca de cambios. El volante pueden variar según el grado de giro físico que puede admitir el volante real, mientras que la palanca de cambios puede variar según el número de velocidades que admita. Para determinar el máximo ángulo de rotación que admite el volante real, lee la propiedad MaxWheelAngle del volante; su valor es el ángulo físico máximo que se admite en grados positivos, igual al valor en grados negativos. Puede determinar el mayor engranaje hacia delante que admite el cambio de patrón leyendo la MaxPatternShifterGear propiedad del volante; su valor es el engranaje hacia delante más alto admitido, inclusivo, es decir, si su valor es 4, entonces el cambio de patrón admite inverso, neutro, primero, segundo, tercero y cuarto engranajes.

auto maxWheelDegrees = racingwheel->MaxWheelAngle;
auto maxShifterGears = racingwheel->MaxPatternShifterGear;

Por último, algunos volantes admiten la fuerza de respuesta a través del volante. Puedes determinar si un volante conectado admite la fuerza de respuesta mediante la lectura de la propiedad WheelMotor del volante. La fuerza de comentarios se admite si WheelMotor no es null; de lo contrario, no se admite.

if (racingwheel->WheelMotor != nullptr)
{
    // force feedback is supported
}

Para obtener información sobre cómo usar la funcionalidad de fuerza de respuesta de los volantes que la admiten, consulta Información general sobre la fuerza de respuesta.

Lectura de los botones

Cada uno de los botones del volante (las cuatro direcciones del panel D, los botones Anterior Gear y Next Gear , y 16 botones adicionales) proporciona una lectura digital que indica si está presionado (hacia abajo) o liberado (hacia arriba). Por motivos de eficacia, las lecturas de los botones no se representan como valores booleanos individuales; en su lugar, se empaquetan todas en un único campo de bits que se representa mediante la enumeración RacingWheelButtons.

Nota

Los volantes 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 RacingWheelButtons y solo se pueden leer accediendo al volante como dispositivo de navegación de la interfaz de usuario. Para obtener más información, consulta UI Navigation Device (Dispositivo de navegación de la interfaz de usuario).

Los valores de los botones se leen en la propiedad Buttons de la estructura RacingWheelReading. Dado que esta propiedad es un campo de bits, se usa el enmascaramiento bit a bit para aislar el valor del botón que te 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 el botón Next Gear está presionado.

if (RacingWheelButtons::NextGear == (reading.Buttons & RacingWheelButtons::NextGear))
{
    // Next Gear is pressed
}

En el ejemplo siguiente, se determina si el botón Next Gear está liberado.

if (RacingWheelButtons::None == (reading.Buttons & RacingWheelButtons::NextGear))
{
    // Next Gear is released (not pressed)
}

A veces, es posible que desee determinar cuándo un botón cambia de presionado a liberado o liberado a presionado, si se presionan o sueltan varios botones, o si un conjunto de botones se organiza de una manera determinada, algunos presionados, algunos no. Para obtener información sobre cómo detectar estas condiciones, consulta Detección de transiciones de botón y Detección disposiciones de botones complejas.

Lectura del volante

El volante es un control necesario que proporciona una lectura analógica entre -1,0 y + 1,0. Un valor de -1,0 corresponde a la posición más a la izquierda del volante; un valor de + 1,0 corresponde a la posición más a la derecha. El valor del volante se lee en la propiedad Wheel de la estructura RacingWheelReading.

float wheel = reading.Wheel;  // returns a value between -1.0 and +1.0.

Aunque las lecturas del volante corresponden a los distintos grados de rotación física del volante real según el rango de rotación que admite el volante físico, lo habitual no es escalar las lecturas del volante; los volantes que admiten mayores grados de rotación simplemente proporcionan una mayor precisión.

Lectura del acelerador y el freno

El acelerador y el freno son controles necesarios que cada uno proporciona lecturas analógicas entre 0,0 (totalmente liberado) y 1,0 (totalmente presionado) representados como valores de punto flotante. El valor del control del acelerador se lee en la propiedad Throttle de la estructura RacingWheelReading; el valor del control del freno se lee en la propiedad Brake.

float throttle = reading.Throttle;  // returns a value between 0.0 and 1.0
float brake    = reading.Brake;     // returns a value between 0.0 and 1.0

Lectura del freno de mano y el embrague

El freno de mano y el embrague son controles opcionales, cada uno de los cuales proporciona lecturas analógicas entre 0,0 (totalmente liberado) y 1,0 (totalmente accionado), que se representan como valores de punto flotante. El valor del control del freno de mano se lee en la propiedad Handbrake de la estructura RacingWheelReading; el valor del control del embrague se lee en la propiedad Clutch.

float handbrake = 0.0;
float clutch = 0.0;

if(racingwheel->HasHandbrake)
{
    handbrake = reading.Handbrake;  // returns a value between 0.0 and 1.0
}

if(racingwheel->HasClutch)
{
    clutch = reading.Clutch;        // returns a value between 0.0 and 1.0
}

Lectura de la palanca de cambios

La palanca de cambios es un control opcional que proporciona una lectura digital entre -1 y MaxPatternShifterGear, que se representa como un valor entero con signo. Un valor de -1 o 0 corresponde a los engranajes inversos y neutros , respectivamente; los valores cada vez más positivos corresponden a mayores marchas hacia delante hasta MaxPatternShifterGear, ambos inclusive. El valor del desplazador de patrones se lee de la propiedad PatternShifterGear de la estructura RacingWheelReading .

if (racingwheel->HasPatternShifter)
{
    gear = reading.PatternShifterGear;
}

Nota

El cambio de patrón, donde se admite, existe junto con los botones De engranaje anterior y Siguiente engranaje necesarios que también afectan al engranaje actual del coche del jugador. Una estrategia sencilla para unificar estas entradas donde ambos están presentes es ignorar el cambio de patrón (y el embrague) cuando un jugador elige una transmisión automática para su automóvil, y ignorar los botones Anterior y Siguiente Engranaje cuando un jugador elige una transmisión manual para su coche solo si su volante está equipado con un control de cambio de patrón. Puedes implementar una estrategia de unificación diferente si esta no te resulta adecuada para el juego.

Ejecución de la muestra de InputInterfacing

La aplicación de ejemplo InputInterfacingUWP en GitHub muestra cómo usar volantes y diferentes tipos de dispositivos de entrada en conjunto; así como cómo se comportan estos dispositivos de entrada como controladores de navegación de la interfaz de usuario.

Información general sobre la fuerza de respuesta

Muchos volantes tienen una capacidad de respuesta forzada para proporcionar una experiencia de conducción más envolvente y desafiante. Los volantes que admiten la fuerza de respuesta suelen estar equipados con un motor único que aplica fuerza al volante a lo largo de un solo eje: el eje de rotación del volante. Forzar comentarios se admite en las aplicaciones para UWP de Windows 10 y Xbox One mediante el espacio de nombres Windows.Gaming.Input.ForceFeedback.

Nota

Las API de respuesta de fuerza son capaces de admitir varios ejes de fuerza, pero actualmente ningún volante de Xbox One admite ningún eje de comentarios que no sea el de rotación de ruedas.

Uso de la fuerza de respuesta

En estas secciones se describen los conceptos básicos de programación de los efectos de la fuerza de respuesta para los volantes de Xbox One. La respuesta se aplica mediante efectos, que se cargan por primera vez en el dispositivo de fuerza de respuesta y, luego, se pueden iniciar, pausar, reanudar y detener de manera similar a los efectos de sonido; sin embargo, primero debes determinar las funcionalidades de respuesta del volante.

Determinar las funcionalidades de fuerza de respuesta

Puedes determinar si un volante conectado admite la fuerza de respuesta mediante la lectura de la propiedad WheelMotor del volante. La fuerza de comentarios no se admite si WheelMotor es null; de lo contrario, se admiten los comentarios forzados y puede continuar para determinar las funcionalidades de comentarios específicas del motor, como los ejes que puede afectar.

if (racingwheel->WheelMotor != nullptr)
{
    auto axes = racingwheel->WheelMotor->SupportedAxes;

    if(ForceFeedbackEffectAxes::X == (axes & ForceFeedbackEffectAxes::X))
    {
        // Force can be applied through the X axis
    }

    if(ForceFeedbackEffectAxes::Y == (axes & ForceFeedbackEffectAxes::Y))
    {
        // Force can be applied through the Y axis
    }

    if(ForceFeedbackEffectAxes::Z == (axes & ForceFeedbackEffectAxes::Z))
    {
        // Force can be applied through the Z axis
    }
}

Carga de los efectos de la fuerza de respuesta

Los efectos de la fuerza de respuesta se cargan en el dispositivo de respuesta donde se "reproducen" de forma autónoma en el comando del juego. Se proporcionan varios efectos básicos; Los efectos personalizados se pueden crear a través de una clase que implementa la interfaz IForceFeedbackEffect .

Clase de efecto Descripción del efecto
ConditionForceEffect Efecto que aplica una fuerza variable en respuesta a un sensor actual dentro del dispositivo.
ConstantForceEffect Efecto que aplica una fuerza constante a lo largo de un vector.
PeriodicForceEffect Efecto que aplica una fuerza variable definida por una forma de onda, a lo largo de un vector.
RampForceEffect Efecto que aplica una fuerza linealmente creciente o decreciente a lo largo de un vector.
using FFLoadEffectResult = ForceFeedback::ForceFeedbackLoadEffectResult;

auto effect = ref new Windows.Gaming::Input::ForceFeedback::ConstantForceEffect();
auto time = TimeSpan(10000);

effect->SetParameters(Windows::Foundation::Numerics::float3(1.0f, 0.0f, 0.0f), time);

// Here, we assume 'racingwheel' is valid and supports force feedback

IAsyncOperation<FFLoadEffectResult>^ request
    = racingwheel->WheelMotor->LoadEffectAsync(effect);

auto loadEffectTask = Concurrency::create_task(request);

loadEffectTask.then([this](FFLoadEffectResult result)
{
    if (FFLoadEffectResult::Succeeded == result)
    {
        // effect successfully loaded
    }
    else
    {
        // effect failed to load
    }
}).wait();

Uso de los efectos de la fuerza de respuesta

Una vez cargados, los efectos se pueden iniciar, pausar, reanudar y detener de forma sincrónica llamando a funciones en la propiedad WheelMotor del volante, o bien individualmente llamando a las funciones del propio efecto de respuesta. Por lo general, se deben cargar todos los efectos que se quieren usar en el dispositivo de respuesta antes de que comience el juego y, luego, usar sus respectivas funciones SetParameters para actualizar los efectos a medida que el juego avanza.

if (ForceFeedbackEffectState::Running == effect->State)
{
    effect->Stop();
}
else
{
    effect->Start();
}

Por último, se puede habilitar, deshabilitar o restablecer de forma asincrónica todo el sistema de fuerza de respuesta en un volante concreto cuando sea necesario.

Vea también