Carbon Controller Library

Category: 

LibGDX bietet bereits eine eigene Library für Controller Support an, jedoch hat man sehr schnell Probleme mit den verschiedenen Mappings. So hat die A-Taste eines XBox 360 Controllers einen anderen Code als der eines Ipega Controllers. Wie man bei dem Ipega Controller sieht, unterscheiden sich diese Codes sogar innerhalb des gleichen Controllers, wenn dieser auf einem anderen Betriebssystem genutzt wird. Außerdem sind diese arbiträren Tastencodes schwer zu merken.
Um diese verschiedenen Probleme zu lösen, habe ich die CarbonController Library entwickelt. Durch diese werden sämtliche Tasten und Achsen der verschiedenen Controller einheitlich angesteuert.

Für genauere Information: Projekt Wiki
Download: carbon-controller-1.0.jar

Anwendung

Grundsätzlich wird diese Bibliothek genauso benutzt wie gdx-controllers. Der Unterschied besteht darin, dass alle Tasten und Achsen uniform behandelt werden.

//mit gdx-controllers:
xbox.getButton(0); // untere Taste (A)
ouya.getButton(96); // untere Taste (O)
//mit CarbonControllers
controller.getButton(CarbonKey.A); // auf jedem Controller die untere Taste (A auf XBox, O auf Ouya, etc.)

Wie man sieht, muss man sich nun nicht mehr manuell darum kümmern, dass die richtigen Mappings benutzt werden.

CarbonController benötigt die gdx-controller Bibliothek.

Controller aufzählen

Um alle angeschlossenen Controller aufzulisten, kann folgender Code verwendet werden:

for(CarbonController controller : CarbonControllers.getControllers()) {
  Gdx.app.log(TAG, controller.getName());
}

Alle Methoden müssen vom Rendering Thread ausgeführt werden, ebenso wie die Methoden des LibGDX Controllers.

Controller Status abfragen

Sobald man eine Instanz eines CarbonController hat, kann man den aktuellen Zustand einer jeden Komponente abfragen. Dabei gilt es zu beachten, dass die Komponenten etwas anders sind als die der LibGDX controller. Insbesondere werden sie nicht nur durch arbiträre Integer abgefragt, sondern durch Enumerationen.

  • CarbonKey: Die typischen Tasten, benannt nach den Tasten eines XBox 360 Controllers, also A, B, X, Y, ...
  • CarbonAxis: Typischerweise Achsen und Trigger. Die Trigger liegen dabei im Bereich [0, 1] und alle anderen Achsen im Bereich [-1, 1].
  • ein einzelner POV: bietet diskrete Richtungsangaben (north, south, etc. )
  • CarbonVector: Bewegungssensoren, wie etwa Beschleunigung oder Orientierung. Wird von den meisten Controllern nicht unterstützt.

Den Status einer Komponente abzufragen ist genauso einfach wie bei einem gdx-Controller. Durch die Enumerationen jedoch direkt ersichtlich welche Taste/Achse abgefragt wird:

boolean buttonPressed = controller.getButton(CarbonKey.A);
float axis = controller.getAxis(CarbonAxis.LX);
PovDirection pov = controller.getPov();
Vector3 acc = controller.getVector(CarbonVector.ACCELEROMETER);

Event basierte Eingabe

Beim polling kann es passieren, dass man einzelne Eingaben nicht mitbekommt. Außerdem ist eine eventbasierte Eingabe unter Umständen auch geeigneter als polling. Listener können sowohl global (für alle Controller), als auch einzeln an bestimmte Controller registriert werden. Das zu implementierende Interface sieht wie folgt aus:

public interface CarbonControllerListener {
  public void connected(CarbonController controller);
  public void disconnected(CarbonController controller);
  public boolean buttonDown(CarbonController controller, CarbonKey key);
  public boolean buttonUp(CarbonController controller, CarbonKey key);
  public boolean axisMoved(CarbonController controller, CarbonAxis axis, float value);
  public boolean povMoved(CarbonController controller, PovDirection value);
  public boolean vectorChanged(CarbonController controller, CarbonVector vector, Vector3 newVector);
}

Jede Methode erhält den Controller, der das Ereignis auslöste, als Parameter. Die ersten beiden Methoden werden aufgerufen, wenn ein Controller angeschlossen oder entfernt wird. Leider funktionieren diese Methoden jedoch nur auf Android. Alle anderen Methoden sollten soweit selbsterklärend sein.

Um die Events eines bestimmten Controllers zu erhalten, kann man einen Listener an diesen anhängen. Falls man sich für die Events aller Controller interessiert, so kann man den Listener auch global registrieren.

controller.addListener(listener); // Events dieses einen Controllers erhalten
Controllers.addListener(listener); // Events aller Controller erhalten

Wenn man nur wenige dieser Methoden überschreiben will, so kann man auch von der ControllerListenerAdapter erben.
Einige der Methoden geben einen boolean zurück. Dies ist von Bedeutung, wenn mehrere Listener an einem Controller angeschlossen sind. Falls solch eine Methode false zurückgibt, so wird das Event weiter an den nächsten Listener gereicht. Wenn jedoch true zurückgegeben wird, so das Event nicht mehr weitergereicht.