Freigeben über


Unformatierter Gamecontroller

Auf dieser Seite werden die Grundlagen der Programmierung für nahezu jede Art von Gamecontroller mit Windows.Gaming.Input.RawGameController und verwandten APIs für die Universelle Windows-Plattform (UWP) beschrieben.

Auf dieser Seite erhalten Sie Informationen zu folgenden Vorgängen:

  • So sammeln Sie eine Liste der verbundenen unformatierten Gamecontroller und deren Benutzer
  • Wie sie erkennen, dass ein unformatierter Gamecontroller hinzugefügt oder entfernt wurde
  • So erhalten Sie die Funktionen eines unformatierten Gamecontrollers
  • Lesen von Eingaben über einen unformatierten Gamecontroller

Übersicht

Ein unformatierter Gamecontroller ist eine generische Darstellung eines Gamecontrollers, dessen Eingaben auf vielen verschiedenen Arten von gängigen Gamecontrollern zu finden sind. Diese Eingaben werden als einfache Arrays von nicht benannten Schaltflächen, Schaltern und Achsen verfügbar gemacht. Mit einem unformatierten Gamecontroller können Sie es Kunden ermöglichen, benutzerdefinierte Eingabezuordnungen zu erstellen, unabhängig davon, welche Art von Controller sie verwenden.

Die RawGameController-Klasse ist wirklich für Szenarien gedacht, wenn die anderen Eingabeklassen (ArcadeStick, FlightStick usw.) Nicht Ihren Anforderungen entsprechen – wenn Sie etwas allgemeineres möchten, antizipieren, dass Kunden viele verschiedene Arten von Gamecontrollern verwenden, dann ist diese Klasse für Sie gedacht.

Erkennen und Nachverfolgen von unformatierten Gamecontrollern

Das Erkennen und Nachverfolgen von unformatierten Gamecontrollern funktioniert genauso wie für Gamepads, mit Ausnahme der RawGameController-Klasse anstelle der Gamepad-Klasse . Weitere Informationen finden Sie unter Gamepad und Vibration.

Abrufen der Funktionen eines unformatierten Gamecontrollers

Nachdem Sie den unformatierten Gamecontroller identifiziert haben, an dem Sie interessiert sind, können Sie Informationen zu den Funktionen des Controllers sammeln. Sie können die Anzahl der Schaltflächen auf dem unformatierten Gamecontroller mit RawGameController.ButtonCount, die Anzahl der analogen Achsen mit RawGameController.AxisCount und die Anzahl der Switches mit RawGameController.SwitchCount abrufen. Darüber hinaus können Sie den Typ eines Switches mit RawGameController.GetSwitchKind abrufen.

Das folgende Beispiel ruft die Eingabeanzahl eines unformatierten Gamecontrollers ab:

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

Im folgenden Beispiel wird der Typ der einzelnen Schalter bestimmt:

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

Lesen des unformatierten Gamecontrollers

Nachdem Sie die Anzahl der Eingaben auf einem unformatierten Gamecontroller kennen, können Sie Eingaben daraus sammeln. Im Gegensatz zu anderen Arten von Eingaben, für die Sie möglicherweise verwendet werden, kommuniziert ein unformatierter Gamecontroller nicht über Zustandsänderungen, indem Ereignisse ausgelöst werden. Stattdessen nehmen Sie regelmäßige Leseergebnisse des aktuellen Zustands, indem Sie ihn abfragen .

Abrufen des unformatierten Gamecontrollers

Beim Abrufen wird eine Momentaufnahme des unformatierten Gamecontrollers zu einem genauen Zeitpunkt erfasst. Dieser Ansatz zum Sammeln von Eingaben eignet sich gut für die meisten Spiele, da ihre Logik in der Regel in einer deterministischen Schleife ausgeführt wird, anstatt ereignisgesteuert zu sein. Es ist in der Regel auch einfacher, Spielbefehle von Eingaben, die alle gleichzeitig gesammelt wurden, zu interpretieren, als aus vielen einzelnen Eingaben, die im Laufe der Zeit gesammelt wurden.

Sie rufen einen unformatierten Gamecontroller ab, indem Sie RawGameController.GetCurrentReading aufrufen. Diese Funktion füllt Arrays für Schaltflächen, Schalter und Achsen auf, die den Zustand des unformatierten Gamecontrollers enthalten.

Im folgenden Beispiel wird ein unformatierter Gamecontroller für den aktuellen Zustand abgerufen:

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

Es gibt keine Garantie dafür, welche Position in jedem Array den Eingabewert unter verschiedenen Typen von Controllern enthält, sodass Sie überprüfen müssen, welche Eingabe die Methoden RawGameController.GetButtonLabel und RawGameController.GetSwitchKind verwendet.

GetButtonLabel informiert Sie über den Text oder das Symbol, der auf der physischen Schaltfläche gedruckt wird, und nicht die Funktion der Schaltfläche. Daher wird es am besten als Hilfe für die Benutzeroberfläche für Fälle verwendet, in denen Sie dem Spieler Hinweise geben möchten, welche Schaltflächen welche Funktionen ausführen. GetSwitchKind informiert Sie über den Typ des Schalters (d. h. wie viele Positionen es hat), aber nicht den Namen.

Es gibt keine standardisierte Möglichkeit, die Beschriftung einer Achse oder eines Schalters zu erhalten, daher müssen Sie diese selbst testen, um zu bestimmen, welche Eingabe die ist.

Wenn Sie über einen bestimmten Controller verfügen, den Sie unterstützen möchten, können Sie die RawGameController.HardwareProductId und RawGameController.HardwareVendorId abrufen und überprüfen, ob sie mit diesem Controller übereinstimmen. Die Position der einzelnen Eingaben in jedem Array ist für jeden Controller mit der gleichen HardwareProductId und HardwareVendorId identisch, sodass Sie sich keine Gedanken darüber machen müssen, dass Ihre Logik möglicherweise unter verschiedenen Controllern desselben Typs inkonsistent ist.

Zusätzlich zum unformatierten Gamecontrollerzustand gibt jeder Wert einen Zeitstempel zurück, der genau angibt, wann der Zustand abgerufen wurde. Der Zeitstempel ist nützlich, um sich auf die Anzeigedauer früherer Messwerte oder auf die Anzeigedauer der Spielsimulation zu beziehen.

Lesen der Schaltflächen und Schalter

Jeder der unformatierten Tasten des Gamecontrollers stellt einen digitalen Lesewert bereit, der angibt, ob er gedrückt (unten) oder losgelassen (nach oben) ist. Schaltflächenwerte werden als einzelne boolesche Werte in einem einzelnen Array dargestellt. Die Bezeichnung für jede Schaltfläche kann mithilfe von RawGameController.GetButtonLabel mit dem Index des booleschen Werts im Array gefunden werden. Jeder Wert wird als GameControllerButtonLabel dargestellt.

Im folgenden Beispiel wird ermittelt, ob die XboxA-Taste gedrückt wird:

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

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

Manchmal möchten Sie vielleicht bestimmen, wann eine Taste von gedrückter Taste in losgelassen übergeht oder losgelassen wird, ob mehrere Tasten gedrückt oder losgelassen werden, oder ob eine Reihe von Tasten auf eine bestimmte Weise angeordnet sind, einige gedrückt und andere nicht. Informationen zum Erkennen jeder dieser Bedingungen finden Sie unter Erkennen von Tastenübergängen und Erkennen komplexer Tastenanordnungen.

Switch-Werte werden als Array von GameControllerSwitchPosition bereitgestellt. Da es sich bei dieser Eigenschaft um ein Bitfeld handelt, wird die bitweise Maskierung verwendet, um die Richtung des Schalters zu isolieren.

Im folgenden Beispiel wird ermittelt, ob sich jeder Schalter in der Aufwärtsposition befindet:

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

Lesen der analogen Eingaben (Sticks, Trigger, Drosselungen usw.)

Eine analoge Achse stellt einen Wert zwischen 0,0 und 1,0 bereit. Dazu gehören jede Dimension auf einem Stick, z. B. X und Y für Standardsticks oder sogar X-, Y- und Z-Achsen (Roll, Pitch und Gieren) für Flugsticks.

Die Werte können analoge Trigger, Drosselungen oder andere Analogeingaben darstellen. Diese Werte werden nicht mit Bezeichnungen bereitgestellt, daher empfehlen wir, dass Ihr Code mit einer Vielzahl von Eingabegeräten getestet wird, um sicherzustellen, dass sie korrekt mit Ihren Annahmen übereinstimmen.

Bei allen Achsen beträgt der Wert etwa 0,5 für einen Stick, wenn er sich in der Mittelposition befindet, aber es ist normal, dass der genaue Wert variieren kann, auch zwischen nachfolgenden Werten; Strategien zur Milderung dieser Variation werden weiter unten in diesem Abschnitt erläutert.

Das folgende Beispiel zeigt, wie die analogen Werte von einem Xbox-Controller gelesen werden:

// 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];

Beim Lesen der Stickwerte werden Sie feststellen, dass sie nicht zuverlässig einen neutralen Lesewert von 0,5 erzeugen, wenn sie sich in der Mitte befinden; Stattdessen erzeugen sie bei jedem Verschieben des Sticks unterschiedliche Werte in der Nähe von 0,5 und kehren zur Mittelposition zurück. Zur Abmilderung dieser Variationen können Sie einen kleinen inaktiven Bereich implementieren, bei dem es sich um einen Wertebereich in der Nähe der idealen Mittelposition handelt, der ignoriert wird.

Eine Möglichkeit zum Implementieren eines Inaktiven Bereichs besteht darin, zu bestimmen, wie weit der Stick von der Mitte bewegt wurde, und die Lesewerte ignorieren, die näher sind als eine Entfernung, die Sie auswählen. Sie können die Entfernung ungefähr berechnen – es ist nicht genau, weil Stickwerte im Wesentlichen polar, nicht planar, Werte sind , nur mithilfe des Pythagorischen Theorem. Dies erzeugt einen radialen inaktiven Bereich.

Das folgende Beispiel veranschaulicht einen einfachen radialen inaktiven Bereich unter Verwendung des Satzes des Pythagoras:

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

Weitere Informationen