Partager via


Contrôleur de jeu brut

Cette page décrit les principes de base de la programmation pour presque tous les types de contrôleurs de jeu à l’aide de Windows.Gaming.Input.RawGameController et des API associées pour le plateforme Windows universelle (UWP).

Voici ce que vous allez apprendre à la lecture de cet article :

  • comment rassembler une liste des contrôleurs de jeu brut connectés et de leurs utilisateurs
  • comment détecter qu’une manette de jeu brute a été ajoutée ou supprimée
  • comment obtenir les fonctionnalités d’un contrôleur de jeu brut
  • comment lire l’entrée d’un contrôleur de jeu brut

Vue d’ensemble

Un contrôleur de jeu brut est une représentation générique d’un contrôleur de jeu, avec des entrées trouvées sur de nombreux types de contrôleurs de jeu courants. Ces entrées sont exposées sous forme de tableaux simples de boutons, de commutateurs et d’axes sans nom. À l’aide d’un contrôleur de jeu brut, vous pouvez autoriser les clients à créer des mappages d’entrée personnalisés, quel que soit le type de contrôleur qu’ils utilisent.

La classe RawGameController est vraiment destinée aux scénarios où les autres classes d’entrée (ArcadeStick, FlightStick, etc.) ne répondent pas à vos besoins. Si vous voulez quelque chose de plus générique, en anticipant que les clients utiliseront de nombreux types différents de contrôleurs de jeu, cette classe est pour vous.

Détecter et suivre les contrôleurs de jeu bruts

La détection et le suivi des contrôleurs de jeu bruts fonctionnent exactement de la même manière que pour les boîtiers de commande, sauf avec la classe RawGameController au lieu de la classe Gamepad . Pour plus d’informations, consultez Boîtier de commande et vibrations .

Obtenir les fonctionnalités d’un contrôleur de jeu brut

Une fois que vous avez identifié le contrôleur de jeu brut qui vous intéresse, vous pouvez recueillir des informations sur les fonctionnalités de la manette. Vous pouvez obtenir le nombre de boutons sur le contrôleur de jeu brut avec RawGameController.ButtonCount, le nombre d’axes analogiques avec RawGameController.AxisCount et le nombre de commutateurs avec RawGameController.SwitchCount. En outre, vous pouvez obtenir le type d’un commutateur à l’aide de RawGameController.GetSwitchKind.

L’exemple suivant obtient les nombres d’entrées d’un contrôleur de jeu brut :

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

L’exemple suivant détermine le type de chaque commutateur :

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

Lecture de la manette de jeu brute

Une fois que vous connaissez le nombre d’entrées sur un contrôleur de jeu brut, vous êtes prêt à collecter des entrées à partir de celle-ci. Toutefois, contrairement à d’autres types d’entrée auxquels vous pouvez être habitué, une manette de jeu brute ne communique pas le changement d’état en soulevant des événements. Au lieu de cela, vous prenez des lectures régulières de son état actuel en l’interrogeant .

Interrogation du contrôleur de jeu brut

L’interrogation capture une instantané du contrôleur de jeu brut à un moment précis. Cette approche de la collecte d’entrées convient parfaitement à la plupart des jeux, car leur logique s’exécute généralement dans une boucle déterministe plutôt que d’être pilotée par les événements. Il est également généralement plus simple d’interpréter les commandes de jeu à partir d’une entrée collectée en même temps que de nombreuses entrées uniques collectées au fil du temps.

Vous interrogez un contrôleur de jeu brut en appelant RawGameController.GetCurrentReading. Cette fonction remplit les tableaux pour les boutons, les commutateurs et les axes qui contiennent l’état du contrôleur de jeu brut.

L’exemple suivant interroge un contrôleur de jeu brut pour son état actuel :

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);

Il n’existe aucune garantie quant à la position de chaque tableau qui contiendra la valeur d’entrée parmi les différents types de contrôleurs. Vous devez donc case activée quelle entrée est celle qui utilise les méthodes RawGameController.GetButtonLabel et RawGameController.GetSwitchKind.

GetButtonLabel indique le texte ou le symbole imprimé sur le bouton physique, plutôt que la fonction du bouton. Par conséquent, il est préférable d’utiliser comme aide pour l’interface utilisateur dans les cas où vous souhaitez donner au joueur des conseils sur les boutons qui exécutent les fonctions. GetSwitchKind vous indique le type de commutateur (c’est-à-dire le nombre de positions qu’il possède), mais pas le nom.

Il n’existe aucun moyen standardisé d’obtenir l’étiquette d’un axe ou d’un commutateur. Vous devez donc les tester vous-même pour déterminer quelle entrée est laquelle.

Si vous avez un contrôleur spécifique que vous souhaitez prendre en charge, vous pouvez obtenir rawGameController.HardwareProductId et RawGameController.HardwareVendorId et case activée s’ils correspondent à ce contrôleur. La position de chaque entrée dans chaque tableau est la même pour chaque contrôleur avec les mêmes HardwareProductId et HardwareVendorId, de sorte que vous n’avez pas à vous soucier de votre logique potentiellement incohérente entre différents contrôleurs du même type.

En plus de l’état brut du contrôleur de jeu, chaque lecture renvoie un horodatage qui indique précisément quand l’état a été récupéré. Cet horodatage est utile pour faire le lien avec le minutage des valeurs précédentes ou de la simulation de jeu.

Lecture des boutons et des commutateurs

Chacun des boutons de la manette de jeu brut fournit une lecture numérique qui indique si elle est enfoncée (bas) ou relâchée (haut). Les lectures de boutons sont représentées sous forme de valeurs booléennes individuelles dans un tableau unique. L’étiquette de chaque bouton est disponible à l’aide de RawGameController.GetButtonLabel avec l’index de la valeur booléenne dans le tableau. Chaque valeur est représentée sous la forme d’un GameControllerButtonLabel.

L’exemple suivant détermine si la touche XboxA est enfoncée :

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

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

Parfois, vous pouvez déterminer quand un bouton passe d’un bouton enfoncé à relâché ou relâché à un bouton enfoncé, si plusieurs boutons sont enfoncés ou relâchés, ou si un ensemble de boutons sont organisés d’une manière particulière (certains appuyés, d’autres non). Pour plus d’informations sur la détection de chacun de ces états, consultez Détecter les changements d’état des boutons et Détecter les dispositions de boutons complexes.

Les valeurs de commutateur sont fournies sous forme de tableau de GameControllerSwitchPosition. Étant donné que cette propriété est un champ de bits, le masquage au niveau du bit est utilisé pour isoler la direction du commutateur.

L’exemple suivant détermine si chaque commutateur est en position haut :

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

Lecture des entrées analogiques (sticks, déclencheurs, limitations, et ainsi de suite)

Un axe analogique fournit une lecture comprise entre 0,0 et 1,0. Cela inclut chaque dimension sur un bâton comme X et Y pour les sticks standard ou même les axes X, Y et Z (roulis, tangage et lacet, respectivement) pour les sticks de vol.

Les valeurs peuvent représenter des déclencheurs analogiques, des limitations ou tout autre type d’entrée analogique. Ces valeurs ne sont pas fournies avec des étiquettes. Nous vous suggérons donc de tester votre code avec divers périphériques d’entrée pour nous assurer qu’ils correspondent correctement à vos hypothèses.

Dans tous les axes, la valeur est d’environ 0,5 pour un bâton lorsqu’il se trouve en position centrale, mais il est normal que la valeur précise varie, même entre les lectures suivantes ; les stratégies d’atténuation de cette variation sont abordées plus loin dans cette section.

L’exemple suivant montre comment lire les valeurs analogiques d’une manette 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];

Lors de la lecture des valeurs de stick, vous remarquerez qu’elles ne produisent pas de manière fiable une lecture neutre de 0,5 au repos dans la position centrale ; au lieu de cela, ils produisent des valeurs différentes proches de 0,5 chaque fois que le stick est déplacé et retourné à la position centrale. Pour compenser ces variations, vous pouvez implémenter une petite zone morte, qui correspond à une plage de valeurs proches de la position centrale idéale à ignorer.

Une façon d’implémenter une zone morte consiste à déterminer la distance à laquelle le stick s’est déplacé du centre et à ignorer les lectures qui sont plus proches que la distance choisie. Vous pouvez calculer la distance à peu près (ce n’est pas exact, car les valeurs de stick sont essentiellement polaires, et non planaires), simplement à l’aide du théorème de Pythagore. Vous obtenez ainsi une zone morte radiale.

L’exemple suivant illustre une zone morte radiale de base à l’aide du théorème de Pythagore :

// 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.
}

Voir aussi