Auf Systemebene meldet Android Eingabeereigniscodes von Gamecontrollern als Android-Schlüsselcodes und -Achsenwerte. In Ihrem Spiel können Sie diese Codes und Werte erhalten und in bestimmte In-Game-Aktionen umwandeln.
Wenn Spieler einen Gamecontroller physisch mit ihren Android-Geräten verbinden oder kabellos koppeln, erkennt das System den Controller automatisch als Eingabegerät und beginnt, seine Eingabeereignisse zu melden. Dein Spiel kann diese Eingabeereignisse empfangen, indem du die folgenden Callback-Methoden in den aktiven Activity
oder die fokussierte View
implementierst. Du solltest die Callbacks entweder für Activity
oder für 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 eines Gamepads oder einer Steuerkreuz-Taste 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 z. B. eines Gamepads oder einer Taste auf dem Steuerkreuz zu verarbeiten.
onKeyUp(int, android.view.KeyEvent)
Wird aufgerufen, um die Freigabe einer physischen Taste wie eines Gamepads oder einer Taste auf dem Steuerkreuz zu verarbeiten.
Es wird empfohlen, die Ereignisse aus dem spezifischen View
-Objekt zu erfassen, mit dem der Nutzer interagiert.
Untersuchen Sie die folgenden von den Callbacks bereitgestellten Objekte, um Informationen zum Typ des empfangenen Eingabeereignisses zu erhalten:
KeyEvent
- Ein Objekt, das die Richtungspads (Steuerkreuz) und Gamepad-Tastenereignisse beschreibt. Zu Schlüsselereignissen gehört ein Schlüsselcode, der die ausgelöste Schaltfläche angibt, z. B.
DPAD_DOWN
oderBUTTON_A
. Sie können den Schlüsselcode abrufen, indem SiegetKeyCode()
oder über Schlüsselereignis-Callbacks wieonKeyDown()
aufrufen. MotionEvent
- Ein Objekt, das die Eingaben über den Joystick und den Schulterauslöser beschreibt. Bewegungsereignisse werden durch einen Aktionscode und eine Reihe von Achsenwerten begleitet. Der Aktionscode gibt die Statusänderung an, z. B. wenn ein Joystick bewegt wird. Die Achsenwerte beschreiben die Position und andere Bewegungseigenschaften für eine bestimmte physische Steuerung, z. B.
AXIS_X
oderAXIS_RTRIGGER
. Um den Aktionscode zu erhalten, rufen SiegetAction()
und den Achsenwert durch Aufrufen vongetAxisValue()
auf.
In dieser Lektion erfahren Sie, wie Sie Eingaben über die gängigsten physischen Steuerelemente (Gamepad-Tasten, Richtungstasten und Joysticks) in einem Spielebildschirm verarbeiten. Dazu implementieren Sie die oben genannten Callback-Methoden View
und verarbeiten die Objekte KeyEvent
und MotionEvent
.
Prüfen, ob ein Gamecontroller verbunden ist
Beim Melden von Eingabeereignissen unterscheidet Android nicht zwischen Ereignissen, die von einem Gerät, das kein Gamecontroller ist, und Ereignissen, die von einem Gamecontroller stammen. Bei einer Touchscreen-Aktion wird beispielsweise ein AXIS_X
-Ereignis generiert, 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 die Verarbeitung von Game-Controller-Eingaben in Ihrem Spiel wichtig ist, sollten Sie zuerst prüfen, ob das Eingabeereignis von einem relevanten Quelltyp stammt.
Wenn Sie prüfen möchten, ob ein verbundenes Eingabegerät ein Gamecontroller ist, rufen Sie getSources()
auf. Dadurch erhalten Sie ein kombiniertes Bitfeld mit den auf diesem Gerät unterstützten Eingabequellentypen. Anschließend können Sie testen, ob die folgenden Felder festgelegt sind:
- Der Quelltyp
SOURCE_GAMEPAD
bedeutet, dass das Eingabegerät Gamepad-Tasten hat (z. B.BUTTON_A
). Beachte, dass dieser Quelltyp nicht genau angibt, ob der Gamecontroller Steuerkreuztasten hat, obwohl die meisten Gamepads normalerweise Richtungssteuerelemente haben. - Der Quelltyp
SOURCE_DPAD
bedeutet, dass das Eingabegerät Tasten auf dem Steuerkreuz hat, z. B.DPAD_UP
. - Der Quelltyp
SOURCE_JOYSTICK
gibt an, dass das Eingabegerät analoge Sticks hat, z. B. einen Joystick, der Bewegungen entlang vonAXIS_X
undAXIS_Y
aufzeichnet.
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 Game-Controller ab. Anschließend können Sie 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, findest du 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 einzelne Eingabefunktionen prüfen, die von einem verbundenen Gamecontroller unterstützt werden. Dies kann beispielsweise nützlich sein, wenn Ihr Spiel nur Eingaben aus der Reihe physischer Steuerelemente verwenden soll, die es versteht.
Mit den folgenden Methoden können Sie feststellen, ob ein bestimmter Schlüsselcode oder Achsencode von einem verbundenen Game-Controller unterstützt wird:
- Unter Android 4.4 (API-Level 19) und höher kannst du durch Aufrufen von
hasKeys(int...)
feststellen, ob ein Schlüsselcode auf einem verbundenen Gamecontroller unterstützt wird. - Ab Android 3.1 (API-Level 12) findest du alle verfügbaren Achsen, die auf einem verbundenen Gamecontroller unterstützt werden, indem du zuerst
getMotionRanges()
aufrufst. Rufen Sie dann für jedes zurückgegebeneInputDevice.MotionRange
-ObjektgetAxis()
auf, um die Achsen-ID abzurufen.
Tastendruck des Gamepads verarbeiten
Abbildung 1 zeigt, wie Android den physischen Steuerelementen auf den meisten Controllern Schlüsselcodes und Achsenwerte zuordnet.
![](https://developer.android.com/static/images/training/game-controller-profiles.png?authuser=6&hl=de)
Abbildung 1: Profil für einen generischen Gamecontroller
Die Zusatzinformationen in der Abbildung beziehen sich auf Folgendes:
Gängige Tastencodes, die durch Drücken der Gamepad-Taste generiert werden, sind BUTTON_A
, BUTTON_B
, BUTTON_SELECT
und BUTTON_START
. Einige Game-Controller lösen auch den Tastencode DPAD_CENTER
aus, wenn die Mitte der Querleiste des Steuerkreuzes gedrückt wird. Dein Spiel kann den Schlüsselcode prüfen, indem es getKeyCode()
oder über Schlüsselereignis-Callbacks wie onKeyDown()
aufruft. Wenn es ein für dein Spiel relevantes Ereignis repräsentiert, wird es als Spielaktion verarbeitet. In Tabelle 1 sind die empfohlenen Spielaktionen für die gängigsten Gamepad-Schaltflächen aufgeführt.
Tabelle 1 Empfohlene Spielaktionen für Gamepad-Tasten
Spiel-Action | Tastencode |
---|---|
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-Funktion Zurück, das in der Designanleitung Navigation beschrieben wird. | KEYCODE_BACK |
Zum vorherigen Element in einem Menü zurückkehren | BUTTON_B |
Auswahl bestätigen oder primäre Spielaktion ausführen | BUTTON_A und
DPAD_CENTER |
* Für dein Spiel sollte die Start-, Auswahl- oder Menütaste nicht erforderlich sein.
Tipp : Sie können in Ihrem Spiel einen Konfigurationsbildschirm bereitstellen, damit Nutzer ihre eigenen Controller-Zuordnungen für Spielaktionen personalisieren können.
Das folgende Snippet zeigt, wie Sie onKeyDown()
überschreiben können, um das Drücken der BUTTON_A
- und DPAD_CENTER
-Schaltflächen einer Spielaktion zuzuordnen.
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 behandelt das System BUTTON_A
standardmäßig als Android-Schlüssel Zurück. Wenn deine App diese Android-Versionen unterstützt, musst du BUTTON_A
als primäre Spielaktion behandeln. Die aktuelle Version des Android SDK auf dem Gerät kannst du anhand des Werts für Build.VERSION.SDK_INT
ermitteln.
Eingabe der Richtungstasten verarbeiten
Die 4-Wege-Richtungstasten (D-Pad) sind eine gängige physische Steuerung in vielen Game-Controllern. Android meldet das Drücken des Steuerkreuzes nach oben und unten als AXIS_HAT_Y
-Ereignisse mit einem Bereich von -1,0 (nach oben) bis 1,0 (nach unten) und das Drücken des Steuerkreuzes nach links oder rechts als AXIS_HAT_X
-Ereignisse mit einem Bereich von -1,0 (links) bis 1,0 (rechts).
Einige Controller melden das Drücken des Steuerkreuzes stattdessen mit einem Tastencode. Wenn für Ihr Spiel das Drücken des Steuerkreuzes wichtig ist, sollten Sie die Ereignisse für die Hut-Achse und die Tastencodes des Steuerkreuzes wie in Tabelle 2 empfohlen als dieselben Eingabeereignisse behandeln.
Tabelle 2 Empfohlene Standardspielaktionen für Tastenkombinationen und Werte der Hutachse auf dem Steuerkreuz.
Spiel-Action | Tastencode des Steuerkreuzes | Hutachsencode |
---|---|---|
Nach oben | KEYCODE_DPAD_UP |
AXIS_HAT_Y (für die Werte 0 bis -1,0) |
Nach unten | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (für die Werte 0 bis 1,0) |
Nach links bewegen | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (für die Werte 0 bis -1,0) |
Nach rechts bewegen | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (für die Werte 0 bis 1,0) |
Das folgende Code-Snippet zeigt eine Hilfsklasse, mit der Sie die Hut-Achse und die Schlüsselcodewerte eines Eingabeereignisses überprü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 überall in Ihrem Spiel verwenden, wo Sie Eingaben über das Steuerkreuz verarbeiten möchten, z. B. im onGenericMotionEvent()
- oder onKeyDown()
-Callback.
Beispiele:
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 ihren Controllern bewegen, meldet Android ein MotionEvent
, das den ACTION_MOVE
-Aktionscode und die aktualisierten Positionen der Joystick-Achsen enthält. Dein Spiel kann anhand der von MotionEvent
bereitgestellten Daten feststellen, ob eine für das Spiel wichtige Joystickbewegung stattgefunden hat.
Bewegungsereignisse des Joysticks können mehrere Bewegungsproben innerhalb eines Objekts zusammenfassen. Das MotionEvent
-Objekt enthält die aktuelle Position für jede Joystick-Achse sowie mehrere Verlaufspositionen für jede Achse. Bei der Meldung von Bewegungsereignissen mit dem Aktionscode ACTION_MOVE
(z. B. Joystickbewegungen) fasst Android die Achsenwerte aus Gründen der Effizienz zusammen. Die historischen Werte für eine Achse bestehen aus einer Reihe unterschiedlicher Werte, die älter als der aktuelle Achsenwert sind und aktueller als die Werte, die bei früheren Bewegungsereignissen gemeldet wurden. Weitere Informationen finden Sie in der MotionEvent
-Referenz.
Anhand der Verlaufsdaten können Sie die Bewegung eines Spielobjekts basierend auf der Joystickeingabe genauer rendern. Rufen Sie zum Abrufen der aktuellen und bisherigen Werte getAxisValue()
oder getHistoricalAxisValue()
auf. Die Anzahl der bisherigen Punkte im Joystick-Ereignis lässt sich auch durch Aufrufen von getHistorySize()
abrufen.
Das folgende Snippet zeigt, wie Sie den Callback onGenericMotionEvent()
überschreiben können, um die Joystickeingabe zu verarbeiten. Sie sollten zuerst die historischen 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 können, müssen Sie ermitteln, ob der Joystick zentriert ist, und dann seine Achsenbewegungen entsprechend berechnen. Joysticks haben in der Regel eine flache Fläche, also einen Wertebereich in der Nähe der Koordinate (0, 0), in der die Achse als zentriert betrachtet wird. Wenn der von Android gemeldete Achsenwert in dem flachen Bereich liegt, sollten Sie den Controller als Ruhezustand betrachten, d. h. ihn auf beiden Achsen beweglich machen.
Das folgende Snippet zeigt eine Hilfsmethode, mit der die Bewegung entlang jeder Achse berechnet wird. Sie rufen dieses Hilfsprogramm in der unten näher beschriebenen processJoystickInput()
-Methode auf.
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; }
Wenn Sie alles zusammensetzen, können Sie die Joystickbewegungen in Ihrem Spiel wie folgt 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 }
Zur Unterstützung von Controllern, die über einen einzelnen Joystick hinaus anspruchsvollere Funktionen haben, sollten Sie die folgenden Best Practices befolgen:
- Mit Dual-Controller-Sticks umgehen Viele Controller haben einen linken
und 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. Behandeln Sie beide Controller-Sticks in Ihrem Code. - Drücken von Schulter-Triggern verarbeiten (aber alternative Eingabemethoden bereitstellen). Einige Controller haben einen linken und
rechten Schulter-Trigger. Wenn diese Trigger vorhanden sind, meldet Android das Drücken des linken Triggers als
AXIS_LTRIGGER
-Ereignis und das Drücken eines rechten Triggers alsAXIS_RTRIGGER
-Ereignis. Unter Android 4.3 (API-Level 18) meldet ein Controller, der einenAXIS_LTRIGGER
erzeugt, auch einen identischen Wert für dieAXIS_BRAKE
-Achse. Dasselbe gilt fürAXIS_RTRIGGER
undAXIS_GAS
. Android meldet alle Drücken von analogen Triggern mit einem normalisierten Wert zwischen 0,0 (veröffentlicht) und 1,0 (vollständig betätigt). Nicht alle Controller haben Trigger. Erwägen Sie daher, Spielern zu erlauben, diese Spielaktionen mit anderen Schaltflächen auszuführen.