Os controles têm dois tipos de ações:
KeyEvent, usado para qualquer botão com um estado binário de "ativado" e "desativado".MotionEvent, usado para qualquer eixo que retorne um intervalo de valores. Por exemplo, de -1 a 1 para controles analógicos ou de 0 a 1 para gatilhos analógicos.
Você pode 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, você pode ler eventos diretamente do Activity.
dispatchGenericMotionEventé gerado para qualquerMotionEventdispatchKeyEvent. é gerado para qualquerKeyEvent.
Verificar se um controle de jogo está conectado
Ao informar eventos de entrada, o Android reutiliza os mesmos IDs de tecla ou eixo para diferentes tipos de dispositivos de entrada. Por exemplo, uma ação em uma tela sensível ao toque gera um
AXIS_X evento que representa a coordenada X
da superfície sensível ao toque, mas um gamepad gera um
AXIS_X evento que representa a posição X
do controle analógico 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
supportsSource(int) função:
- Um tipo de origem de
SOURCE_GAMEPADindica que o dispositivo de entrada tem botões de controle (por exemplo,KEYCODE_BUTTON_A). Observe que 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 longoAXIS_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 código de dispositivo a um jogador e processar as ações do jogo separadamente para cada jogador conectado. Para saber mais sobre a compatibilidade com vários controles de jogos que estão 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. Ela unifica todos os controles no subconjunto mais comum de recursos e fornece uma interface consistente entre eles, incluindo a capacidade de detectar o layout dos botões.
Esta figura mostra como um desenvolvedor de jogos Android pode esperar que um controle comum seja exibido no Android.
A tabela lista os nomes e tipos de eventos padrão para controles de jogos. Para uma
lista completa de eventos, consulte Variantes comuns. O sistema
envia MotionEvent eventos por onGenericMotionEvent e KeyEvent eventos
por onKeyDown e onKeyUp.
| Entrada do controle | Evento de tecla | MotionEvent |
|---|---|---|
| 1. Botão direcional |
AXIS_HAT_X(entrada horizontal) AXIS_HAT_Y(entrada vertical) |
|
| 2. Controle analógico esquerdo |
KEYCODE_BUTTON_THUMBL(quando pressionado) |
AXIS_X(movimento horizontal) AXIS_Y(movimento vertical) |
| 3. Controle 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. Botão direito |
KEYCODE_BUTTON_R1 |
|
| 9. Gatilho direito |
AXIS_RTRIGGER |
|
| 10. Gatilho esquerdo | AXIS_LTRIGGER |
|
| 11. Botão esquerdo | KEYCODE_BUTTON_L1 |
|
| 12. Iniciar | KEYCODE_BUTTON_START |
|
| 13. Selecionar | KEYCODE_BUTTON_SELECT |
Processar o pressionamento de botão
Como o Android informa o pressionamento de botões do controle de forma idêntica ao pressionamento de botões do teclado, você precisa:
- Validar se o evento está vindo de um
SOURCE_GAMEPAD. - Verifique se você só recebe o botão uma vez com
KeyEvent.getRepeatCount(), O Android envia eventos de tecla repetidos da mesma forma que se você mantivesse uma tecla do teclado pressionada. - Indique que um evento é 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 é 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 ESQUERDO ou DIREITO do botão direcional como eventos AXIS_HAT_X, com -1,0 indicando para a esquerda e 1,0 indicando para a 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 esta classe auxiliar no seu jogo sempre que quiser processar a entrada do botão direcional (por exemplo, nos
onGenericMotionEvent()
ou
onKeyDown()
callbacks).
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
ACTION_MOVE código
de ação e as posições atualizadas dos eixos do joystick. Seu jogo pode usar os
dados fornecidos por 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
MotionEvent objeto 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 MotionEvent
referência para mais detalhes.
Para renderizar com precisão o movimento de um objeto do jogo com base na entrada do joystick, você pode usar as informações históricas 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
onGenericMotionEvent()
callback 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 no exemplo 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
AXIS_Xeventos e movimentos verticais comoAXIS_Yeventos. Para o direcional analógico direito, o Android relata movimentos horizontais comoAXIS_Zeventos e movimentos verticais comoAXIS_RZeventos. Verifique se os dois controles direcionais analógicos estão sendo processados 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 de eventos de eixo. Os jogos precisam oferecer suporte a eventosAXIS_eKEYCODE_BUTTON_para permanecerem compatíveis com todos os controles de jogos comuns, mas preferem o evento que faz mais sentido para a jogabilidade se um controle informar os dois. No Android 4.3 (nível 18 da API) e mais recentes, um controle que produz umAXIS_LTRIGGERtambém informa um valor idêntico para oAXIS_BRAKEeixo. 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 ser diferentes 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 controles que emitem eventos
AXIS_eKEYCODE_BUTTON_só emitem eventosAXIS_, e o suporte para alguns controles pode estar ausente.
Variantes comuns
Com a grande variedade de suporte que o Android oferece para controles, pode não ficar claro como criar e testar para verificar se o jogo funciona sem bugs entre a base de jogadores. Descobrimos que, apesar dessa variedade aparente, os fabricantes de controles em todo o mundo tendem a aderir de forma consistente a três estilos diferentes de controle. 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 continuar confiante de que o jogo pode ser jogado sem recorrer a listas de permissão e negação.
Tipos comuns de controle
O estilo mais comum de controles tende a imitar os layouts de 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 console mudam os eventos enviados e, muitas vezes, até mesmo o layout lógico dos botões.
Ao testar, recomendamos validar se o jogo funciona com um controle em cada uma das categorias. Você pode testar com controles próprios ou fabricantes terceirizados populares. Geralmente, mapeamos os controles mais populares para a definição acima da melhor maneira possível.
| Tipo de controle | Diferenças de comportamento | Variações de rótulos |
|---|---|---|
| Controles de estilo Xbox
Esses controles são normalmente feitos para a plataforma Microsoft Xbox e Windows* . |
Esses controladores correspondem ao conjunto de atributos descrito em Processar entradas do controlador | Os botões L2/R2 nesses controles são rotulados como LT/RT. |
| Controles de estilo Switch
Esses controles são normalmente projetados para a família de consoles Nintendo Switch* . |
Esses controles 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, de modo que |
| Controles de estilo PlayStation
Esses controles são normalmente projetados para a família de consoles Sony PlayStation* . |
Esses controles enviam MotionEvents
como os controles de estilo Xbox, mas também enviam KeyEvents
como os controles de estilo Switch quando totalmente pressionados. |
Esses controles usam um conjunto diferente de glifos para 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 controles enviam AXIS_LTRIGGER e AXIS_RTRIGGER, alguns 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. Geralmente, isso não causa problemas, mas esteja ciente de recursos como telas de remapeamento de teclas.
| Gatilho | MotionEvent |
KeyEvent |
|---|---|---|
| Gatilho esquerdo | AXIS_LTRIGGERAXIS_BRAKE
|
KEYCODE_BUTTON_L2
|
| Gatilho direito | AXIS_RTRIGGERAXIS_GAS
|
KEYCODE_BUTTON_R2
|
É necessário verificar se o jogo pode processar KeyEvent e MotionEvent para manter a compatibilidade com o maior número possível de controles e se os eventos são desduplicados.
Controles compatíveis
Ao testar, recomendamos validar se o jogo funciona com um controle em cada uma das categorias.
- Estilo Xbox
- Estilo Nintendo Switch
- Estilo PlayStation
Você pode testar com controles próprios ou fabricantes terceirizados populares. Geralmente, mapeamos os controles mais populares para a definição da forma mais próxima possível.