Partager via


Contrôleur de jeu brut

Cette page décrit les principes de base de la programmation pour presque n’importe quel type de contrôleur de jeu à l’aide de Windows.Gaming.Input.RawGameController et des API associées pour la plateforme Windows universelle (UWP).

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

  • comment rassembler une liste de contrôleurs de jeu bruts connectés et de leurs utilisateurs
  • comment détecter qu’un contrôleur de jeu brut a été ajouté ou supprimé
  • comment obtenir les fonctionnalités d’un contrôleur de jeu brut
  • comment lire l’entrée à partir 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 différents de contrôleurs de jeu courants. Ces entrées sont exposées sous forme de tableaux simples de boutons, commutateurs et 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 souhaitez quelque chose de plus générique, en prévision que les clients utiliseront de nombreux types de contrôleurs de jeu différents, alors 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 façon que pour les boîtiers de commande, sauf avec la classe RawGameController au lieu de la classe Gamepad . Pour obtenir plus d’informations, consultez Boîtier de commande et vibrations.

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

Après avoir identifié le contrôleur de jeu brut qui vous intéresse, vous pouvez collecter des informations sur les fonctionnalités du contrôleur. 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 le nombre 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 du contrôleur de jeu brut

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 que vous pouvez utiliser, un contrôleur de jeu brut ne communique pas le changement d’état en générant 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 un instantané du contrôleur de jeu brut à un moment précis dans le temps. Cette approche de la collecte d’entrée est adaptée à 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’entrées collectées toutes en même temps plutôt 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 des tableaux pour les boutons, commutateurs et 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 dans chaque tableau qui contiendra la valeur d’entrée parmi différents types de contrôleurs. Vous devez donc vérifier quelle entrée consiste à utiliser les méthodes RawGameController.GetButtonLabel et RawGameController.GetSwitchKind.

GetButtonLabel vous 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 l’interface utilisateur pour les cas où vous souhaitez donner aux joueurs des indications 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 devrez 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 vérifier s’ils correspondent à ce contrôleur. La position de chaque entrée dans chaque tableau est la même pour chaque contrôleur avec le même HardwareProductId et HardwareVendorId. Vous n’avez donc pas à vous soucier de votre logique potentiellement incohérente entre différents contrôleurs du même type.

En plus de l’état du contrôleur de jeu brut, chaque lecture retourne un horodatage qui indique précisément quand l’état a été récupéré. Le timestamp est utile pour se rapporter au minutage des lectures précédentes ou au minutage de la simulation de jeu.

Lecture des boutons et des commutateurs

Chacun des boutons du contrôleur de jeu brut fournit une lecture numérique qui indique s’il est enfoncé (bas) ou relâché (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 le bouton XboxA est enfoncé :

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

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

Vous pouvez avoir besoin de savoir quand un bouton passe de l’état appuyé à l’état relâché, ou inversement, si plusieurs boutons sont à l’état appuyé ou relâché, ou si un groupe de boutons a une disposition particulière, certains présentant l’état appuyé et d’autres l’état relâché. Pour plus d’informations sur la détection de chacune de ces conditions, consultez Détection des transitions de boutons et Détection des dispositions complexes des boutons.

Les valeurs de commutateur sont fournies sous la forme d’un 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 de 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 tel que X et Y pour les bâtons standard ou même les axes X, Y et Z (rouleau, tangage et lacet, respectivement) pour les bâtons 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 un large éventail d’appareils d’entrée pour s’assurer qu’ils correspondent correctement à vos hypothèses.

Dans tous les axes, la valeur est d’environ 0,5 pour un bâton lorsqu’elle est 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 à partir d’un contrôleur 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 stick, vous remarquerez qu’elles ne produisent pas de lecture neutre de 0,5 au repos dans la position centrale ; Au lieu de cela, ils produisent des valeurs différentes près de 0,5 chaque fois que le stick est déplacé et retourné à la position centrale. Pour atténuer ces variations, vous pouvez implémenter une petite zone morte, qui est une plage de valeurs proche de la position centrale idéale qui sont ignorées.

L’une des façons d’implémenter une zone morte consiste à déterminer la distance à laquelle le stick est déplacé du centre et à ignorer les lectures qui sont plus proches que la distance que vous choisissez. Vous pouvez calculer la distance à peu près , ce n’est pas exact, car les lectures stick sont essentiellement polaires, pas planaires, valeurs, juste en utilisant le théorème pythagorean. Cela produit une zone morte radiale.

L’exemple suivant illustre une zone morte radiale simple calculée à 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