Joystick de voo
Esta página descreve os conceitos básicos de programação para hastes de voo certificadas pelo Xbox One usando Windows.Gaming.Input.FlightStick e APIs relacionadas para a Plataforma Universal do Windows (UWP).
Ao ler esta página, você saberá como:
- como reunir uma lista de palitos de voo conectados e seus usuários
- como detectar que uma vara de voo foi adicionada ou removida
- como ler a entrada de uma ou mais varas de voo
- como os joysticks de voo se comportam como dispositivos de navegação da interface do usuário
As joystick de voo são dispositivos de entrada de jogos que são valorizados por reproduzir a sensação de joystick de voo que seriam encontradas no cockpit de um avião ou nave espacial. Eles são o dispositivo de entrada perfeito para o controle rápido e preciso do voo. Os joystick de voo têm suporte nos aplicativos Windows 10 ou Windows 11 e Xbox One por meio do namespace Windows.Gaming.Input.
Os joystick de voo certificados pelo Xbox One são equipados com os seguintes controles:
- Um joystick analógico tortuoso capaz de rolar, arremessar e yaw
- Uma restrição analógica
- Dois botões de fogo
- Um comutador de chapéu digital de 8 vias
- Botões Exibir e Menu
Observação
Os botões Exibir e Menu são usados para dar suporte à navegação da interface do usuário, não a comandos de jogo e, portanto, não podem ser facilmente acessados como botões de joystick.
Para aliviar a carga de dar suporte aos diferentes dispositivos de entrada para navegação na interface do usuário e incentivar a consistência entre jogos e dispositivos, a maioria dos dispositivos de entrada física atua simultaneamente como dispositivos de entrada lógica separados chamados controladores de navegação da interface do usuário. O controlador de navegação da interface do usuário fornece um vocabulário comum para comandos de navegação da interface do usuário em dispositivos de entrada.
Como controlador de navegação da interface do usuário, um joystick de voo mapeia o conjunto necessário de comandos de navegação para os botões joystick e View, Menu, FirePrimarye FireSecondary.
Comando de navegação | Entrada de joystick de voo |
---|---|
Operante | Joystick para cima |
Para baixo | Joystick para baixo |
Esquerda | Joystick à esquerda |
Right | Joystick à direita |
Visualizar | Botão Exibir |
Menu | Botão Menu |
Aceitar | Botão FirePrimary |
Cancelar | Botão FireSecondary |
Os joystick de voo não mapeiam nenhum dos conjuntos opcionais de comandos de navegação.
A detecção e o acompanhamento de joystick de voo funcionam exatamente da mesma forma nos gamepads, exceto na classe FlightStick em vez da classe Gamepad. Consulte Gamepad e vibração para obter mais informações.
Depois de identificar o joystick de voo em que você está interessado, você está pronto para coletar informações dele. No entanto, ao contrário de alguns outros tipos de entrada que você pode estar acostumado, os joystick de voo não comunicam a alteração de estado aumentando os eventos. Em vez disso, você faz leituras regulares de seus estados atuais pesquisando-os.
A sondagem captura um instantâneo do joystick de voo em um ponto preciso no tempo. Essa abordagem para coleta de entrada é uma boa opção para a maioria dos jogos porque sua lógica normalmente é executada em um loop determinístico em vez de ser orientada por eventos. Normalmente, também é mais simples interpretar comandos de jogo da entrada coletada de uma só vez do que de muitas entradas simples coletadas ao longo do tempo.
Você sonda um joystick de voo chamando FlightStick.GetCurrentReading. Essa função retorna um FlightStickReading que contém o estado do joystick de voo.
O exemplo a seguir sonda um joystick de voo para seu estado atual:
auto flightStick = myFlightSticks->GetAt(0);
FlightStickReading reading = flightStick->GetCurrentReading();
Além do estado do joystick de voo, cada leitura inclui um carimbo de data/hora que indica precisamente quando o estado foi recuperado. O carimbo de data/hora é útil para se relacionar com o tempo das leituras anteriores ou com o tempo da simulação do jogo.
O joystick fornece uma leitura analógica entre -1.0 e 1.0 nos eixos X, Y e Z (roll, pitch e yaw, respectivamente). Para o roll, um valor de -1.0 corresponde à posição mais à esquerda do joystick, enquanto um valor de 1,0 corresponde à posição mais à direita. Para o pitch, um valor de -1.0 corresponde à posição mais inferior do joystick, enquanto um valor de 1,0 corresponde à posição mais alta. Para yaw, um valor de -1.0 corresponde à posição mais contra-horário, distorcida, enquanto um valor de 1.0 corresponde à posição mais no sentido horário.
Em todos os eixos, o valor é aproximadamente 0,0 quando o joystick está na posição central, mas é normal que o valor preciso varie, mesmo entre as leituras subsequentes. As estratégias para atenuar essa variação serão discutidas posteriormente nesta seção.
O valor do rolo do joystick é lido da propriedade FlightStickReading.Roll, o valor do pitch é lido da propriedade FlightStickReading.Pitche o valor da yaw é lido da propriedade 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;
Ao ler os valores do joystick, você observará que eles não produzem de forma confiável uma leitura neutra de 0,0 quando o joystick estiver em repouso na posição central; Em vez disso, eles produzirão valores diferentes próximos a 0,0 cada vez que o joystick for movido e retornado para a posição central. Para atenuar essas variações, você pode implementar uma pequena zona morta, que é um intervalo de valores próximos à posição central ideal que são ignorados.
Uma maneira de implementar uma zona morta é determinar o quão longe o joystick se moveu do centro e ignorar leituras mais próximas do que alguma distância que você escolher. Você pode calcular a distância aproximadamente—não é exata porque as leituras de joystick são essencialmente valores—polares, não planares, apenas usando o teorema pitagórico. Isso produz uma zona morta radial.
O exemplo a seguir demonstra um deadzone radial básico usando o teorema pitagórico:
// 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 um dos dois botões de fogo do joystick de voo fornece uma leitura digital que indica se ele é pressionado (para baixo) ou liberado (para cima). Para obter eficiência, as leituras de botão não são representadas como valores boolianos individuais. Em vez disso, elas são empacotadas em um único campo de bits representado pela enumeração FlightStickButtons. Além disso, o comutador de chapéu de 8 vias fornece uma direção empacotada em um único campo de bits representado pela enumeração GameControllerSwitchPosition.
Observação
Os joysticks de voo são equipados com botões adicionais usados para a navegação da interface do usuário, como os botões Exibir e Menu. Esses botões não fazem parte da FlightStickButtons
enumeração e só podem ser lidos acessando o joystick de voo como um dispositivo de navegação da interface do usuário. Para obter mais informações, consulte controlador de navegação da interface do usuário.
Os valores de botão são lidos da propriedade FlightStickReading.Buttons. Como essa propriedade é um campo de bits, o mascaramento bit a bit é usado para isolar o valor do botão no qual você está interessado. O botão é pressionado (para baixo) quando o bit correspondente é definido; caso contrário, é liberado (para cima).
O exemplo a seguir determina se o botão FirePrimary é pressionado:
if (FlightStickButtons::FirePrimary == (reading.Buttons & FlightStickButtons::FirePrimary))
{
// FirePrimary is pressed.
}
O exemplo a seguir determina se o botão FirePrimary foi liberado:
if (FlightStickButtons::None == (reading.Buttons & FlightStickButtons::FirePrimary))
{
// FirePrimary is released (not pressed).
}
Às vezes, convém determinar quando um botão passa de pressionado para liberado ou vice-versa, se vários botões foram pressionados ou liberados ou se um conjunto de botões está organizado de determinada maneira—alguns pressionados, outros, não. Para obter informações sobre como detectar cada uma dessas condições, consulte Detectando transições de botão e Detectando arranjos de botões complexos.
O valor do comutador de chapéu é lido da propriedade FlightStickReading.HatSwitch. Como essa propriedade também é um campo de bits, o mascaramento bit a bit é novamente usado para isolar a posição do interruptor de chapéu.
O exemplo a seguir determina se o comutador de chapéu está na posição de cima:
if (GameControllerSwitchPosition::Up == (reading.HatSwitch & GameControllerSwitchPosition::Up))
{
// The hat switch is in the up position.
}
O exemplo a seguir determina se o comutador de chapéu está na posição central:
if (GameControllerSwitchPosition::Center == (reading.HatSwitch & GameControllerSwitchPosition::Center))
{
// The hat switch is in the center position.
}