Gérer les actions de la manette

Au niveau du système, Android signale les codes d'événement d'entrée des manettes de jeu en tant que codes de touche et valeurs d'axe Android. Dans votre jeu, vous pouvez recevoir ces codes et valeurs et les convertir en actions spécifiques.

Lorsque les joueurs se connectent physiquement ou sans fil à une manette de jeu avec leurs appareils Android, le système détecte automatiquement la manette en tant que 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 ciblé (vous devez implémenter les rappels pour Activity ou View, mais pas les deux):

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 décrivant les événements liés aux boutons d'un pavé directionnel et d'une 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 ou BUTTON_A. Vous pouvez obtenir le code de touche en appelant getKeyCode() ou à partir de rappels d'événements de touche tels que onKeyDown().
MotionEvent
Objet décrivant les mouvements du joystick et du déclencheur sur l'épaule. 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 mouvement pour une commande physique spécifique, telle que AXIS_X ou AXIS_RTRIGGER. Vous pouvez obtenir le code d'action en appelant getAction() et la valeur de l'axe en appelant getAxisValue().

Cette leçon explique comment gérer les entrées provenant des types de commandes physiques les plus courants (boutons de manette de jeu, pavés directionnelles 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

Lorsque vous signalez des événements d'entrée, Android ne fait pas la distinction entre les événements provenant d'une manette de jeu et ceux provenant d'une manette. Par exemple, une action sur l'é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 souhaite gérer les entrées de 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 périphérique d'entrée connecté est une manette de jeu, appelez getSources() afin d'obtenir un champ de bits combiné des types de sources d'entrée compatibles avec cet appareil. Vous pouvez ensuite effectuer un test pour voir si les champs suivants sont définis:

  • Le type de source SOURCE_GAMEPAD indique que le périphérique 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 pour pavé directionnel, bien que la plupart des manettes disposent généralement de commandes directionnelles.
  • Le type de source SOURCE_DPAD indique que le périphérique d'entrée dispose de boutons du pavé directionnel (par exemple, DPAD_UP).
  • Le type de source SOURCE_JOYSTICK indique que le périphérique d'entrée dispose de joysticks de commande analogiques (par exemple, un joystick qui enregistre les mouvements le long de AXIS_X et AXIS_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. Le cas échéant, la méthode récupère les ID d'appareil pour les manettes de jeu. Vous pouvez ensuite associer chaque ID d'appareil à un joueur dans votre jeu et traiter séparément les actions de chaque joueur connecté. Pour en savoir plus sur la prise en charge de plusieurs manettes de jeu connectées simultanément sur le même appareil Android, consultez 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;
}

En outre, vous pouvez 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 l'entrée 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 compatible avec une manette de jeu connectée, utilisez les techniques suivantes:

  • Sous 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...).
  • Dans 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, sur chaque objet InputDevice.MotionRange renvoyé, appelez getAxis() 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 avec les commandes physiques de la plupart des manettes de jeu.

Figure 1 : Profil d'une manette de jeu générique.

Les accroches de la figure font référence aux éléments suivants:

Les codes de touche couramment générés lorsque vous appuyez sur un bouton d'une manette de jeu sont BUTTON_A, BUTTON_B, BUTTON_SELECT et BUTTON_START. Certaines manettes de jeu déclenchent également le code de touche DPAD_CENTER lorsque l'utilisateur appuie sur le centre de la barre transversale du pavé directionnel. Votre jeu peut inspecter le code de touche 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, il peut être traité comme une action de jeu. Le tableau 1 liste les actions de jeu recommandées pour les boutons les plus courants des manettes de jeu.

Tableau 1. Actions de jeu recommandées pour les boutons des manettes de jeu.

Action de jeu Code des touches du bouton
Lancer le jeu depuis le menu principal, ou mettre en pause/réactiver en cours de jeu BUTTON_START*
Afficher le menu BUTTON_SELECT* et KEYCODE_MENU*
Identique au comportement de navigation Retour 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 reposer sur la présence des boutons "Démarrer", "Sélectionner" ou "Menu".

Conseil : Pensez à 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 dans le 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 : Sur Android 4.2 (niveau d'API 17) ou version antérieure, le système traite BUTTON_A comme touche Retour par défaut. Si votre application est compatible avec ces versions d'Android, assurez-vous de traiter BUTTON_A comme l'action principale du jeu. Pour déterminer la version actuelle du SDK Android sur l'appareil, reportez-vous à la valeur Build.VERSION.SDK_INT.

Traiter la saisie du pavé directionnel

Le pavé directionnel à quatre directions est un contrôle physique courant dans de nombreuses manettes de jeu. Android signale les appuis vers le haut et vers le bas sur le pavé directionnel comme des événements AXIS_HAT_Y compris entre -1,0 (haut) et 1,0 (bas), et les appuis vers la gauche ou la droite sur le pavé directionnel comme des événements AXIS_HAT_X avec une plage comprise entre -1,0 (gauche) et 1,0 (droite).

À la place, certains contrôleurs signalent les pressions sur le pavé directionnel avec un code de touche. Si votre jeu concerne les pressions 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.

Tableau 2. Actions de jeu par défaut recommandées pour les codes de touches du pavé directionnel et les valeurs de l'axe des chapeaux.

Action de jeu Code du clavier directionnel Code d'axe du chapeau
Monter KEYCODE_DPAD_UP AXIS_HAT_Y (pour les valeurs comprises entre 0 et -1)
Se déplacer vers le bas 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)
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 du chapeau et les valeurs de code clé à partir d'un événement d'entrée pour déterminer la direction du pavé directionnel.

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()).

Par 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 avec le 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 nouvelles positions des axes du joystick. Votre jeu peut utiliser les données fournies par MotionEvent pour déterminer si un mouvement du joystick 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 (par exemple, les mouvements du joystick), Android regroupe les valeurs des axes pour plus d'efficacité. Les valeurs historiques d'un axe sont l'ensemble des valeurs distinctes antérieures à 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 la saisie au joystick. Pour récupérer les valeurs actuelles et historiques, appelez getAxisValue() ou getHistoricalAxisValue(). Vous pouvez également trouver le nombre de points historiques dans l'événement du joystick en appelant getHistorySize().

L'extrait de code suivant montre comment remplacer le rappel onGenericMotionEvent() pour traiter la saisie via le 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 avec le joystick, vous devez déterminer s'il 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 proches 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 situe dans la zone plate, vous devez considérer le contrôleur au repos (c'est-à-dire immobile sur les deux axes).

L'extrait ci-dessous montre une méthode d'assistance qui calcule le mouvement le long de chaque axe. Vous appelez cet outil d'aide dans la méthode processJoystickInput() décrite plus loin.

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 pouvez 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 dotées de fonctionnalités plus sophistiquées au-delà d'un seul joystick, suivez ces bonnes pratiques:

  • Manipulez les doubles manettes. De nombreuses manettes de jeu disposent à la fois d'un joystick gauche et d'un joystick droit. Pour le stick gauche, Android signale les mouvements horizontaux en tant qu'événements AXIS_X et les mouvements verticaux en tant qu'événements AXIS_Y. Pour le stick droite, Android signale les mouvements horizontaux en tant qu'événements AXIS_Z et les mouvements verticaux en tant qu'événements AXIS_RZ. Veillez à gérer les deux manettes de manette dans votre code.
  • Gérer les pressions sur le déclencheur d'épaule (mais fournir d'autres méthodes de saisie). Certaines manettes sont dotées de déclencheurs au niveau de l'épaule gauche et droite. Si ces déclencheurs sont présents, Android signale une pression sur le déclencheur à gauche comme un événement AXIS_LTRIGGER et une pression sur le déclencheur droit comme un événement AXIS_RTRIGGER. Sur Android 4.3 (niveau d'API 18), un contrôleur qui génère un AXIS_LTRIGGER signale également une valeur identique pour l'axe AXIS_BRAKE. Il en va de même pour AXIS_RTRIGGER et AXIS_GAS. Android signale toutes les pressions sur des déclencheurs analogiques avec une valeur normalisée comprise entre 0.0 (publié) et 1.0 (complètement appuyé). Toutes les manettes n'ont pas de déclencheurs. Nous vous conseillons donc d'autoriser les joueurs à effectuer ces actions de jeu avec d'autres boutons.