Au niveau du système, Android signale les codes d'événement d'entrée des manettes de jeu sous la forme de codes de touche Android et de valeurs d'axe. Dans votre jeu, vous pouvez recevoir ces codes et ces valeurs, et les convertir en actions spécifiques.
Lorsque les joueurs connectent physiquement ou associent sans fil une manette de jeu à leurs appareils Android, le système la détecte automatiquement comme un périphérique d'entrée et commence à signaler ses événements d'entrée. Votre jeu peut recevoir ces événements d'entrée en implémentant les méthodes de rappel suivantes dans votre Activity
actif ou votre View
actif (vous devez implémenter les rappels pour Activity
ou View
, mais pas les deux):
- De
Activity
:dispatchGenericMotionEvent(android.view. MotionEvent)
Appelé pour traiter des événements de mouvement génériques tels que les mouvements de joystick.
dispatchKeyEvent(android.view.KeyEvent)
Appelé pour traiter les événements de touche, tels qu'un appui ou un relâchement d'un bouton de manette de jeu ou de pavé directionnel.
- De
View
:onGenericMotionEvent(android.view.MotionEvent)
Appelé pour traiter des événements de mouvement génériques tels que les mouvements de joystick.
onKeyDown(int, android.view.KeyEvent)
Appelé pour traiter l'appui sur une touche physique telle qu'un gamepad ou un bouton du pavé directionnel.
onKeyUp(int, android.view.KeyEvent)
Appelé pour traiter la libération d'une touche physique telle qu'une manette de jeu ou un bouton de croix directionnelle.
L'approche recommandée consiste à capturer les événements de l'objet View
spécifique avec lequel l'utilisateur interagit.
Inspectez les objets suivants fournis par les rappels pour obtenir des informations sur le type d'événement d'entrée reçu:
KeyEvent
- Objet qui décrit les événements de pavé directionnel et de bouton de manette de jeu. Les événements de touche sont accompagnés d'un code de touche qui indique le bouton spécifique déclenché, par exemple
DPAD_DOWN
ouBUTTON_A
. Vous pouvez obtenir le code de clé en appelantgetKeyCode()
ou à partir de rappels d'événements de clé tels queonKeyDown()
. MotionEvent
- Objet qui décrit les entrées provenant des mouvements du joystick et des boutons de déclenchement. Les événements de mouvement sont accompagnés d'un code d'action et d'un ensemble de valeurs d'axe. Le code d'action spécifie le changement d'état qui s'est produit, par exemple le déplacement d'un joystick. Les valeurs des axes décrivent la position et d'autres propriétés de déplacement pour une commande physique spécifique, comme
AXIS_X
ouAXIS_RTRIGGER
. Vous pouvez obtenir le code d'action en appelantgetAction()
et la valeur de l'axe en appelantgetAxisValue()
.
Cette leçon explique comment gérer les entrées des types de commandes physiques les plus courants (boutons de manette de jeu, pavés directionnels et joysticks) sur un écran de jeu en implémentant les méthodes de rappel View
mentionnées ci-dessus et en traitant les objets KeyEvent
et MotionEvent
.
Vérifier qu'une manette de jeu est connectée
Lors de la création de rapports sur les événements d'entrée, Android ne fait pas la distinction entre les événements provenant d'un appareil autre qu'une manette de jeu et ceux provenant d'une manette de jeu. Par exemple, une action sur un écran tactile génère un événement AXIS_X
qui représente la coordonnée X de la surface tactile, tandis qu'un joystick génère un événement AXIS_X
qui représente la position X du joystick. Si votre jeu gère l'entrée de la manette de jeu, vous devez d'abord vérifier que l'événement d'entrée provient d'un type de source approprié.
Pour vérifier qu'un appareil d'entrée connecté est une manette de jeu, appelez getSources()
pour obtenir un champ de bits combiné des types de sources d'entrée compatibles avec cet appareil. Vous pouvez ensuite effectuer un test pour vérifier si les champs suivants sont définis:
- Un type de source
SOURCE_GAMEPAD
indique que l'appareil d'entrée dispose de boutons de manette de jeu (par exemple,BUTTON_A
). Notez que ce type de source n'indique pas strictement si la manette de jeu dispose de boutons de pavé directionnel, bien que la plupart des manettes de jeu disposent généralement de commandes directionnelles. - Un type de source
SOURCE_DPAD
indique que l'appareil d'entrée dispose de boutons de croix directionnelle (par exemple,DPAD_UP
). - Un type de source
SOURCE_JOYSTICK
indique que l'appareil d'entrée dispose de joysticks analogiques (par exemple, un joystick qui enregistre les mouvements le long deAXIS_X
etAXIS_Y
).
L'extrait de code suivant montre une méthode d'assistance qui vous permet de vérifier si les périphériques d'entrée connectés sont des manettes de jeu. Si tel est le cas, la méthode récupère les ID d'appareil des manettes de jeu. Vous pouvez ensuite associer chaque ID d'appareil à un joueur dans votre jeu et traiter les actions du jeu pour chaque joueur connecté séparément. Pour savoir comment prendre en charge plusieurs manettes de jeu connectées simultanément sur le même appareil Android, consultez la section Assurer la compatibilité avec plusieurs manettes de jeu.
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; }
Vous pouvez également vérifier les fonctionnalités d'entrée individuelles compatibles avec une manette de jeu connectée. Cela peut être utile, par exemple, si vous souhaitez que votre jeu n'utilise que les entrées de l'ensemble de commandes physiques qu'il comprend.
Pour détecter si un code de touche ou un code d'axe spécifique est pris en charge par une manette de jeu connectée, utilisez les techniques suivantes:
- Dans Android 4.4 (niveau d'API 19) ou version ultérieure, vous pouvez déterminer si un code de touche est compatible avec une manette de jeu connectée en appelant
hasKeys(int...)
. - Sous Android 3.1 (niveau d'API 12) ou version ultérieure, vous pouvez trouver tous les axes disponibles compatibles avec une manette de jeu connectée en appelant d'abord
getMotionRanges()
. Ensuite, pour chaque objetInputDevice.MotionRange
renvoyé, appelezgetAxis()
pour obtenir son ID d'axe.
Traiter les pressions sur les boutons d'une manette de jeu
La figure 1 montre comment Android mappe les codes de touche et les valeurs d'axe sur les commandes physiques de la plupart des manettes de jeu.
Les légendes de la figure font référence aux éléments suivants :
Les codes de touche courants générés par l'appui sur les boutons de la manette de jeu incluent BUTTON_A
, BUTTON_B
, BUTTON_SELECT
et BUTTON_START
. Certaines manettes de jeu déclenchent également le code de touche DPAD_CENTER
lorsque vous appuyez au centre de la barre croisée du pavé directionnel. Votre jeu peut inspecter le code clé en appelant getKeyCode()
ou à partir de rappels d'événements clés tels que onKeyDown()
. S'il représente un événement pertinent pour votre jeu, le traiter en tant qu'action de jeu. Le tableau 1 liste les actions de jeu recommandées pour les boutons de manette de jeu les plus courants.
Action dans le jeu | Code de touche du bouton |
---|---|
Lancez le jeu dans le menu principal ou mettez-le en pause/reprenez sa lecture pendant le jeu | BUTTON_START * |
Afficher le menu | BUTTON_SELECT *
et KEYCODE_MENU * |
Identique au comportement de navigation vers l'arrière d'Android décrit dans le guide de conception de navigation. | KEYCODE_BACK |
Revenir à un élément précédent dans un menu | BUTTON_B |
Confirmer la sélection ou effectuer l'action principale du jeu | BUTTON_A et DPAD_CENTER |
* Votre jeu ne doit pas dépendre de la présence des boutons "Démarrer", "Sélectionner" ou "Menu".
Conseil : Envisagez de fournir un écran de configuration dans votre jeu pour permettre aux utilisateurs de personnaliser leurs propres mappages de manette de jeu pour les actions de jeu.
L'extrait de code suivant montre comment remplacer onKeyDown()
pour associer les pressions sur les boutons BUTTON_A
et DPAD_CENTER
à une action de jeu.
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; } }
Remarque : Sous Android 4.2 (niveau d'API 17) ou version antérieure, le système considère BUTTON_A
comme la touche Retour Android par défaut. Si votre application est compatible avec ces versions d'Android, veillez à traiter BUTTON_A
comme l'action de jeu principale. Pour déterminer la version actuelle du SDK Android sur l'appareil, reportez-vous à la valeur Build.VERSION.SDK_INT
.
Traiter les entrées du pavé directionnel
Le pavé directionnel à quatre sens est une commande physique courante dans de nombreuses manettes de jeu. Android signale les appuis sur les touches Haut et Bas du pavé directionnel en tant qu'événements AXIS_HAT_Y
avec une plage de -1,0 (haut) à 1,0 (bas), et les appuis sur les touches GAUCHE ou DROITE du pavé directionnel en tant qu'événements AXIS_HAT_X
avec une plage comprise entre -1,0 (gauche) et 1,0 (droite).
Certains contrôleurs signalent plutôt les pressions sur la croix directionnelle à l'aide d'un code de touche. Si votre jeu s'intéresse aux appuis sur le pavé directionnel, vous devez traiter les événements de l'axe du chapeau et les codes des touches du pavé directionnel comme les mêmes événements d'entrée, comme recommandé dans le tableau 2.
Action dans le jeu | Code des touches du pavé directionnel | Code pour l'axe du chapeau |
---|---|---|
Monter | KEYCODE_DPAD_UP |
AXIS_HAT_Y (pour les valeurs comprises entre 0 et -1,0) |
Descendre | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (pour les valeurs comprises entre 0 et 1,0) |
Déplacer à gauche | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (pour les valeurs comprises entre 0 et -1,0) |
Déplacer à droite | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (pour les valeurs comprises entre 0 et 1,0) |
L'extrait de code suivant montre une classe d'assistance qui vous permet de vérifier l'axe de la croix directionnelle et les valeurs de code de touche à partir d'un événement d'entrée pour déterminer la direction de la croix directionnelle.
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; } } }
Vous pouvez utiliser cette classe d'assistance dans votre jeu là où vous souhaitez traiter l'entrée du pavé directionnel (par exemple, dans les rappels onGenericMotionEvent()
ou onKeyDown()
).
Exemple :
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. ... }
Traiter les mouvements du joystick
Lorsque les joueurs déplacent un joystick sur leurs manettes de jeu, Android signale un MotionEvent
contenant le code d'action ACTION_MOVE
et les positions mises à jour des axes du joystick. Votre jeu peut utiliser les données fournies par MotionEvent
pour déterminer si un mouvement de joystick qui l'intéresse s'est produit.
Notez que les événements de mouvement du joystick peuvent regrouper plusieurs échantillons de mouvement dans un même objet. L'objet MotionEvent
contient la position actuelle de chaque axe du joystick, ainsi que plusieurs positions historiques pour chaque axe. Lorsque vous signalez des événements de mouvement avec le code d'action ACTION_MOVE
(tels que les mouvements de joystick), Android regroupe les valeurs d'axe pour plus d'efficacité. Les valeurs historiques d'une axe se composent de l'ensemble de valeurs distinctes plus anciennes que la valeur actuelle de l'axe et plus récentes que les valeurs signalées dans les événements de mouvement précédents. Pour en savoir plus, consultez la documentation de référence sur MotionEvent
.
Vous pouvez utiliser les informations historiques pour afficher plus précisément le mouvement d'un objet de jeu en fonction de l'entrée du joystick. Pour récupérer les valeurs actuelles et historiques, appelez getAxisValue()
ou getHistoricalAxisValue()
. Vous pouvez également trouver le nombre de points d'historique dans l'événement du joystick en appelant getHistorySize()
.
L'extrait de code suivant montre comment remplacer le rappel onGenericMotionEvent()
pour traiter l'entrée du joystick. Vous devez d'abord traiter les valeurs historiques d'un axe, puis sa position actuelle.
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); } }
Avant d'utiliser la saisie au joystick, vous devez déterminer si le joystick est centré, puis calculer ses mouvements d'axe en conséquence. Les joysticks ont généralement une zone plate, c'est-à-dire une plage de valeurs proche de la coordonnée (0,0) à laquelle l'axe est considéré comme centré. Si la valeur de l'axe indiquée par Android se trouve dans la zone plate, vous devez considérer que la manette est au repos (c'est-à-dire immobile sur les deux axes).
L'extrait de code ci-dessous montre une méthode d'assistance qui calcule le mouvement le long de chaque axe. Vous appelez cet outil auxiliaire dans la méthode processJoystickInput()
décrite plus bas.
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; }
En résumé, voici comment vous pourriez traiter les mouvements du joystick dans votre jeu:
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 }
Pour prendre en charge les manettes de jeu qui disposent de fonctionnalités plus sophistiquées qu'un seul joystick, suivez ces bonnes pratiques :
- Gérer les deux sticks de contrôleur De nombreuses manettes de jeu sont équipées d'un joystick gauche et d'un joystick droit. Pour le joystick gauche, Android signale les mouvements horizontaux en tant qu'événements
AXIS_X
et les mouvements verticaux en tant qu'événementsAXIS_Y
. Pour le stick de droite, Android signale les mouvements horizontaux en tant qu'événementsAXIS_Z
, et les mouvements verticaux en tant qu'événementsAXIS_RZ
. Veillez à gérer les deux sticks du contrôleur dans votre code. -
Gérez les pressions sur les boutons de déclenchement (et assurez-vous que votre jeu fonctionne avec les événements
AXIS_
etKEYCODE_BUTTON_
). Certains contrôleurs sont dotés de boutons de déclenchement gauche et droit. Lorsqu'ils sont présents, ils émettent un événementAXIS_*TRIGGER
ouKEYCODE_BUTTON_*2
, ou les deux. Pour la gâchette gauche, il s'agit deAXIS_LTRIGGER
etKEYCODE_BUTTON_L2
. Pour le déclencheur droit, il s'agit deAXIS_RTRIGGER
etKEYCODE_BUTTON_R2
. Les événements d'axe ne se produisent que si le déclencheur émet une plage de valeurs comprise entre 0 et 1. Certains contrôleurs avec sortie analogique émettent des événements de bouton en plus des événements d'axe. Les jeux doivent être compatibles avec les événementsAXIS_
etKEYCODE_BUTTON_
pour rester compatibles avec toutes les manettes de jeu courantes. Toutefois, préférez l'événement le plus adapté à votre jeu si une manette signale les deux. Sous Android 4.3 (niveau d'API 18) ou version ultérieure, un contrôleur qui produit unAXIS_LTRIGGER
indique également une valeur identique pour l'axeAXIS_BRAKE
. Il en va de même pourAXIS_RTRIGGER
etAXIS_GAS
. Android enregistre toutes les pressions sur le déclencheur analogique avec une valeur normalisée comprise entre 0,0 (déclencheur relâché) et 1,0 (déclencheur complètement enfoncé). -
Les comportements et la prise en charge spécifiques peuvent varier dans les environnements d'émulation. Le comportement des plates-formes émulées, telles que Google Play Jeux, peut légèrement varier en fonction des fonctionnalités du système d'exploitation hôte. Par exemple, certains contrôleurs qui émettent à la fois des événements
AXIS_
etKEYCODE_BUTTON_
n'émettent que des événementsAXIS_
, et la compatibilité avec certains contrôleurs peut être totalement absente.