Gerenciar ações do controle

No nível do sistema, o Android informa códigos de evento de entrada dos controles de jogos. como códigos de tecla e valores de eixo do Android. É possível receber esses códigos no jogo e valores e os convertem em ações específicas no jogo.

Quando os jogadores se conectam fisicamente ou pareiam sem fio um controle de jogo para os dispositivos Android, o sistema detecta automaticamente o controlador como um dispositivo de entrada e começa a relatar os eventos de entrada. Seu jogo pode receber esses eventos de entrada implementando os seguintes métodos de callback no seu ativo Activity ou View em foco (você deve implementar os callbacks para a Activity ou View, mas não ambos):

A abordagem recomendada é capturar os eventos do objeto View específico com que o usuário interage. Inspecione os seguintes objetos fornecidos pelos callbacks para conseguir informações sobre o tipo de evento de entrada recebido:

KeyEvent
Um objeto que descreve direcional eventos de botão direcional e gamepad. Os eventos principais são acompanhados por um key code que indica o botão específico acionado, como DPAD_DOWN ou BUTTON_A. Você pode obter o o código da tecla chamando getKeyCode() ou usando a callbacks de eventos, como onKeyDown().
MotionEvent
Um objeto que descreve entradas do joystick e do gatilho lateral movimentos. Os eventos de movimento são acompanhados por um código de ação e um conjunto de valores de eixo. O código de ação especifica a mudança de estado que ocorreu como um joystick sendo movido. Os valores do eixo descrevem a posição e outros propriedades de movimento para um controle físico específico, como AXIS_X ou AXIS_RTRIGGER. Você pode conferir o código de ação chamando getAction() e o valor do eixo chamando getAxisValue().

Esta lição se concentra em como você pode lidar com entradas dos tipos mais comuns de controles físicos (botões do gamepad, botões direcionais e joysticks) em uma tela de jogo implementando o mencionado acima View métodos de callback e processamento objetos KeyEvent e MotionEvent.

Verificar se um controle de jogo está conectado

Ao informar eventos de entrada, o Android não distingue entre os eventos originados em um dispositivo de controle que não seja de jogo e os eventos que vieram em um controle de jogo. Por exemplo, uma ação de tela touch gera uma evento AXIS_X que representa o X coordenada da superfície sensível ao toque, mas o joystick gera uma Evento AXIS_X que representa a posição X do joystick. Se seu jogo se preocupa em lidar com entradas do controlador, primeiro verifique se o evento de entrada vem de um tipo de origem relevante.

Para verificar se um dispositivo de entrada conectado é um controle de jogo, chame getSources() para obter um campo de bits combinado de tipos de origem de entrada compatíveis com esse dispositivo. Em seguida, é possível testar os seguintes campos serão definidos:

  • Um tipo de origem SOURCE_GAMEPAD indica se o dispositivo de entrada tem botões de gamepad (por exemplo, BUTTON_A). Observe que esta fonte não indica estritamente se o controle de jogo tem botões D-pad, embora a maioria dos gamepads tenha controles direcionais.
  • Um tipo de origem SOURCE_DPAD indica que o dispositivo de entrada tem botões D-pad (por exemplo, DPAD_UP).
  • Um tipo de origem de SOURCE_JOYSTICK indica que o dispositivo de entrada tem controles analógicos (por exemplo, um joystick que registra movimentos ao longo de AXIS_X e AXIS_Y).

O snippet de código a seguir mostra um método auxiliar que permite verificar se os dispositivos de entrada conectados são controles de jogo. Nesse caso, o método recupera os IDs de dispositivos para os controles de jogos. É possível associar cada dispositivo ID com um jogador no seu jogo e processar as ações do jogo para cada um dos usuários conectados de vídeo separadamente. Para saber mais sobre como oferecer suporte a vários controles de jogos conectados simultaneamente no mesmo dispositivo Android, consulte Ofereça suporte a vários controles de jogos.

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;
}

Além disso, verifique os recursos de entrada individuais compatível com um controle de jogo conectado. Isso pode ser útil, por exemplo, se você quer que o jogo use somente entradas do conjunto de controles físicos entende.

Para detectar se um código de tecla ou código de eixo específico é suportado por um use estas técnicas:

  • No Android 4.4 (API de nível 19) ou versões mais recentes, é possível determinar se um código compatível com um controle de jogo conectado chamando hasKeys(int...):
  • No Android 3.1 (nível 12 da API) ou versões mais recentes, todos os eixos disponíveis compatível com um controle de jogo conectado, chamando getMotionRanges(): Depois, em cada Objeto InputDevice.MotionRange retornado. Chame getAxis() para receber o ID do eixo.

Processar o pressionamento do botão do gamepad

A figura 1 mostra como o Android mapeia os códigos de tecla e os valores dos eixos para controles na maioria dos controles de jogos.

Figura 1. Perfil de um controle de jogo genérico.

As frases de destaque na figura referem-se ao seguinte:

Códigos de tecla comuns gerados ao pressionar botões do gamepad incluem: BUTTON_A, BUTTON_B, BUTTON_SELECT, e BUTTON_START. Algum jogo Eles também acionam o código de tecla DPAD_CENTER quando o centro da barra transversal do botão direcional é pressionado. Seu jogo pode inspecionar o código de tecla chamando getKeyCode() ou de callbacks de eventos principais, como onKeyDown(), e, se representar um evento que seja relevante para seu jogo, processe-o como um uma ação do jogo. A Tabela 1 lista as ações de jogo recomendadas para os casos mais comuns. botões do gamepad.

Tabela 1. Ações de jogo recomendadas para gamepad botões.

Ação do jogo Código da tecla do botão
Iniciar jogo no menu principal ou pausar/retomar durante o jogo BUTTON_START*
Menu de exibição BUTTON_SELECT* e KEYCODE_MENU*
Igual ao comportamento de navegação Voltar do Android descrito nos Design de navegação guia. KEYCODE_BACK
Voltar para um item anterior em um menu BUTTON_B
Confirmar a seleção ou executar a ação principal do jogo BUTTON_A e DPAD_CENTER

* Seu jogo não pode depender da presença das opções "Iniciar", "Selecionar" ou "Menu" .

Dica : considere mostrar uma tela de configuração no jogo para permitir que os usuários personalizem os próprios mapeamentos de controles de jogo para ações do jogo.

O snippet a seguir mostra como modificar onKeyDown() a associar BUTTON_A e Pressionar o botão DPAD_CENTER com uma ação de jogo.

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;
    }
}

Observação: no Android 4.2 (API de nível 17) e inferiores, o sistema trata BUTTON_A como o Android Tecla Voltar por padrão. Caso seu app seja compatível com os seguintes sistemas versões, trate BUTTON_A como jogo principal à ação. Para determinar o SDK do Android atual versão no dispositivo, consulte o Valor de Build.VERSION.SDK_INT.

Processar entradas pelo botão direcional

O botão direcional de quatro direções é um controle físico comum em muitos jogos e controladores. O Android informa que o botão direcional para cima e para baixo pressiona como AXIS_HAT_Y eventos com um intervalo de -1,0 (para cima) a 1,0 (para baixo), e o botão direcional ESQUERDO ou DIREITO pressiona como AXIS_HAT_X eventos com intervalo de -1,0 (esquerda) até 1.0 (direita).

Alguns controles informam o pressionamento do botão direcional com um código de tecla. Se o jogo se preocupa com o pressionamento do botão direcional, trate os eventos do eixo do chapéu e o botão direcional códigos de teclas como os mesmos eventos de entrada, conforme recomendado na Tabela 2.

Tabela 2. Ações de jogo padrão recomendadas para o botão direcional e os valores do eixo do chapéu.

Ação do jogo Código do botão direcional Código do botão do ângulo de visão
Mover para cima KEYCODE_DPAD_UP AXIS_HAT_Y (para valores de 0 a -1,0)
Mover para baixo KEYCODE_DPAD_DOWN AXIS_HAT_Y (para valores de 0 a 1,0)
Mover para a esquerda KEYCODE_DPAD_LEFT AXIS_HAT_X (para valores de 0 a -1,0)
Mover para a direita KEYCODE_DPAD_RIGHT AXIS_HAT_X (para valores de 0 a 1,0)

O snippet de código a seguir mostra uma classe auxiliar que permite verificar o chapéu eixo e valores de código de tecla de um evento de entrada para determinar a direção do botão direcional.

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;
         }
     }
}

Use essa classe auxiliar no jogo sempre que quiser processar usando o botão direcional (por exemplo, no onGenericMotionEvent() ou onKeyDown() ).

Exemplo:

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.
    ...
}

Processar movimentos do joystick

Quando os jogadores movem um joystick nos controles, o Android relata um MotionEvent que contém o O código de ação ACTION_MOVE e a versão atualizada posições dos eixos do joystick. Seu jogo pode usar os dados fornecidos pelo o MotionEvent para determinar se um movimento do joystick se importa com o que aconteceu.

Observe que os eventos de movimento do joystick podem agrupar várias amostras de movimento. em um único objeto. O objeto MotionEvent contém a posição atual de cada eixo de joystick, bem como vários valores históricos para cada eixo. Ao relatar eventos de movimento com o código de ação ACTION_MOVE (como movimentos do joystick), o Android agrupa o valores de eixo para eficiência. Os valores históricos de um eixo consistem nos conjunto de valores distintos mais antigos que o valor do eixo atual e mais recentes informados em eventos de movimento anteriores. Consulte a Referência de MotionEvent para mais detalhes.

Use as informações históricas para renderizar um jogo com mais precisão movimento do objeto com base na entrada do joystick. Para recuperar os valores atuais e históricos, chamar getAxisValue() ou getHistoricalAxisValue(). Também é possível encontrar o número de impressões históricas no evento de joystick, chamando getHistorySize():

O snippet a seguir mostra como modificar Callback onGenericMotionEvent() para processar a entrada do joystick. Primeiro, você deve processar os valores históricos de um eixo e, em seguida, processar sua posição atual.

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);
    }
}

Antes de usar a entrada do joystick, é necessário determinar se ele está ao centro e calcular os movimentos do eixo de maneira correspondente. Normalmente, os joysticks ter uma área plana, ou seja, um intervalo de valores próximo à coordenada (0,0) no qual o eixo é considerado centralizado. Se o valor do eixo relatado por O Android está dentro da área plana, você deve tratar o controle como em repouso, ou seja, imóvel ao longo dos dois eixos.

O snippet abaixo mostra um método auxiliar que calcula o movimento junto com cada eixo. Você invoca esse auxiliar no método processJoystickInput() descritos abaixo.

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;
}

Juntando tudo, veja como você pode processar os movimentos do joystick seu jogo:

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
}

Para oferecer suporte a controles de jogos mais sofisticados recursos além de um único joystick, siga estas práticas recomendadas:

  • Gerencie dois controles direcionais analógicos. Muitos controles de jogo têm um joystick esquerdo e direito. Para o direcional analógico esquerdo, o Android Informa movimentos horizontais como eventos AXIS_X e movimentos verticais como eventos AXIS_Y. Para o direcional analógico direito, o Android relata movimentos horizontais como AXIS_Z eventos e movimentos verticais como AXIS_RZ. Certifique-se de lidar que os dois controles se fixam no seu código.
  • Lidar com o pressionamento dos gatilhos superiores (mas fornecer entradas alternativas) métodos). Alguns controles têm os ombros esquerdo e direito gatilhos. Se esses gatilhos estiverem presentes, o Android vai informar que um pressionamento do gatilho esquerdo como um evento AXIS_LTRIGGER, pressionar o gatilho direito como AXIS_RTRIGGER. No Android 4.3 (API de nível 18), um controlador que produz AXIS_LTRIGGER também informa um um valor idêntico para o eixo AXIS_BRAKE. A o mesmo vale para AXIS_RTRIGGER e AXIS_GAS. O Android informa todos os acionadores analógicos pressiona com um valor normalizado de 0,0 (liberado) a 1,0 (totalmente pressionado). Não todos os controles têm gatilhos, então considere permitir que os jogadores façam isso ações do jogo com outros botões.