Controlador de jogo bruto

Esta página descreve os conceitos básicos de programação para praticamente qualquer tipo de controlador de jogo usando Windows.Gaming.Input.RawGameController e APIs relacionadas para a Plataforma Universal do Windows (UWP).

Ao ler esta página, você saberá como:

  • como obter uma lista de controladores de jogo brutos e seus usuários
  • como detectar se um controlador de jogo bruto foi adicionado ou removido
  • como obter os recursos de um controlador de jogo bruto
  • como ler a entrada de um controlador de jogo bruto

Visão geral

Um controlador de jogo bruto é uma representação genérica de um controlador de jogo, com entradas encontradas em vários tipos diferentes de controladores de jogos comuns. Essas entradas são expostas como matrizes simples de botões, comutadores e eixos sem nome. Usando um controlador de jogo bruto, você pode permitir que os clientes criem mapeamentos de entrada personalizados, não importando o tipo de controlador que eles estejam usando.

A classe RawGameController é realmente destinada a cenários em que as outras classes de entrada (ArcadeStick, FlightStick e assim por diante) não atendem às suas necessidades— se você quiser algo mais genérico, antecipando que os clientes usarão muitos tipos diferentes de controladores de jogo, essa classe é para você.

Detectar e acompanhar controladores de jogos brutos

A detecção e o acompanhamento de controladores de jogos brutos funcionam exatamente da mesma forma nos gamepads, exceto na classe RawGameController em vez da classe Gamepad. Consulte Gamepad e vibração para obter mais informações.

Obter os recursos de um controlador de jogo bruto

Depois de identificar o controlador de jogo bruto em que você está interessado, será possível coletar informações sobre os recursos do controlador. Você pode obter o número de botões no controlador de jogo bruto com RawGameController.ButtonCount, o número de eixos analógicos com RawGameController.AxisCount e o número de opções com RawGameController.SwitchCount. Além disso, você pode obter o tipo de um comutador usando RawGameController.GetSwitchKind.

O exemplo a seguir obtém as contagens de entrada de um controlador de jogo bruto:

auto rawGameController = myRawGameControllers->GetAt(0);
int buttonCount = rawGameController->ButtonCount;
int axisCount = rawGameController->AxisCount;
int switchCount = rawGameController->SwitchCount;

O exemplo a seguir determina o tipo de cada comutador:

for (uint32_t i = 0; i < switchCount; i++)
{
    GameControllerSwitchKind mySwitch = rawGameController->GetSwitchKind(i);
}

Leitura do controlador de jogo bruto

Depois que você souber o número de entradas em um controlador de jogo bruto, estará pronto para coletar informações dele. No entanto, ao contrário de outros tipos de entrada com os quais você possa estar acostumado, um controlador de jogo bruto não comunica a alteração de estado acionando eventos. Você faz leituras regulares do estado atual deles fazendo uma sondagem.

Sondagem do controlador de jogo bruto

A sondagem registra um instantâneo do controlador de jogo bruto em um momento preciso. Essa abordagem para a coleta de entrada é uma boa ideia para a maioria dos jogos porque sua lógica normalmente é executada em um loop determinístico em vez de ser controlada por eventos. Também é geralmente mais simples interpretar os comandos de jogos da entrada coletados todos de uma vez do que de muitas entradas únicas coletadas ao longo do tempo.

Você sonda um controlador de jogo bruto ao chamar RawGameController.GetCurrentReading. Essa função preenche matrizes de botões, comutadores e eixos que contêm o estado do controlador de jogo bruto.

O exemplo a seguir sonda o estado atual de um controlador de jogo bruto:

Platform::Array<bool>^ currentButtonReading =
    ref new Platform::Array<bool>(buttonCount);

Platform::Array<GameControllerSwitchPosition>^ currentSwitchReading =
    ref new Platform::Array<GameControllerSwitchPosition>(switchCount);

Platform::Array<double>^ currentAxisReading = ref new Platform::Array<double>(axisCount);

rawGameController->GetCurrentReading(
    currentButtonReading,
    currentSwitchReading,
    currentAxisReading);

Não há nenhuma garantia de qual posição em cada matriz manterá qual valor de entrada entre diferentes tipos de controladores, portanto você precisará verificar as entradas usando os métodos RawGameController.GetButtonLabel e RawGameController.GetSwitchKind.

GetButtonLabel informará o texto ou símbolo impresso no botão físico, em vez da função do botão, portanto, ele é melhor usado como um auxílio para interface do usuário para casos em que você deseja dar dicas ao jogador sobre quais botões executam quais funções. GetSwitchKind informará o tipo de comutador (ou seja, quantas posições ele tem), mas não o nome.

Não há nenhuma maneira padronizada para obter o rótulo de um eixo ou de um computador e, portanto, você precisará testá-los por conta própria para determinar as entradas.

Se você tiver um controlador específico ao qual deseja dar suporte, obtenha RawGameController.HardwareProductId e RawGameController.HardwareVendorId e verifique se elas correspondem a esse controlador. A posição de cada entrada em cada matriz é a mesmo para todos os controladores com as mesmas HardwareProductId e HardwareVendorId e, portanto, você não precisa se preocupar se sua lógica estiver sendo potencialmente inconsistente entre os diferentes controladores do mesmo tipo.

Além do estado do controlador de jogo bruto, cada leitura retorna um carimbo de data/hora que indica precisamente quando o estado foi recuperado. O carimbo de data e hora é útil para estabelecer a relação entre o tempo das leituras anteriores e o tempo da simulação do jogo.

Leitura dos botões e comutadores

Cada um dos botões do controlador de jogo bruto fornece uma leitura digital que indica se ele está pressionado (para baixo) ou liberado (para cima). As leituras de botão são representadas como valores Booleanos individuais em uma única matriz. O rótulo de cada botão pode ser encontrado usando RawGameController.GetButtonLabel com o índice do valor Booliano na matriz. Cada valor é representado como um GameControllerButtonLabel.

O exemplo a seguir determina se o botão XboxA está pressionado:

for (uint32_t i = 0; i < buttonCount; i++)
{
    if (currentButtonReading[i])
    {
        GameControllerButtonLabel buttonLabel = rawGameController->GetButtonLabel(i);

        if (buttonLabel == GameControllerButtonLabel::XboxA)
        {
            // XboxA is pressed.
        }
    }
}

Às vezes, talvez você queira determinar quando um botão faz a transição de pressionado para liberado ou liberado para pressionado, se vários botões são pressionados ou liberados ou se um conjunto de botões é organizado de uma maneira específica— alguns pressionados, outros não. Para obter informações sobre como detectar cada uma dessas condições, consulte Detectando transições do botão e Detectando organizações complexas de botão.

Os valores do comutador são fornecidos como uma matriz de GameControllerSwitchPosition. Como essa propriedade é um campo de bits, o mascaramento bit a bit é usado para isolar a direção do comutador.

O exemplo a seguir determina se cada comutador está na posição vertical:

for (uint32_t i = 0; i < switchCount; i++)
{
    if (GameControllerSwitchPosition::Up ==
        (currentSwitchReading[i] & GameControllerSwitchPosition::Up))
    {
        // The switch is in the up position.
    }
}

Leitura das entradas analógicas (joysticks, gatilhos, aceleradores e assim por diante)

Um eixo analógico fornece uma leitura entre 0,0 e 1,0. Isso inclui cada dimensão em um joystick, como X e Y para joysticks padrão, ou até mesmo os eixos X, Y e Z (rolagem, rotação e guinada, respectivamente) para joysticks para simulador de voo.

Os valores podem representar gatilhos e aceleradores analógicos ou qualquer outro tipo de entrada analógica. Esses valores não são fornecidos com rótulos, por isso, sugerimos que seu código seja testado com uma variedade de dispositivos de entrada para garantir que eles correspondam corretamente às suas suposições.

Nos dois eixos, o valor é de aproximadamente 0,5 quando o joystick está na posição central, mas é normal que o valor exato varie, até mesmo entre as leituras subsequentes; as estratégias para atenuar essa variação são abordadas mais adiante nesta seção.

O exemplo a seguir mostra como ler os valores analógicos de um controlador do Xbox:

// Xbox controllers have 6 axes: 2 for each stick and one for each trigger.
float leftStickX = currentAxisReading[0];
float leftStickY = currentAxisReading[1];
float rightStickX = currentAxisReading[2];
float rightStickY = currentAxisReading[3];
float leftTrigger = currentAxisReading[4];
float rightTrigger = currentAxisReading[5];

Na leitura dos valores dos joysticks, você observará que eles não produzem uma leitura neutra confiável de 0,5 quando estão em repouso na posição central; eles produzirão valores diferentes próximos de 0,5 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 a que distância do centro o joystick foi movido e ignorar as leituras mais próximas em vez da distância que você escolher. Você pode calcular a distância aproximadamente , não é exato porque as leituras de vara 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 uma zona morta radial básica usando o 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 = leftStickY * leftStickY;
float adjacentSquared = leftStickX * leftStickX;

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

Confira também