Os controladores têm dois tipos de ações:
KeyEventusado para qualquer botão com um estado binário de "ativado" e "desativado".MotionEventusado para qualquer eixo que retorne um intervalo de valores. Por exemplo, -1 a 1 para controles analógicos ou 0 a 1 para gatilhos analógicos.
É possível ler essas entradas do View que tem focus.
onGenericMotionEventé gerado para qualquerMotionEvent.onKeyDowneonKeyUpsão gerados paraKeyEventquando os botões são pressionados e liberados.
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);
}
Se necessário, leia os eventos diretamente do Activity.
dispatchGenericMotionEventé arrecadado para qualquerMotionEventdispatchKeyEvent. é gerado para qualquerKeyEvent.
Verificar se um controle de jogo está conectado
Ao informar eventos de entrada, o Android reutiliza a mesma chave ou os mesmos IDs de eixo para
diferentes tipos de dispositivos de entrada. Por exemplo, uma ação em uma tela sensível ao toque gera um evento AXIS_X que representa a coordenada X da superfície sensível ao toque, mas um gamepad gera um evento AXIS_X que representa a posição X do stick esquerdo. Isso significa que você precisa verificar o tipo de origem para interpretar corretamente os eventos de entrada.
Para verificar se um InputDevice conectado é um controle de jogo, use a função
supportsSource(int):
- Um tipo de origem de
SOURCE_GAMEPADindica que o dispositivo de entrada tem botões de controle (por exemplo,KEYCODE_BUTTON_A). Esse tipo de origem não indica estritamente se o controle de jogo tem botões direcionais, embora a maioria dos controles normalmente tenha controles direcionais. - Um tipo de origem de
SOURCE_DPADindica que o dispositivo de entrada tem botões direcionais (por exemplo,DPAD_UP). - Um tipo de origem de
SOURCE_JOYSTICKindica que o dispositivo de entrada tem controles direcionais analógicos, por exemplo, um joystick que registra movimentos ao longo deAXIS_XeAXIS_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 jogos. Em caso afirmativo, o método recupera os códigos de dispositivo dos controles de jogos. Em seguida, você pode associar cada ID de dispositivo a um jogador e processar as ações do jogo separadamente para cada jogador conectado. Para saber mais sobre compatibilidade com vários controles de jogos conectados simultaneamente no mesmo dispositivo Android, consulte Compatibilidade com 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 (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;
}
Processar entradas do controle
Esta seção descreve os tipos de controles de jogos compatíveis com o Android.
Os desenvolvedores de C++ precisam usar a biblioteca Game Controller. Ele unifica todos os controladores no subconjunto mais comum de recursos e oferece uma interface consistente entre eles, incluindo a capacidade de detectar o layout do botão.
Esta figura mostra como um desenvolvedor de jogos Android pode esperar que um controle comum seja no Android.
A tabela lista os nomes e tipos de eventos padrão para gamepads. Para ver uma
lista completa de eventos, consulte Variantes comuns. O sistema envia eventos MotionEvent por onGenericMotionEvent e eventos KeyEvent por onKeyDown e onKeyUp.
| Entrada do controlador | Evento de tecla | MotionEvent |
|---|---|---|
| 1. Botão direcional |
AXIS_HAT_X(entrada horizontal) AXIS_HAT_Y(entrada vertical) |
|
| 2. Botão analógico esquerdo |
KEYCODE_BUTTON_THUMBL(quando pressionado) |
AXIS_X(movimento horizontal) AXIS_Y(movimento vertical) |
| 3. Botão analógico direito |
KEYCODE_BUTTON_THUMBR(quando pressionado) |
AXIS_Z(movimento horizontal) AXIS_RZ(movimento vertical) |
| 4. Botão X | KEYCODE_BUTTON_X |
|
| 5. Botão A | KEYCODE_BUTTON_A |
|
| 6. Botão Y | KEYCODE_BUTTON_Y |
|
| 7. Botão B | KEYCODE_BUTTON_B |
|
| 8. Bumper direito |
KEYCODE_BUTTON_R1 |
|
| 9. Gatilho direito |
AXIS_RTRIGGER |
|
| 10. Gatilho esquerdo | AXIS_LTRIGGER |
|
| 11. Para-choque esquerdo | KEYCODE_BUTTON_L1 |
|
| 12. Iniciar | KEYCODE_BUTTON_START |
|
| 13. Selecionar | KEYCODE_BUTTON_SELECT |
Processar o pressionamento de botão
Como o Android informa os pressionamentos de botões do controle de maneira idêntica aos pressionamentos de botões do teclado, é necessário:
- Valide se o evento está vindo de um
SOURCE_GAMEPAD. - Verifique se você só recebe o botão uma vez com
KeyEvent.getRepeatCount(). O Android vai enviar eventos de tecla repetidos como se você tivesse pressionado uma tecla do teclado. - Indique que um evento foi processado retornando
true. Transmita eventos não processados para
superpara verificar se as várias camadas de compatibilidade do Android funcionam corretamente.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); } }
Processar entradas pelo botão direcional
O botão direcional de quatro vias, ou D-pad, é um controle físico comum em muitos controles de jogos. O Android informa o pressionamento dos botões direcionais PARA CIMA e PARA BAIXO como eventos AXIS_HAT_Y, com -1,0 indicando para cima e 1,0 indicando para baixo. Ele informa o pressionamento dos botões direcionais ESQUERDO ou DIREITO como eventos AXIS_HAT_X, com -1,0 indicando esquerda e 1,0 indicando direita.
Alguns controles informam o pressionamento do botão direcional com um código de tecla. Se seu jogo usar os pressionamentos do botão direcional, trate os eventos do botão do ângulo de visão e os códigos do botão direcional como os mesmos eventos de entrada, conforme recomendado na tabela 2.
Tabela 2. Ações recomendadas do jogo padrão para códigos de botão direcional e valores do botão do ângulo de visão.
| 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 os valores do botão do ângulo de visão e do 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.
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);
}
}
Você pode usar essa classe auxiliar no seu jogo sempre que quiser processar a entrada do botão direcional (por exemplo, nos callbacks
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 de jogos, o Android informa um
MotionEvent que contém o
código de ação ACTION_MOVE
e as posições atualizadas dos eixos do joystick. Seu jogo pode usar os
dados fornecidos pelo MotionEvent
para determinar se houve um movimento no joystick.
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 para cada eixo do joystick, bem como várias posições históricas
para cada eixo. Ao relatar eventos de movimento com o código de ação
ACTION_MOVE (por exemplo, movimentos do
joystick), o Android agrupa os valores dos eixos para aumentar a eficiência. Os valores históricos de um eixo consistem no conjunto de valores distintos mais antigos do que o valor do eixo atual e mais recentes do que os valores informados em qualquer evento de movimento anterior. Consulte a referência do MotionEvent para mais detalhes.
Para renderizar com precisão o movimento de um objeto do jogo com base na entrada do joystick, use as informações do histórico fornecidas por objetos MotionEvent.
É possível recuperar valores atuais e históricos usando os seguintes métodos:
getAxisValue()getHistoricalAxisValue()getHistorySize()(para encontrar o número de pontos históricos no evento do joystick)
O snippet a seguir mostra como você pode substituir o callback
onGenericMotionEvent()
para processar a entrada do joystick. Primeiro, você precisa processar os valores históricos de um eixo e, em seguida, a 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á centralizado e, em seguida, calcular os movimentos do eixo de forma adequada. Os joysticks normalmente têm 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 informado pelo Android estiver dentro da área plana, você precisará fazer com que o controle fique em repouso, isto é, imóvel ao longo dos dois eixos.
O snippet mostra um método auxiliar que calcula o movimento ao longo de cada eixo. Você invoca esse auxiliar no método processJoystickInput() descrito
mais adiante na amostra a seguir:
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 no 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 compatibilidade com controles de jogos que têm recursos mais sofisticados além de um único joystick, siga estas práticas recomendadas:
- Gerencie dois controles direcionais analógicos. Muitos controles de jogos têm um joystick esquerdo e um direito. Para o direcional analógico esquerdo, o Android relata movimentos horizontais como eventos
AXIS_Xe movimentos verticais como eventosAXIS_Y. Para o direcional analógico direito, o Android relata movimentos horizontais como eventosAXIS_Ze movimentos verticais como eventosAXIS_RZ. Certifique-se de gerenciar os dois controles direcionais analógicos no seu código. - Gerencie o pressionamento dos gatilhos superiores e verifique se o jogo funciona com eventos
AXIS_eKEYCODE_BUTTON_. Alguns controles têm gatilhos superiores nas extremidades esquerda e direita. Quando esses gatilhos estão presentes, eles emitem um eventoAXIS_*TRIGGERouKEYCODE_BUTTON_*2, ou ambos. Para o gatilho esquerdo, seriaAXIS_LTRIGGEReKEYCODE_BUTTON_L2. Para o gatilho direito, seriaAXIS_RTRIGGEReKEYCODE_BUTTON_R2. Os eventos de eixo só ocorrem se o gatilho emitir um intervalo de valores entre 0 e 1, e alguns controles com saída analógica emitem eventos de botão além dos eventos de eixo. Os jogos precisam oferecer suporte aos eventosAXIS_eKEYCODE_BUTTON_para continuar compatíveis com todos os controles de jogos comuns, mas prefira o evento que faz mais sentido para sua jogabilidade se um controle informar os dois. No Android 4.3 (API de nível 18) e versões mais recentes, um controle que produz umAXIS_LTRIGGERtambém informa um valor idêntico para o eixoAXIS_BRAKE. O mesmo vale paraAXIS_RTRIGGEReAXIS_GAS. O Android informa todos os pressionamentos de gatilhos analógicos com um valor normalizado de 0,0 (liberado) a 1,0 (totalmente pressionado). - Comportamentos e suporte específicos podem variar em ambientes emulados.
Plataformas emuladas, como o Google Play Games,
podem ter um comportamento ligeiramente diferente com base nos recursos do sistema
operacional host. Por exemplo, alguns controladores que emitem eventos
AXIS_eKEYCODE_BUTTON_só emitem eventosAXIS_, e o suporte para alguns controladores pode estar totalmente ausente.
Opções comuns
Com a grande variedade de compatibilidade do Android com controles, pode não ficar claro como criar e testar para verificar se o jogo funciona sem bugs entre os jogadores. Descobrimos que, apesar dessa variedade aparente, os fabricantes de controladores em todo o mundo tendem a aderir consistentemente a três estilos diferentes de controladores. Alguns oferecem alternâncias de hardware entre dois ou mais deles.
Isso significa que você pode testar com apenas três controles entre sua equipe de desenvolvimento e ter certeza de que o jogo pode ser jogado sem recorrer a listas de permissão e bloqueio.
Tipos de controles comuns
O estilo mais comum de controles imita os layouts dos consoles de jogos populares. Isso é estético nos rótulos e no layout dos botões e funcional pelos eventos gerados. Os controles com alternâncias de hardware entre diferentes tipos de consoles mudam os eventos enviados e, muitas vezes, até mesmo o layout lógico dos botões.
Ao testar, recomendamos que você valide se o jogo funciona com um controlador em cada uma das categorias. Você pode testar com controladores próprios ou fabricantes terceirizados conhecidos. Em geral, mapeamos os controladores mais populares para a definição acima com base no melhor esforço.
| Tipo de controlador | Diferenças comportamentais | Variações de rotulagem |
|---|---|---|
| Controles estilo Xbox
Esses são controles normalmente feitos para a plataforma Microsoft Xbox e Windows*. |
Esses controladores correspondem ao conjunto de recursos descrito em Processar entradas do controlador. | Os botões L2/R2 nesses controles são rotulados como LT/RT |
| Controladores de estilo de troca
Esses controles geralmente são projetados para a família de consoles Nintendo Switch*. |
Esses controladores enviam os KeyEvent
KEYCODE_BUTTON_R2
KEYCODE_BUTTON_L2
MotionEvents |
Os botões L2/R2 nesses controles são rotulados como ZL/ZR.
Esses controles também trocam os botões A e B e os botões X e Y. Portanto, |
| Controles estilo PlayStation
Esses controles geralmente são projetados para a família de consoles Sony PlayStation*. |
Esses controles enviam MotionEvents
como os controles estilo Xbox, mas também enviam KeyEvents
como os controles estilo Switch quando totalmente pressionados. |
Esses controles usam um conjunto diferente de glifos para os botões frontais. |
* Microsoft, Xbox e Windows são marcas registradas da Microsoft; Nintendo Switch é uma marca registrada da Nintendo of America Inc.; PlayStation é uma marca registrada da Sony Interactive Entertainment Inc.
Desambiguar botões de gatilho
Alguns controladores enviam AXIS_LTRIGGER e AXIS_RTRIGGER, outros enviam KEYCODE_BUTTON_L2 e KEYCODE_BUTTON_R2, e outros enviam todos esses eventos com base nos recursos de hardware. Maximize a compatibilidade oferecendo suporte a todos esses eventos.
Todos os controles que enviam AXIS_LTRIGGER também enviam AXIS_BRAKE, da mesma forma que AXIS_RTRIGGER e AXIS_GAS, para ajudar a maximizar a compatibilidade entre volantes de corrida e controles de jogos típicos. Em geral, isso não causa problemas, mas fique
atento a recursos como telas de remapeamento de teclas.
| Acionador | MotionEvent |
KeyEvent |
|---|---|---|
| Gatilho esquerdo | AXIS_LTRIGGERAXIS_BRAKE
|
KEYCODE_BUTTON_L2
|
| Gatilho direito | AXIS_RTRIGGERAXIS_GAS
|
KEYCODE_BUTTON_R2
|
Verifique se o jogo consegue processar KeyEvent e MotionEvent para manter a compatibilidade com o máximo de controles possível e se os eventos são duplicados.
Controles compatíveis
Ao testar, recomendamos que você valide se o jogo funciona com um controlador em cada uma das categorias.
- Estilo Xbox
- Estilo do Nintendo Switch
- Estilo PlayStation
Você pode testar com controles próprios ou fabricantes terceirizados conhecidos, e geralmente mapeamos os controles mais usados para a definição o mais próximo possível.