Auf Systemebene meldet Android Eingabeereigniscodes von Gamecontrollern als Android-Schlüsselcodes und Achsenwerte. In Ihrem Spiel können Sie diese Codes und Werte empfangen und in bestimmte In-Game-Aktionen umwandeln.
Wenn Spieler einen Gamecontroller physisch mit ihrem Android-Gerät verbinden oder kabellos koppeln, erkennt das System den Controller automatisch als Eingabegerät und beginnt, seine Eingabeereignisse zu melden. Ihr Spiel kann diese Eingabeereignisse empfangen, indem Sie die folgenden Rückrufmethoden in Ihrer aktiven Activity
oder fokussierten View
implementieren. Sie sollten die Rückrufe entweder für die Activity
oder die View
implementieren, aber nicht für beide:
- Von
Activity
:dispatchGenericMotionEvent(android.view. MotionEvent)
Wird aufgerufen, um allgemeine Bewegungsereignisse wie Joystickbewegungen zu verarbeiten.
dispatchKeyEvent(android.view.KeyEvent)
Wird aufgerufen, um wichtige Ereignisse wie das Drücken oder Loslassen einer Gamepad- oder Steuerkreuztaste zu verarbeiten.
- Von
View
:onGenericMotionEvent(android.view.MotionEvent)
Wird aufgerufen, um allgemeine Bewegungsereignisse wie Joystickbewegungen zu verarbeiten.
onKeyDown(int, android.view.KeyEvent)
Wird aufgerufen, um das Drücken einer physischen Taste wie eines Gamepads oder eines Steuerkreuzes zu verarbeiten.
onKeyUp(int, android.view.KeyEvent)
Wird aufgerufen, um das Loslassen einer physischen Taste wie eines Gamepads oder einer D-Pad-Taste zu verarbeiten.
Wir empfehlen, die Ereignisse für das spezifische View
-Objekt aufzuzeichnen, mit dem der Nutzer interagiert.
Prüfe die folgenden Objekte, die von den Callbacks bereitgestellt werden, um Informationen zum Typ des empfangenen Eingabeereignisses zu erhalten:
KeyEvent
- Ein Objekt, das Ereignisse für das Steuerkreuz und die Schaltflächen des Gamepads beschreibt. Schlüsselereignisse werden von einem Schlüsselcode begleitet, der die ausgelöste Schaltfläche angibt, z. B.
DPAD_DOWN
oderBUTTON_A
. Sie können den Schlüsselcode durch Aufrufen vongetKeyCode()
oder über Rückrufe für wichtige Ereignisse wieonKeyDown()
abrufen. MotionEvent
- Ein Objekt, das die Eingabe durch Bewegungen des Joysticks und des Schulterauslösers beschreibt. Bewegungsereignisse werden von einem Aktionscode und einer Reihe von Achsenwerten begleitet. Der Aktionscode gibt die aufgetretene Statusänderung an, z. B. die Bewegung eines Joysticks. Die Achsenwerte beschreiben die Position und andere Bewegungseigenschaften für ein bestimmtes physisches Steuerelement, z. B.
AXIS_X
oderAXIS_RTRIGGER
. Sie können den Aktionscode durch Aufrufen vongetAction()
und den Achsenwert durch Aufrufen vongetAxisValue()
abrufen.
In dieser Lektion erfahren Sie, wie Sie die Eingaben der gängigsten Arten von physischen Steuerelementen (Gamepad-Tasten, Richtungstasten und Joysticks) auf einem Spielbildschirm verarbeiten, indem Sie die oben genannten View
-Callback-Methoden implementieren und KeyEvent
- und MotionEvent
-Objekte verarbeiten.
Prüfen, ob ein Gamecontroller verbunden ist
Bei der Meldung von Eingabeereignissen unterscheidet Android nicht zwischen Ereignissen, die von einem Gerät ohne Gamecontroller stammen, und Ereignissen, die von einem Gamecontroller stammen. Eine Touchscreenaktion generiert beispielsweise ein AXIS_X
-Ereignis, das die X-Koordinate der Touchoberfläche darstellt, während ein Joystick ein AXIS_X
-Ereignis generiert, das die X-Position des Joysticks darstellt. Wenn in Ihrem Spiel die Eingabe über einen Gamecontroller verarbeitet werden soll, sollten Sie zuerst prüfen, ob das Eingabeereignis von einem relevanten Quelltyp stammt.
Wenn du prüfen möchtest, ob ein verbundenes Eingabegerät ein Gamecontroller ist, ruf getSources()
auf, um ein kombiniertes Bitfeld der auf diesem Gerät unterstützten Eingabequellentypen zu erhalten. Sie können dann testen, ob die folgenden Felder festgelegt sind:
- Ein Quelltyp von
SOURCE_GAMEPAD
gibt an, dass das Eingabegerät Gamepad-Tasten hat (z. B.BUTTON_A
). Dieser Quelltyp gibt nicht genau an, ob der Gamecontroller D-Pad-Tasten hat, obwohl die meisten Gamepads in der Regel Richtungssteuerelemente haben. - Ein Quelltyp von
SOURCE_DPAD
gibt an, dass das Eingabegerät D-Pad-Tasten hat (z. B.DPAD_UP
). - Ein Quelltyp von
SOURCE_JOYSTICK
weist darauf hin, dass das Eingabegerät analoge Steuerknüppel hat (z. B. einen Joystick, der Bewegungen entlang vonAXIS_X
undAXIS_Y
erfasst).
Das folgende Code-Snippet zeigt eine Hilfsmethode, mit der Sie prüfen können, ob die verbundenen Eingabegeräte Gamecontroller sind. In diesem Fall ruft die Methode die Geräte-IDs für die Gamecontroller ab. Sie können dann jede Geräte-ID einem Spieler in Ihrem Spiel zuordnen und Spielaktionen für jeden verbundenen Spieler separat verarbeiten. Weitere Informationen zur Unterstützung mehrerer Gamecontroller, die gleichzeitig mit demselben Android-Gerät verbunden sind, finden Sie unter Mehrere Gamecontroller unterstützen.
Kotlin
fun getGameControllerIds(): List<Int> { val gameControllerDeviceIds = mutableListOf<Int>() val deviceIds = InputDevice.getDeviceIds() deviceIds.forEach { deviceId -> InputDevice.getDevice(deviceId).apply { // Verify that the device has gamepad buttons, control sticks, or both. if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD || sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK) { // This device is a game controller. Store its device ID. gameControllerDeviceIds .takeIf { !it.contains(deviceId) } ?.add(deviceId) } } } return gameControllerDeviceIds }
Java
public ArrayList<Integer> getGameControllerIds() { ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>(); int[] deviceIds = InputDevice.getDeviceIds(); for (int deviceId : deviceIds) { InputDevice dev = InputDevice.getDevice(deviceId); int sources = dev.getSources(); // Verify that the device has gamepad buttons, control sticks, or both. if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { // This device is a game controller. Store its device ID. if (!gameControllerDeviceIds.contains(deviceId)) { gameControllerDeviceIds.add(deviceId); } } } return gameControllerDeviceIds; }
Außerdem können Sie auch nach einzelnen Eingabefunktionen suchen, die von einem angeschlossenen Controller unterstützt werden. Das kann beispielsweise nützlich sein, wenn Sie möchten, dass in Ihrem Spiel nur Eingaben von physischen Steuerelementen verwendet werden, die es versteht.
So prüfen Sie, ob ein bestimmter Tasten- oder Achsencode von einem verbundenen Gamecontroller unterstützt wird:
- Unter Android 4.4 (API-Level 19) oder höher können Sie mithilfe von
hasKeys(int...)
feststellen, ob ein Tastencode auf einem verbundenen Gamecontroller unterstützt wird. - Unter Android 3.1 (API-Level 12) oder höher können Sie alle verfügbaren Achsen auf einem verbundenen Gamecontroller aufrufen, indem Sie zuerst
getMotionRanges()
drücken. Rufen Sie dann für jedes zurückgegebeneInputDevice.MotionRange
-ObjektgetAxis()
auf, um die Achsen-ID abzurufen.
Gamepad-Tastendrücke verarbeiten
Abbildung 1 zeigt, wie Android Tastencodes und Achsenwerte den physischen Steuerelementen der meisten Gamecontroller zuordnet.
Die Zusatzinformationen in der Abbildung beziehen sich auf Folgendes:
Gängige Tastencodes, die durch das Drücken von Gamepad-Tasten generiert werden, sind BUTTON_A
, BUTTON_B
, BUTTON_SELECT
und BUTTON_START
. Bei einigen Gamecontrollern wird der Tastencode DPAD_CENTER
auch ausgelöst, wenn die Mitte des Steuerkreuzes gedrückt wird. Ihr Spiel kann den Schlüsselcode prüfen, indem getKeyCode()
aufgerufen wird oder über Rückrufe für Schlüsselereignisse wie onKeyDown()
. Wenn es sich um ein Ereignis handelt, das für Ihr Spiel relevant ist, wird es als Spielaktion verarbeitet. In Tabelle 1 sind die empfohlenen Spielaktionen für die gängigsten Gamepad-Tasten aufgeführt.
Spielaktion | Code für die Taste |
---|---|
Spiel im Hauptmenü starten oder während des Spiels pausieren/pausierung aufheben | BUTTON_START * |
Menü einblenden | BUTTON_SELECT *
und KEYCODE_MENU * |
Entspricht dem Verhalten der Android-Schaltfläche Zurück, das im Designleitfaden Navigation beschrieben ist. | KEYCODE_BACK |
Zurück zu einem vorherigen Menüpunkt wechseln | BUTTON_B |
Auswahl bestätigen oder primäre Spielaktion ausführen | BUTTON_A und
DPAD_CENTER |
* Ihr Spiel darf nicht von der Anwesenheit der Start-, Auswahl- oder Menütaste abhängen.
Tipp : Sie können in Ihrem Spiel einen Konfigurationsbildschirm einrichten, über den Nutzer ihre eigenen Gamecontroller-Zuordnungen für Spielaktionen anpassen können.
Im folgenden Snippet wird gezeigt, wie Sie onKeyDown()
überschreiben, um die Tastendrücke BUTTON_A
und DPAD_CENTER
mit einer Spielaktion zu verknüpfen.
Kotlin
class GameView(...) : View(...) { ... override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { var handled = false if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) { if (event.repeatCount == 0) { when (keyCode) { // Handle gamepad and D-pad button presses to navigate the ship ... else -> { keyCode.takeIf { isFireKey(it) }?.run { // Update the ship object to fire lasers ... handled = true } } } } if (handled) { return true } } return super.onKeyDown(keyCode, event) } // Here we treat Button_A and DPAD_CENTER as the primary action // keys for the game. private fun isFireKey(keyCode: Int): Boolean = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A }
Java
public class GameView extends View { ... @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { if (event.getRepeatCount() == 0) { switch (keyCode) { // Handle gamepad and D-pad button presses to // navigate the ship ... default: if (isFireKey(keyCode)) { // Update the ship object to fire lasers ... handled = true; } break; } } if (handled) { return true; } } return super.onKeyDown(keyCode, event); } private static boolean isFireKey(int keyCode) { // Here we treat Button_A and DPAD_CENTER as the primary action // keys for the game. return keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A; } }
Hinweis : Unter Android 4.2 (API-Ebene 17) und niedriger wird BUTTON_A
standardmäßig als Android-Zurück-Taste behandelt. Wenn Ihre App diese Android-Versionen unterstützt, müssen Sie BUTTON_A
als primäre Spielaktion behandeln. Die aktuelle Version des Android SDK auf dem Gerät findest du unter dem Wert Build.VERSION.SDK_INT
.
Eingaben über die Richtungstasten verarbeiten
Das Steuerkreuz ist eine gängige physische Steuerung in vielen Gamecontrollern. In Android wird das Drücken der Tasten nach oben und unten als AXIS_HAT_Y
-Ereignisse in einem Bereich von -1,0 (aufwärts) bis 1,0 (nach unten) angegeben. Beim Drücken der Tasten nach links oder rechts wird das Steuerkreuz als AXIS_HAT_X
-Ereignisse mit einem Bereich von -1,0 (links) bis 1,0 (rechts) angegeben.
Einige Controller melden D-Pad-Aktionen stattdessen mit einem Tastencode. Wenn in Ihrem Spiel die Druckbefehle des Steuerkreuzes berücksichtigt werden, sollten Sie die Ereignisse der Richtungsachse und die Tastencodes des Steuerkreuzes wie in Tabelle 2 empfohlen als Eingabeereignisse behandeln.
Spielaktion | Tastencode des Steuerkreuzes | Hat-Achsencode |
---|---|---|
Nach oben | KEYCODE_DPAD_UP |
AXIS_HAT_Y (für Werte von 0 bis -1,0) |
Nach unten | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (für Werte von 0 bis 1,0) |
Nach links bewegen | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (für Werte von 0 bis -1,0) |
Nach rechts bewegen | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (für Werte von 0 bis 1,0) |
Das folgende Code-Snippet zeigt eine Hilfsklasse, mit der Sie die Hutachse und Schlüsselcodewerte eines Eingabeereignisses prüfen können, um die Richtung des Steuerkreuzes zu bestimmen.
Kotlin
class Dpad { private var directionPressed = -1 // initialized to -1 fun getDirectionPressed(event: InputEvent): Int { if (!isDpadDevice(event)) { return -1 } // If the input event is a MotionEvent, check its hat axis values. (event as? MotionEvent)?.apply { // Use the hat axis value to find the D-pad direction val xaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_X) val yaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_Y) directionPressed = when { // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad // LEFT and RIGHT direction accordingly. xaxis.compareTo(-1.0f) == 0 -> Dpad.LEFT xaxis.compareTo(1.0f) == 0 -> Dpad.RIGHT // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad // UP and DOWN direction accordingly. yaxis.compareTo(-1.0f) == 0 -> Dpad.UP yaxis.compareTo(1.0f) == 0 -> Dpad.DOWN else -> directionPressed } } // If the input event is a KeyEvent, check its key code. (event as? KeyEvent)?.apply { // Use the key code to find the D-pad direction. directionPressed = when(event.keyCode) { KeyEvent.KEYCODE_DPAD_LEFT -> Dpad.LEFT KeyEvent.KEYCODE_DPAD_RIGHT -> Dpad.RIGHT KeyEvent.KEYCODE_DPAD_UP -> Dpad.UP KeyEvent.KEYCODE_DPAD_DOWN -> Dpad.DOWN KeyEvent.KEYCODE_DPAD_CENTER -> Dpad.CENTER else -> directionPressed } } return directionPressed } companion object { internal const val UP = 0 internal const val LEFT = 1 internal const val RIGHT = 2 internal const val DOWN = 3 internal const val CENTER = 4 fun isDpadDevice(event: InputEvent): Boolean = // Check that input comes from a device with directional pads. event.source and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD } }
Java
public class Dpad { final static int UP = 0; final static int LEFT = 1; final static int RIGHT = 2; final static int DOWN = 3; final static int CENTER = 4; int directionPressed = -1; // initialized to -1 public int getDirectionPressed(InputEvent event) { if (!isDpadDevice(event)) { return -1; } // If the input event is a MotionEvent, check its hat axis values. if (event instanceof MotionEvent) { // Use the hat axis value to find the D-pad direction MotionEvent motionEvent = (MotionEvent) event; float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X); float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y); // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad // LEFT and RIGHT direction accordingly. if (Float.compare(xaxis, -1.0f) == 0) { directionPressed = Dpad.LEFT; } else if (Float.compare(xaxis, 1.0f) == 0) { directionPressed = Dpad.RIGHT; } // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad // UP and DOWN direction accordingly. else if (Float.compare(yaxis, -1.0f) == 0) { directionPressed = Dpad.UP; } else if (Float.compare(yaxis, 1.0f) == 0) { directionPressed = Dpad.DOWN; } } // If the input event is a KeyEvent, check its key code. else if (event instanceof KeyEvent) { // Use the key code to find the D-pad direction. KeyEvent keyEvent = (KeyEvent) event; if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { directionPressed = Dpad.LEFT; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) { directionPressed = Dpad.RIGHT; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) { directionPressed = Dpad.UP; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) { directionPressed = Dpad.DOWN; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) { directionPressed = Dpad.CENTER; } } return directionPressed; } public static boolean isDpadDevice(InputEvent event) { // Check that input comes from a device with directional pads. if ((event.getSource() & InputDevice.SOURCE_DPAD) != InputDevice.SOURCE_DPAD) { return true; } else { return false; } } }
Sie können diese Hilfsklasse in Ihrem Spiel überall dort verwenden, wo Sie die Eingabe über das Steuerkreuz verarbeiten möchten, z. B. in den onGenericMotionEvent()
- oder onKeyDown()
-Callbacks.
Beispiel:
Kotlin
private val dpad = Dpad() ... override fun onGenericMotionEvent(event: MotionEvent): Boolean { if (Dpad.isDpadDevice(event)) { when (dpad.getDirectionPressed(event)) { Dpad.LEFT -> { // Do something for LEFT direction press ... return true } Dpad.RIGHT -> { // Do something for RIGHT direction press ... return true } Dpad.UP -> { // Do something for UP direction press ... return true } ... } } // Check if this event is from a joystick movement and process accordingly. ... }
Java
Dpad dpad = new Dpad(); ... @Override public boolean onGenericMotionEvent(MotionEvent event) { // Check if this event if from a D-pad and process accordingly. if (Dpad.isDpadDevice(event)) { int press = dpad.getDirectionPressed(event); switch (press) { case LEFT: // Do something for LEFT direction press ... return true; case RIGHT: // Do something for RIGHT direction press ... return true; case UP: // Do something for UP direction press ... return true; ... } } // Check if this event is from a joystick movement and process accordingly. ... }
Joystickbewegungen verarbeiten
Wenn Spieler einen Joystick auf ihrer Gamecontroller bewegen, meldet Android eine MotionEvent
, die den ACTION_MOVE
-Aktionskode und die aktualisierten Positionen der Achsen des Joysticks enthält. Ihr Spiel kann die von der MotionEvent
bereitgestellten Daten verwenden, um festzustellen, ob eine Joystickbewegung, die für das Spiel relevant ist, stattgefunden hat.
Beachten Sie, dass bei Joystick-Bewegungsereignissen mehrere Bewegungsmuster in einem einzigen Objekt zusammengefasst werden können. Das MotionEvent
-Objekt enthält die aktuelle Position für jede Joystickachse sowie mehrere bisherige Positionen für jede Achse. Wenn Bewegungsereignisse mit dem Aktionscode ACTION_MOVE
(z. B. Joystickbewegungen) erfasst werden, werden die Achsenwerte von Android aus Effizienzgründen in einem Batch gesendet. Die bisherigen Werte für eine Achse bestehen aus den einzelnen Werten, die älter als der aktuelle Achsenwert sind und jünger als die Werte, die in früheren Bewegungsereignissen erfasst wurden. Weitere Informationen finden Sie in der Referenz zu MotionEvent
.
Anhand der Verlaufsdaten können Sie die Bewegung eines Spielobjekts basierend auf der Joystickeingabe genauer rendern. Wenn Sie die aktuellen und bisherigen Werte abrufen möchten, rufen Sie getAxisValue()
oder getHistoricalAxisValue()
auf. Die Anzahl der bisherigen Punkte finden Sie auch im Joystick-Ereignis, indem Sie getHistorySize()
aufrufen.
Im folgenden Snippet wird gezeigt, wie Sie den onGenericMotionEvent()
-Callback überschreiben, um die Joystick-Eingabe zu verarbeiten. Sie sollten zuerst die bisherigen Werte für eine Achse und dann ihre aktuelle Position verarbeiten.
Kotlin
class GameView(...) : View(...) { override fun onGenericMotionEvent(event: MotionEvent): Boolean { // Check that the event came from a game controller return if (event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK && event.action == MotionEvent.ACTION_MOVE) { // Process the movements starting from the // earliest historical position in the batch (0 until event.historySize).forEach { i -> // Process the event at historical position i processJoystickInput(event, i) } // Process the current movement sample in the batch (position -1) processJoystickInput(event, -1) true } else { super.onGenericMotionEvent(event) } } }
Java
public class GameView extends View { @Override public boolean onGenericMotionEvent(MotionEvent event) { // Check that the event came from a game controller if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { // Process all historical movement samples in the batch final int historySize = event.getHistorySize(); // Process the movements starting from the // earliest historical position in the batch for (int i = 0; i < historySize; i++) { // Process the event at historical position i processJoystickInput(event, i); } // Process the current movement sample in the batch (position -1) processJoystickInput(event, -1); return true; } return super.onGenericMotionEvent(event); } }
Bevor Sie die Joystick-Eingabe verwenden, müssen Sie feststellen, ob der Joystick zentriert ist, und dann die Achsenbewegungen entsprechend berechnen. Joysticks haben in der Regel einen flachen Bereich, d. h. einen Wertebereich in der Nähe der Koordinate (0, 0), bei der die Achse als zentriert betrachtet wird. Wenn der von Android gemeldete Achsenwert in den flachen Bereich fällt, sollte der Controller im Ruhezustand sein, d. h. sich entlang beider Achsen bewegen.
Das folgende Snippet zeigt eine Hilfsmethode, mit der die Bewegung entlang jeder Achse berechnet wird. Dieser Helfer wird in der unten beschriebenen processJoystickInput()
-Methode aufgerufen.
Kotlin
private fun getCenteredAxis( event: MotionEvent, device: InputDevice, axis: Int, historyPos: Int ): Float { val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source) // A joystick at rest does not always report an absolute position of // (0,0). Use the getFlat() method to determine the range of values // bounding the joystick axis center. range?.apply { val value: Float = if (historyPos < 0) { event.getAxisValue(axis) } else { event.getHistoricalAxisValue(axis, historyPos) } // Ignore axis values that are within the 'flat' region of the // joystick axis center. if (Math.abs(value) > flat) { return value } } return 0f }
Java
private static float getCenteredAxis(MotionEvent event, InputDevice device, int axis, int historyPos) { final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource()); // A joystick at rest does not always report an absolute position of // (0,0). Use the getFlat() method to determine the range of values // bounding the joystick axis center. if (range != null) { final float flat = range.getFlat(); final float value = historyPos < 0 ? event.getAxisValue(axis): event.getHistoricalAxisValue(axis, historyPos); // Ignore axis values that are within the 'flat' region of the // joystick axis center. if (Math.abs(value) > flat) { return value; } } return 0; }
Zusammenfassend können Sie Joystickbewegungen in Ihrem Spiel so verarbeiten:
Kotlin
private fun processJoystickInput(event: MotionEvent, historyPos: Int) { val inputDevice = event.device // Calculate the horizontal distance to move by // using the input value from one of these physical controls: // the left control stick, hat axis, or the right control stick. var x: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos) if (x == 0f) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos) } if (x == 0f) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos) } // Calculate the vertical distance to move by // using the input value from one of these physical controls: // the left control stick, hat switch, or the right control stick. var y: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos) if (y == 0f) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos) } if (y == 0f) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos) } // Update the ship object based on the new x and y values }
Java
private void processJoystickInput(MotionEvent event, int historyPos) { InputDevice inputDevice = event.getDevice(); // Calculate the horizontal distance to move by // using the input value from one of these physical controls: // the left control stick, hat axis, or the right control stick. float x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos); if (x == 0) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos); } if (x == 0) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos); } // Calculate the vertical distance to move by // using the input value from one of these physical controls: // the left control stick, hat switch, or the right control stick. float y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos); if (y == 0) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos); } if (y == 0) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos); } // Update the ship object based on the new x and y values }
Wenn Sie Gamecontroller mit komplexeren Funktionen als einem einzelnen Joystick unterstützen möchten, beachten Sie die folgenden Best Practices:
- Dual-Controller-Sticks verarbeiten Viele Gamecontroller haben sowohl einen linken als auch einen rechten Joystick. Für den linken Stick meldet Android horizontale Bewegungen als
AXIS_X
-Ereignisse und vertikale Bewegungen alsAXIS_Y
-Ereignisse. Für den rechten Stick meldet Android horizontale Bewegungen alsAXIS_Z
-Ereignisse und vertikale Bewegungen alsAXIS_RZ
-Ereignisse. Achten Sie darauf, in Ihrem Code beide Controllersticks zu verarbeiten. -
Geben Sie eine Reaktion auf das Drücken des Schulter-Triggers aus und achten Sie darauf, dass Ihr Spiel mit den Ereignissen
AXIS_
undKEYCODE_BUTTON_
funktioniert. Einige Controller haben Auslöser für die linke und rechte Schulter. Wenn diese Trigger vorhanden sind, wird einAXIS_*TRIGGER
- oderKEYCODE_BUTTON_*2
-Ereignis oder beides gesendet. Für den linken Trigger wären dasAXIS_LTRIGGER
undKEYCODE_BUTTON_L2
. Für den rechten Abzug wären dasAXIS_RTRIGGER
undKEYCODE_BUTTON_R2
. Achsenereignisse treten nur auf, wenn der Trigger einen Wertebereich zwischen 0 und 1 ausgibt. Einige Controller mit analogem Ausgang geben zusätzlich zu Achsenereignissen auch Tastenereignisse aus. Spiele müssen sowohlAXIS_
- als auchKEYCODE_BUTTON_
-Ereignisse unterstützen, um mit allen gängigen Gamecontrollern kompatibel zu bleiben. Wenn ein Controller beide meldet, sollten Sie jedoch das Ereignis verwenden, das für Ihr Gameplay am sinnvollsten ist. Unter Android 4.3 (API-Ebene 18) und höher meldet ein Controller, der eineAXIS_LTRIGGER
erzeugt, auch einen identischen Wert für dieAXIS_BRAKE
-Achse. Dasselbe gilt fürAXIS_RTRIGGER
undAXIS_GAS
. Android meldet alle analogen Auslöserdrücke mit einem normalisierten Wert von 0,0 (losgelassen) bis 1,0 (vollständig gedrückt). -
Das Verhalten und die Unterstützung können in emulierten Umgebungen variieren. Emulierte Plattformen wie Google Play Spiele können sich je nach den Funktionen des Host-Betriebssystems leicht unterscheiden. Einige Controller, die sowohl
AXIS_
- als auchKEYCODE_BUTTON_
-Ereignisse senden, senden beispielsweise nurAXIS_
-Ereignisse. Für einige Controller fehlt die Unterstützung möglicherweise vollständig.