Controller haben zwei Arten von Aktionen:
KeyEventfür jede Taste mit einem binären Status „Ein“ und „Aus“MotionEventfür jede Achse, die einen Wertebereich zurückgibt z. B. -1 bis 1 für Analog-Sticks oder 0 bis 1 für analoge Trigger
Sie können diese Eingaben aus der View lesen, die focus hat.
onGenericMotionEventwird für jedesMotionEventausgelöst.onKeyDownundonKeyUpwerden fürKeyEventausgelöst, wenn Tasten gedrückt und losgelassen werden.
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.isFromSource(SOURCE_GAMEPAD)
&& event.repeatCount == 0
) {
Log.d("GameView", "Gamepad key pressed: $keyCode")
return true
}
return super.onKeyDown(keyCode, event)
}
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
if (event.isFromSource(SOURCE_JOYSTICK)) {
Log.d("GameView", "Gamepad event: $event")
return true
}
return super.onGenericMotionEvent(event)
}
Java
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.isFromSource(SOURCE_GAMEPAD)
&& event.getRepeatCount() == 0
) {
Log.d("GameView", "Gamepad key pressed: " + keyCode);
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (event.isFromSource(SOURCE_JOYSTICK)) {
Log.d("GameView", "Gamepad event: " + event);
return true;
}
return super.onGenericMotionEvent(event);
}
Bei Bedarf können Sie Ereignisse stattdessen direkt aus dem Activity lesen.
dispatchGenericMotionEventwird für jedesMotionEventausgelöst.dispatchKeyEvent. wird für jedesKeyEventausgelöst.
Prüfen, ob ein Gamecontroller verbunden ist
Beim Melden von Eingabeereignissen verwendet Android dieselben Schlüssel- oder Achsen-IDs für verschiedene Eingabegerätetypen. Beispielsweise generiert eine Touchscreen-Aktion ein
AXIS_X-Ereignis, das die X
-Koordinate der Touch-Oberfläche darstellt. Ein Gamepad generiert jedoch ein
AXIS_X-Ereignis, das die X
-Position des linken Sticks darstellt. Das bedeutet, dass Sie den Quelltyp prüfen müssen, um Eingabeereignisse richtig zu interpretieren.
Verwenden Sie die
supportsSource(int) Funktion, um zu prüfen, ob ein verbundenes InputDevice ein Gamecontroller ist:
- Ein Quelltyp von
SOURCE_GAMEPADgibt an, dass das Eingabegerät Controller-Tasten hat (z. B.KEYCODE_BUTTON_A). Beachten Sie , dass dieser Quelltyp nicht unbedingt angibt, ob der Gamecontroller Steuerkreuz-Tasten hat, obwohl die meisten Controller in der Regel Richtungstasten haben. - Ein Quelltyp von
SOURCE_DPADgibt an, dass das Eingabegerät Steuerkreuz-Tasten hat (z. B.DPAD_UP). - Ein Quelltyp von
SOURCE_JOYSTICKgibt an, dass das Eingabegerät analoge Steuersticks hat (z. B. ein Joystick, der Bewegungen entlangAXIS_XundAXIS_Yerfasst).
Das folgende Code-Snippet zeigt eine Hilfsmethode, mit der Sie prüfen können, ob die verbundenen Eingabegeräte Gamecontroller sind. Wenn ja, ruft die Methode die Geräte-IDs für die Gamecontroller 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, 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 (supportsSource(SOURCE_GAMEPAD)
|| supportsSource(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);
if (dev == null) {
continue;
}
// Verify that the device has gamepad buttons, control sticks, or both.
if (dev.supportsSource(SOURCE_GAMEPAD) || dev.supportsSource(SOURCE_JOYSTICK)) {
// This device is a game controller. Store its device ID.
if (!gameControllerDeviceIds.contains(deviceId)) {
gameControllerDeviceIds.add(deviceId);
}
}
}
return gameControllerDeviceIds;
}
Controllereingaben verarbeiten
In diesem Abschnitt werden die Typen für Gamecontroller beschrieben, die unter Android unterstützt werden.
C++-Entwickler sollten die Game Controller Library verwenden. Sie vereinheitlicht alle Controller auf die gängigste Teilmenge von Funktionen und bietet eine konsistente Schnittstelle zwischen ihnen, einschließlich der Möglichkeit, das Tastenlayout zu erkennen.
Diese Abbildung zeigt, wie ein gängiger Controller unter Android für einen Android-Spieleentwickler aussehen kann.
In der Tabelle sind die Standardereignisnamen und -typen für Gamecontroller aufgeführt. Eine
vollständige Liste der Ereignisse finden Sie unter Häufige Varianten. Das System
sendet MotionEvent Ereignisse über onGenericMotionEvent und KeyEvent Ereignisse
über onKeyDown und onKeyUp.
| Controllereingabe | KeyEvent | MotionEvent |
|---|---|---|
| 1. D-Pad |
AXIS_HAT_X(horizontale Eingabe) AXIS_HAT_Y(vertikale Eingabe) |
|
| 2. Linker Analog-Stick |
KEYCODE_BUTTON_THUMBL(wenn gedrückt) |
AXIS_X(horizontale Bewegung) AXIS_Y(vertikale Bewegung) |
| 3. Rechter Analog-Stick |
KEYCODE_BUTTON_THUMBR(wenn gedrückt) |
AXIS_Z(horizontale Bewegung) AXIS_RZ(vertikale Bewegung) |
| 4. X-Taste | KEYCODE_BUTTON_X |
|
| 5. A-Taste | KEYCODE_BUTTON_A |
|
| 6. Y-Taste | KEYCODE_BUTTON_Y |
|
| 7. B-Taste | KEYCODE_BUTTON_B |
|
| 8. Rechter Bumper |
KEYCODE_BUTTON_R1 |
|
| 9. Rechter Trigger |
AXIS_RTRIGGER |
|
| 10. Linker Trigger | AXIS_LTRIGGER |
|
| 11. Linker Bumper | KEYCODE_BUTTON_L1 |
|
| 12. Starten | KEYCODE_BUTTON_START |
|
| 13. Auswählen | KEYCODE_BUTTON_SELECT |
Tastendrücke verarbeiten
Da Android das Drücken von Controller-Tasten genauso meldet wie das Drücken von Tastaturtasten, müssen Sie Folgendes tun:
- Prüfen Sie, ob das Ereignis von einem
SOURCE_GAMEPADstammt. - Achten Sie darauf, dass Sie die Taste nur einmal mit
KeyEvent.getRepeatCount(), empfangen. Android sendet wiederholte Tastendrücke genauso, als würden Sie eine Tastatur Taste gedrückt halten. - Geben Sie
truezurück, um anzugeben, dass ein Ereignis verarbeitet wurde. Übergeben Sie nicht verarbeitete Ereignisse an
super, um zu prüfen, ob die verschiedenen Kompatibilitätsebenen von Android ordnungsgemäß funktionieren.Kotlin
class GameView : View { // ... override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { event.apply { var handled = false // make sure we're handling gamepad events if (isFromSource(SOURCE_GAMEPAD)) { // avoid processing the keycode repeatedly if (repeatCount == 0) { when (keyCode) { // handle the "A" button KEYCODE_BUTTON_A -> { handled = true } } // ... } } if (handled) { return true } } return super.onKeyDown(keyCode, event) } }Java
public class GameView extends View { // ... @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; // make sure we're handling gamepad events if (event.isFromSource(SOURCE_GAMEPAD)) { // avoid processing the keycode repeatedly if (event.getRepeatCount() == 0) { switch (keyCode) { case KEYCODE_BUTTON_A: // handle the "A" button handled = true; break; // ... } } // mark this event as handled if (handled) { return true; } } // Always do this instead of "return false" // it allows Android's input compatibility layers to work return super.onKeyDown(keyCode, event); } }
Eingabe über das Steuerkreuz verarbeiten
Das 4-Wege-Steuerkreuz ist eine gängige physische Steuerung bei vielen Gamecontrollern. Android meldet das Drücken von „Nach oben“ und „Nach unten“ auf dem Steuerkreuz als AXIS_HAT_Y-Ereignisse, wobei -1,0 für „Nach oben“ und 1,0 für „Nach unten“ steht. Das Drücken von „Nach links“ oder „Nach rechts“ auf dem Steuerkreuz wird als AXIS_HAT_X-Ereignisse gemeldet, wobei -1,0 für „Nach links“ und 1,0 für „Nach rechts“ steht.
Einige Controller melden das Drücken des Steuerkreuzes stattdessen mit einem Schlüsselcode. Wenn Ihr Spiel das Drücken des Steuerkreuzes berücksichtigt, sollten Sie die Ereignisse der Hat-Achse und die Schlüsselcodes des Steuerkreuzes wie in Tabelle 2 empfohlen als dieselben Eingabeereignisse behandeln.
Tabelle 2 Empfohlene Standardspielaktionen für Schlüsselcodes des Steuerkreuzes und Werte der Hat-Achse
| Spielaktion | Schlüsselcode des Steuerkreuzes | Code der Hat-Achse |
|---|---|---|
| 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 | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (für Werte von 0 bis -1,0) |
| Nach rechts | 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 Werte der Hat-Achse und des Schlüsselcodes aus einem Eingabeereignis prüfen können, um die Richtung des Steuerkreuzes zu ermitteln.
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.
return event.isFromSource(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.
return event.isFromSource(InputDevice.SOURCE_DPAD);
}
}
Sie können diese Hilfsklasse in Ihrem Spiel überall verwenden, wo Sie Eingaben ü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 ihren Gamecontrollern bewegen, meldet Android ein
MotionEvent, das den
ACTION_MOVE Aktions
code und die aktualisierten Positionen der Achsen des Joysticks enthält. Ihr Spiel kann anhand der
Daten von MotionEvent
ermitteln, ob eine Joystickbewegung stattgefunden hat, die für das Spiel relevant ist.
Beachten Sie, dass bei Joystick-Motion-Events mehrere Bewegungsbeispiele in einem einzigen Objekt zusammengefasst werden können. Das
MotionEvent-Objekt enthält die
aktuelle Position für jede Joystickachse sowie mehrere historische Positionen
für jede Achse. Beim Melden von Bewegungsereignissen mit dem Aktionscode
ACTION_MOVE (z. B.
Joystickbewegungen) fasst Android die Achsenwerte aus Effizienzgründen zusammen. Die historischen Werte für eine Achse bestehen aus der Menge der eindeutigen Werte, die älter als der aktuelle Achsenwert und neuer als die in früheren Motion-Events gemeldeten Werte sind. Weitere Informationen finden Sie in der MotionEvent
Referenz.
Um die Bewegung eines Spielobjekts basierend auf der Joystickeingabe genau zu rendern, können Sie die historischen Informationen verwenden, die von MotionEvent-Objekten bereitgestellt werden.
Sie können aktuelle und historische Werte mit den folgenden Methoden abrufen:
getAxisValue()getHistoricalAxisValue()getHistorySize()(um die Anzahl der historischen Punkte im Joystickereignis zu ermitteln)
Das folgende Snippet zeigt, wie Sie den
onGenericMotionEvent()
Callback überschreiben können, um Joystickeingaben 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 Joystickeingaben verwenden, müssen Sie prüfen, 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 gilt. Wenn der von Android gemeldete Achsenwert in den flachen Bereich fällt, sollten Sie den Controller als im Ruhezustand befindlich behandeln (d. h. bewegungslos entlang beider Achsen).
Das Snippet zeigt eine Hilfsmethode, mit der die Bewegung entlang jeder Achse berechnet wird. Sie rufen diese Hilfsmethode in der Methode processJoystickInput() auf, die im folgenden Beispiel beschrieben wird:
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;
}
So können Sie Joystickbewegungen in Ihrem Spiel 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 anspruchsvolleren Funktionen als nur einem Joystick unterstützen möchten, sollten Sie diese Best Practices befolgen:
- Zwei 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_XEreignisse und vertikale Bewegungen alsAXIS_YEreignisse. Für den rechten Stick meldet Android horizontale Bewegungen alsAXIS_ZEreignisse und vertikale Bewegungen alsAXIS_RZEreignisse. Achten Sie darauf, dass Sie beide Controller-Sticks in Ihrem Code verarbeiten. - Drücken der Schultertrigger verarbeiten und sicherstellen, dass Ihr Spiel mit
AXIS_undKEYCODE_BUTTON_-Ereignissen funktioniert. Einige Controller haben linke und rechte Schultertrigger. Wenn diese Trigger vorhanden sind, geben sie einAXIS_*TRIGGER- oderKEYCODE_BUTTON_*2-Ereignis oder beides aus. Für den linken Trigger wären dasAXIS_LTRIGGERundKEYCODE_BUTTON_L2. Für den rechten Trigger wären dasAXIS_RTRIGGERundKEYCODE_BUTTON_R2. Achsenereignisse treten nur auf, wenn der Trigger einen Wertebereich zwischen 0 und 1 ausgibt. Einige Controller mit analoger Ausgabe 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 bevorzugen, das für Ihr Gameplay am sinnvollsten ist. Unter Android 4.3 (API-Ebene 18) und höher meldet ein Controller, der einAXIS_LTRIGGERauch einen identischen Wert für dieAXIS_BRAKEAchse. Dasselbe gilt fürAXIS_RTRIGGERundAXIS_GAS. Android meldet alle analogen Triggerdrücke mit einem normalisierten Wert von 0,0 (losgelassen) bis 1,0 (vollständig gedrückt). - Bestimmte Verhaltensweisen und Unterstützung können in emulierten Umgebungen unterschiedlich sein.
Emulierte Plattformen wie Google Play Games,
können sich je nach den Funktionen des Host
betriebssystems leicht unterscheiden. Einige Controller, die sowohl
AXIS_- als auchKEYCODE_BUTTON_-Ereignisse ausgeben, geben beispielsweise nurAXIS_-Ereignisse aus. Die Unterstützung für einige Controller ist möglicherweise gar nicht vorhanden.
Häufige Varianten
Angesichts der breiten Unterstützung von Controllern unter Android ist es möglicherweise unklar, wie Sie Ihr Spiel erstellen und testen können, um sicherzustellen, dass es bei Ihren Spielern fehlerfrei funktioniert. Trotz dieser scheinbaren Vielfalt halten sich Controllerhersteller auf der ganzen Welt in der Regel an drei verschiedene Controller-Stile. Einige bieten Hardware-Umschalter zwischen zwei oder mehr dieser Stile.
Das bedeutet, dass Sie mit nur drei Controllern in Ihrem Entwicklerteam testen können und sicher sein können, dass Ihr Spiel spielbar ist, ohne auf Zulassungs- und Sperrlisten zurückgreifen zu müssen.
Häufige Controllertypen
Die gängigsten Controller-Stile ahmen in der Regel die Layouts beliebter Spielkonsolen nach. Das gilt sowohl für die Beschriftung und das Layout der Tasten als auch für die ausgelösten Ereignisse. Bei Controllern mit Hardware-Umschaltern zwischen verschiedenen Konsolentypen ändern sich die gesendeten Ereignisse und oft sogar das logische Tastenlayout.
Beim Testen empfehlen wir, dass Sie prüfen, ob Ihr Spiel mit einem Controller in jeder der Kategorien funktioniert. Sie können mit Controllern von Erstanbietern oder beliebten Drittanbietern testen. Im Allgemeinen ordnen wir die beliebtesten Controller nach bestem Wissen und Gewissen der obigen Definition zu.
| Controllertyp | Verhaltensunterschiede | Beschriftungsvariationen |
|---|---|---|
| Controller im Xbox-Stil
Diese Controller werden in der Regel für die Microsoft Xbox- und Windows* Plattform entwickelt. |
Diese Controller entsprechen dem Feature-Set, das unter Controllereingaben verarbeiten beschrieben ist. | Die Tasten L2/R2 dieser Controller sind mit LT/RT beschriftet. |
| Controller im Switch-Stil
Diese Controller sind in der Regel für die Nintendo Switch*-Konsolenfamilie konzipiert. |
Diese Controller senden die KeyEvent
KEYCODE_BUTTON_R2
KEYCODE_BUTTON_L2
MotionEvents |
Die Tasten L2/R2 dieser Controller sind mit ZL/ZR beschriftet.
Bei diesen Controllern werden auch die Tasten A und B sowie die
Tasten X und Y vertauscht. |
| Controller im PlayStation-Stil
Diese Controller sind in der Regel für die Sony PlayStation* Familie von Konsolen konzipiert. |
Diese Controller senden MotionEvents
wie die Controller im Xbox-Stil, aber auch KeyEvents
wie die Controller im Switch-Stil, wenn sie vollständig gedrückt werden. |
Diese Controller verwenden eine andere Reihe von Symbolen für die Tasten an der Oberseite. |
* Microsoft, Xbox und Windows sind eingetragene Marken von Microsoft. Nintendo Switch ist eine eingetragene Marke von Nintendo of America Inc. PlayStation ist eine eingetragene Marke von Sony Interactive Entertainment Inc.
Trigger-Tasten unterscheiden
Einige Controller senden AXIS_LTRIGGER und AXIS_RTRIGGER, andere KEYCODE_BUTTON_L2 und KEYCODE_BUTTON_R2 und wieder andere senden alle diese Ereignisse basierend auf ihren Hardwarefunktionen. Maximieren Sie die Kompatibilität, indem Sie alle diese Ereignisse unterstützen.
Alle Controller, die AXIS_LTRIGGER senden, senden auch AXIS_BRAKE. Ähnliches gilt für AXIS_RTRIGGER und AXIS_GAS. So wird die Kompatibilität zwischen Rennlenkrädern und typischen Gamecontrollern maximiert. Im Allgemeinen verursacht das keine Probleme, aber bei Funktionen wie Bildschirmen zur Tastenbelegung sollten Sie darauf achten.
| Trigger | MotionEvent |
KeyEvent |
|---|---|---|
| Linker Trigger | AXIS_LTRIGGERAXIS_BRAKE
|
KEYCODE_BUTTON_L2
|
| Rechter Trigger | AXIS_RTRIGGERAXIS_GAS
|
KEYCODE_BUTTON_R2
|
Achten Sie darauf, dass Ihr Spiel sowohl KeyEvent als auch MotionEvent verarbeiten kann, um die Kompatibilität mit möglichst vielen Controllern aufrechtzuerhalten, und dass Ereignisse dedupliziert werden.
Unterstützte Controller
Beim Testen empfehlen wir, dass Sie prüfen, ob Ihr Spiel mit einem Controller in jeder der Kategorien funktioniert.
- Xbox-Stil
- Nintendo Switch-Stil
- PlayStation-Stil
Sie können mit Controllern von Erstanbietern oder beliebten Drittanbietern testen. Im Allgemeinen ordnen wir die beliebtesten Controller so genau wie möglich der Definition zu.