Inhaltsverzeichnis

  1. Einleitung
  2. Die Klasse
  3. Verwendung

Kommentare

GamePads mit DirectInput abfragen

Autor: SteveKr

^ Einleitung


Oft benötigt man für Spiele GamePad-Support. Das Problem bei XNA ist, dass es für Gamepads XINPUT nutzt, welches leider nur XBox-Controller unterstützen, weshalb andere GamePads außen vor bleiben.
Um dennoch auch "normale" GamPads abfragen zu können, kann man auf DirectInput zurückgreifen. Dazu benötigt unter .Net einen entsprechenden DirectX-Wrapper und da bieten sich entweder das nicht mehr weiterentwickelte Managed DirectX von Microsoft, oder die freie Alternative SlimDX an.

In diesem Tutorial wird SlimDX verwendet um eine kleine Klasse zu programmieren, mit der man komfortabel GamePads abfragen kann.

Downloaden kann man SlimDX auf der folgenden Seite:
http://code.google.com/p/slimdx/wiki/Downloads?tm=2
Die entsprechende Datei heißt SlimDX Installer SP1.

Nachdem wir SlimDX installiert haben öffnen oder erstellen wir ein XNA-Projekt, in dem wir die Gamepad-Abfrage integrieren wollen.
Dort fügen wir zunächst den Verweis auf SlimDX hinzu.

Hinweis: Der Code zum Abfragen des GamePads ist zum Teil dem entsprechenden SlimDX-DirectInput-Sample entnommen.

^ Die Klasse


Als Erstes erstellen wir eine neue Klasse, geben ihr den Namen GameController und fügen die folgende Using-Direktive hinzu:
using SlimDX.DirectInput;

Dann benötigen wir 2 Objekte:
public class GameController
{
    // Das GamePad
    private Joystick joystick;

    // Status des GamePads
    private JoystickState state = new JoystickState();

Damit wir das GamePad entsprechend nutzen können müssen wir zunächst DirectInput initialisieren. Das geschieht genau einmal, in der Regel zu Beginn des Spiels.
DirectInput input = new DirectInput();

Das so instanziierte DirectInput-Objekt müssen wir dann anschließend der GameController-Klasse übergeben. Dem Konstruktor übergeben zusätzlich noch wir ein Game-Objekt und die Nummer des GamePads (falls mehrere angeschlossen sind).
    public GameController(DirectInput directInput, Game game, int number)
    {
        // Geräte suchen
        var devices = directInput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly);
        if (devices.Count == 0 || devices[number] == null)
        {
            // Kein Gamepad vorhanden
            return;
        }

        // Gamepad erstellen
        joystick = new Joystick(directInput, devices[number].InstanceGuid);

        // Das GamePad soll nur reagieren, wenn sich unser Spiel(-fenster) im Vordergrund befindet
        joystick.SetCooperativeLevel(game.Window.Handle, CooperativeLevel.Exclusive | CooperativeLevel.Foreground);

        // Den Zahlenbereich der Achsen auf -1000 bis 1000 setzen
        foreach (DeviceObjectInstance deviceObject in joystick.GetObjects())
        {
            if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0)
                joystick.GetObjectPropertiesById((int)deviceObject.ObjectType).SetRange(-1000, 1000);

        }

        joystick.Acquire();
    }

In der GetState-Methode wird der aktuelle Status des GamePads abgefragt und zurückgegeben.
    public JoystickState GetState()
    {
        if (joystick.Acquire().IsFailure || joystick.Poll().IsFailure)
        {
            // Wenn das GamePad nicht erreichbar ist, leeren Status zurückgeben.
            state = new JoystickState();
            return state;
        }

        state = joystick.GetCurrentState();

        return state;
    }

Am Ende geben wir unser GamePad wieder frei.
    public void Release()
    {
        if (joystick != null)
        {
            joystick.Unacquire();
            joystick.Dispose();
        }
        joystick = null;
    }


^ Verwendung


Die Klasse ist nun fertig gestellt und kann eingesetzt werden.

Dazu fügen wir zunächst die folgende Zeile zu den Using-Direktiven hinzu. Damit können wir die JoystickState-Klasse unter dem Namen GameControllerState verwenden, wodurch wir uns später die zusätzliche Angabe des Namespaces sparen.
using GameControllerState = SlimDX.DirectInput.JoystickState;

Für jedes GamePad, das wir verwenden wollen, benötigen wir ein GameController-Objekt:
public class Game1 : Microsoft.Xna.Framework.Game
{
    DirectInput directInput;
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    GameController controller;

Dieses Erstellen wir in der Initialize-Methode und übergeben unser Game-Objekt und die Nummer des GamePads.
protected override void Initialize()
{
    directInput = new DirectInput();
    controller = new GameController(directInput, this, 0);

    base.Initialize();
}

Beim Beenden des Spiels geben wir dann unser GamePad wieder frei.
protected override void UnloadContent()
{
    controller.Release();
}

Und nun zum wohl wichtigsten Teil, dem Abfragen des GamePads. Das funktioniert in etwa so, wie wir es auch von Maus und Tastatur in XNA gewohnt sind.
protected override void Update(GameTime gameTime)
{
    // Aktuellen Status holen
    GameControllerState state = controller.GetState();

    // Wenn Knopf 1 gedrückt wird, das Spiel beenden
    if (state.GetButtons()[1])
    {
        this.Exit();
    }

    base.Update(gameTime);
}