I controller hanno due tipi di azioni:
KeyEventutilizzato per qualsiasi pulsante con uno stato binario "on" e "off"MotionEventutilizzato per qualsiasi asse che restituisce un intervallo di valori. Ad esempio, da -1 a 1 per gli stick analogici o da 0 a 1 per i trigger analogici.
Puoi leggere questi input dal View che ha focus.
onGenericMotionEventviene raccolto per qualsiasiMotionEvent.onKeyDowneonKeyUpvengono sollevati perKeyEventquando i pulsanti vengono premuti e rilasciati.
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 necessario, puoi leggere gli eventi direttamente da Activity.
dispatchGenericMotionEventè stato raccolto per qualsiasiMotionEventdispatchKeyEvent. è stato raccolto per qualsiasiKeyEvent.
Verificare che sia collegato un controller di gioco
Quando segnala gli eventi di input, Android riutilizza gli stessi ID tasto o asse per
diversi tipi di dispositivi di input. Ad esempio, un'azione sul touchscreen genera un evento
AXIS_X che rappresenta la coordinata X
della superficie touch, mentre un gamepad genera un evento
AXIS_X che rappresenta la posizione X
dello stick sinistro. Ciò significa che devi controllare il tipo di origine per
interpretare correttamente gli eventi di input.
Per verificare che un InputDevice connesso sia un controller, utilizza la funzione
supportsSource(int):
- Un tipo di origine
SOURCE_GAMEPADindica che il dispositivo di input ha pulsanti del controller (ad esempio,KEYCODE_BUTTON_A). Tieni presente che questo tipo di origine non indica rigorosamente se il controller di gioco ha pulsanti D-pad, anche se la maggior parte dei controller in genere ha controlli direzionali. - Un tipo di origine
SOURCE_DPADindica che il dispositivo di input ha pulsanti D-pad (ad esempio,DPAD_UP). - Un tipo di origine
SOURCE_JOYSTICKindica che il dispositivo di input ha joystick di controllo analogici (ad esempio, un joystick che registra i movimenti lungoAXIS_XeAXIS_Y).
Il seguente snippet di codice mostra un metodo helper che consente di verificare se i dispositivi di input collegati sono controller di gioco. In questo caso, il metodo recupera gli ID dispositivo per i controller di gioco. Puoi quindi associare ogni ID dispositivo a un giocatore nel tuo gioco ed elaborare separatamente le azioni di gioco per ogni giocatore connesso. Per scoprire di più sul supporto di più controller di gioco collegati contemporaneamente allo stesso dispositivo Android, consulta Supportare più controller di gioco.
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;
}
Elaborare gli input del controller
Questa sezione descrive i tipi di controller di gioco supportati su Android.
Gli sviluppatori C++ devono utilizzare la libreria Game Controller. Unifica tutti i controller nel sottoinsieme più comune di funzionalità e fornisce un'interfaccia coerente tra loro, inclusa la possibilità di rilevare il layout dei pulsanti.
Questa figura mostra l'aspetto di un controller comune per uno sviluppatore di giochi per Android.
La tabella elenca i nomi e i tipi di eventi standard per i controller di gioco. Per un
elenco completo degli eventi, vedi Varianti comuni. Il sistema
invia gli eventi MotionEvent tramite onGenericMotionEvent e gli eventi KeyEvent
tramite onKeyDown e onKeyUp.
| Input del controller | KeyEvent | MotionEvent |
|---|---|---|
| 1. D-Pad |
AXIS_HAT_X(input orizzontale) AXIS_HAT_Y(input verticale) |
|
| 2. Levetta analogica sinistra |
KEYCODE_BUTTON_THUMBL(quando è premuto) |
AXIS_X(movimento orizzontale) AXIS_Y(movimento verticale) |
| 3. Levetta analogica destra |
KEYCODE_BUTTON_THUMBR(quando è premuto) |
AXIS_Z(movimento orizzontale) AXIS_RZ(movimento verticale) |
| 4. Tasto X | KEYCODE_BUTTON_X |
|
| 5. Tasto A | KEYCODE_BUTTON_A |
|
| 6. Tasto Y | KEYCODE_BUTTON_Y |
|
| 7. Tasto B | KEYCODE_BUTTON_B |
|
| 8. Dorsale destro |
KEYCODE_BUTTON_R1 |
|
| 9. Grilletto destro |
AXIS_RTRIGGER |
|
| 10. Grilletto sinistro | AXIS_LTRIGGER |
|
| 11. Pulsante dorsale sinistro | KEYCODE_BUTTON_L1 |
|
| 12. Inizia | KEYCODE_BUTTON_START |
|
| 13. Seleziona | KEYCODE_BUTTON_SELECT |
Gestire le pressioni dei pulsanti
Poiché Android segnala la pressione dei pulsanti del controller in modo identico a quella dei tasti della tastiera, devi:
- Verifica che l'evento provenga da un
SOURCE_GAMEPAD. - Assicurati di ricevere il pulsante una sola volta con
KeyEvent.getRepeatCount(), Android invierà eventi chiave ripetuti proprio come se avessi tenuto premuto un tasto della tastiera. - Indica che un evento viene gestito restituendo
true. Passa gli eventi non gestiti a
superper verificare che i vari livelli di compatibilità di Android funzionino correttamente.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); } }
Elaborare l'input del d-pad
Il pad direzionale a 4 direzioni, o D-pad, è un controllo fisico comune in molti controller di gioco. Android segnala le pressioni del D-pad SU e GIÙ come eventi AXIS_HAT_Y,
con -1.0 che indica SU e 1.0 che indica GIÙ. Registra le pressioni del D-pad SINISTRA o DESTRA
come eventi AXIS_HAT_X, con -1.0 che indica sinistra e 1.0 che indica
destra.
Alcuni controller, invece, segnalano le pressioni sul D-pad con un codice tasto. Se il tuo gioco prende in considerazione le pressioni del D-pad, devi trattare gli eventi dell'asse del cappello e i codici chiave del D-pad come gli stessi eventi di input, come consigliato nella tabella 2.
Tabella 2. Azioni di gioco predefinite consigliate per i codici dei tasti del D-pad e i valori degli assi del cappello.
| Azione di gioco | Codice tasto D-pad | Codice asse del cappello |
|---|---|---|
| Sposta su | KEYCODE_DPAD_UP |
AXIS_HAT_Y (per valori da 0 a -1,0) |
| Sposta giù | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (per valori da 0 a 1,0) |
| Sposta a sinistra | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (per valori da 0 a -1,0) |
| Sposta a destra | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (per valori da 0 a 1,0) |
Il seguente snippet di codice mostra una classe helper che consente di controllare l'asse del cappello e i valori del codice chiave di un evento di input per determinare la direzione del D-pad.
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);
}
}
Puoi utilizzare questa classe helper nel tuo gioco ovunque tu voglia elaborare l'input del D-pad (ad esempio, nei callback
onGenericMotionEvent()
o
onKeyDown()).
Ad esempio:
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.
...
}
Elaborare i movimenti del joystick
Quando i giocatori muovono un joystick sui controller di gioco, Android segnala un
MotionEvent che contiene il
ACTION_MOVE codice
di azione e le posizioni aggiornate degli assi del joystick. Il gioco può utilizzare i dati forniti da MotionEvent per determinare se si è verificato un movimento del joystick di interesse.
Tieni presente che gli eventi di movimento del joystick possono raggruppare più campioni di movimento
all'interno di un singolo oggetto. L'oggetto
MotionEvent contiene la
posizione attuale di ogni asse del joystick, nonché più posizioni storiche
per ogni asse. Quando vengono segnalati eventi di movimento con il codice azione
ACTION_MOVE (ad esempio
movimenti del joystick), Android raggruppa i valori degli assi per efficienza. I valori storici di un asse sono costituiti dall'insieme di valori distinti precedenti al valore attuale dell'asse e più recenti dei valori riportati in eventuali eventi di movimento precedenti. Per ulteriori dettagli, consulta il riferimento MotionEvent.
Per eseguire il rendering accurato del movimento di un oggetto di gioco in base all'input del joystick, puoi
utilizzare le informazioni storiche fornite dagli oggetti MotionEvent.
Puoi recuperare i valori attuali e storici utilizzando i seguenti metodi:
getAxisValue()getHistoricalAxisValue()getHistorySize()(per trovare il numero di punti storici nell'evento joystick)
Il seguente snippet mostra come potresti eseguire l'override del
callback onGenericMotionEvent() per elaborare l'input del joystick. Devi prima elaborare i valori storici
di un asse, quindi la sua posizione attuale.
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);
}
}
Prima di utilizzare l'input del joystick, devi determinare se il joystick è centrato, quindi calcolare i movimenti dell'asse di conseguenza. I joystick in genere hanno un'area piatta, ovvero un intervallo di valori vicino alla coordinata (0,0) in cui l'asse è considerato centrato. Se il valore dell'asse segnalato da Android rientra nell'area piatta, devi considerare il controller a riposo (ovvero immobile lungo entrambi gli assi).
Lo snippet mostra un metodo helper che calcola il movimento lungo ciascun
asse. Richiami questo helper nel metodo processJoystickInput() descritto
più avanti nel seguente esempio:
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;
}
Mettendo insieme tutti i pezzi, ecco come potresti elaborare i movimenti del joystick nel tuo gioco:
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
}
Per supportare i controller di gioco con funzionalità più sofisticate rispetto a un singolo joystick, segui queste best practice:
- Gestire i due joystick del controller. Molti controller di gioco hanno un joystick sinistro
e uno destro. Per lo stick sinistro, Android segnala i movimenti orizzontali
come eventi
AXIS_Xe i movimenti verticali come eventiAXIS_Y. Per lo stick destro, Android segnala i movimenti orizzontali come eventiAXIS_Ze i movimenti verticali come eventiAXIS_RZ. Assicurati di gestire entrambi gli stick del controller nel tuo codice. - Gestisci le pressioni dei tasti dorsali (e assicurati che il gioco funzioni con gli eventi
AXIS_eKEYCODE_BUTTON_). Alcuni controller hanno i grilletti destro e sinistro. Quando sono presenti, questi attivatori emettono un eventoAXIS_*TRIGGERoKEYCODE_BUTTON_*2o entrambi. Per il trigger sinistro, si tratta diAXIS_LTRIGGEReKEYCODE_BUTTON_L2. Per il trigger destro, si tratta diAXIS_RTRIGGEReKEYCODE_BUTTON_R2. Gli eventi dell'asse si verificano solo se il trigger emette un intervallo di valori compreso tra 0 e 1 e alcuni controller con uscita analogica emettono eventi dei pulsanti oltre agli eventi dell'asse. I giochi devono supportare gli eventiAXIS_eKEYCODE_BUTTON_per rimanere compatibili con tutti i controller di gioco comuni, ma preferisci l'evento più adatto al tuo gameplay se un controller segnala entrambi. Su Android 4.3 (livello API 18) e versioni successive, un controller che produce unAXIS_LTRIGGERriporta anche un valore identico per l'asseAXIS_BRAKE. Lo stesso vale perAXIS_RTRIGGEReAXIS_GAS. Android segnala tutte le pressioni dei trigger analogici con un valore normalizzato da 0,0 (rilasciato) a 1,0 (completamente premuto). - Il comportamento e il supporto specifici possono variare negli ambienti emulati.
Le piattaforme emulate, come Google Play Giochi,
potrebbero differire leggermente nel comportamento in base alle funzionalità del sistema operativo host. Ad esempio, alcuni controller che emettono eventi
AXIS_eKEYCODE_BUTTON_emettono solo eventiAXIS_e il supporto per alcuni controller potrebbe mancare del tutto.
Varianti comuni
Data l'ampia gamma di controller supportati da Android, potrebbe non essere chiaro come creare e testare per verificare che il tuo gioco funzioni senza bug tra i tuoi giocatori. Abbiamo notato che, nonostante questa apparente varietà, i produttori di controller in tutto il mondo tendono ad attenersi in modo coerente a tre diversi stili di controller. Alcuni forniscono interruttori hardware per passare da una modalità all'altra.
Ciò significa che puoi eseguire test con un minimo di tre controller tra i membri del tuo team di sviluppo e avere la certezza che il tuo gioco sia giocabile senza ricorrere a elenchi di consentiti e bloccati.
Tipi di controller comuni
Lo stile più comune dei controller tende a imitare i layout delle console di gioco più popolari. Ciò vale sia per l'estetica delle etichette e del layout dei pulsanti sia per la funzionalità degli eventi generati. I controller con interruttori hardware tra diversi tipi di console cambieranno gli eventi che inviano e spesso anche la disposizione logica dei pulsanti.
Durante i test, ti consigliamo di verificare che il gioco funzioni con un controller in ciascuna delle categorie. Puoi scegliere di eseguire i test con controller proprietari o con produttori di terze parti noti. In genere, mappiamo i controller più popolari alla definizione riportata sopra nel miglior modo possibile.
| Tipo di controller | Differenze comportamentali | Varianti di etichettatura |
|---|---|---|
| Controller in stile Xbox
Questi controller sono in genere realizzati per la piattaforma Microsoft Xbox e Windows*. |
Questi controller corrispondono al set di funzionalità descritto in Input del controller di processo | I pulsanti L2/R2 di questi controller sono etichettati LT/RT |
| Controller in stile Switch
Questi controller sono in genere progettati per la famiglia di console Nintendo Switch*. |
Questi controller inviano i KeyEvent
KEYCODE_BUTTON_R2
KEYCODE_BUTTON_L2
MotionEvent |
I pulsanti L2/R2 di questi controller sono etichettati ZL/ZR.
Questi controller scambiano anche i pulsanti A e B e i pulsanti
X e Y, quindi |
| Controller in stile PlayStation
Questi controller sono in genere progettati per la famiglia di console Sony PlayStation*. |
Questi controller inviano MotionEvents
come i controller in stile Xbox, ma anche KeyEvents
come i controller in stile Switch quando sono completamente premuti. |
Questi controller utilizzano un set diverso di simboli per i pulsanti frontali. |
* Microsoft, Xbox e Windows sono marchi registrati di Microsoft; Nintendo Switch è un marchio registrato di Nintendo of America Inc.; PlayStation è un marchio registrato di Sony Interactive Entertainment Inc.
Pulsanti di attivazione disambiguati
Alcuni controller inviano AXIS_LTRIGGER e AXIS_RTRIGGER, altri inviano
KEYCODE_BUTTON_L2 e KEYCODE_BUTTON_R2, mentre altri ancora inviano tutti questi eventi
in base alle funzionalità hardware. Massimizza la compatibilità supportando tutti
questi eventi.
Tutti i controller che inviano AXIS_LTRIGGER invieranno anche AXIS_BRAKE, allo stesso modo
per AXIS_RTRIGGER e AXIS_GAS, per massimizzare la compatibilità tra i volanti
e i controller di gioco tipici. In genere questo non causa problemi, ma fai
attenzione alle funzionalità come le schermate di rimappatura dei tasti.
| Trigger | MotionEvent |
KeyEvent |
|---|---|---|
| Grilletto sinistro | AXIS_LTRIGGERAXIS_BRAKE
|
KEYCODE_BUTTON_L2
|
| Grilletto destro | AXIS_RTRIGGERAXIS_GAS
|
KEYCODE_BUTTON_R2
|
È necessario prestare attenzione per verificare che il gioco possa gestire sia KeyEvent sia
MotionEvent per mantenere la compatibilità con il maggior numero possibile di controller e che gli eventi vengano deduplicati.
Controller supportati
Durante i test, ti consigliamo di verificare che il gioco funzioni con un controller in ciascuna delle categorie.
- Stile Xbox
- Stile Nintendo Switch
- Stile PlayStation
Puoi eseguire test con controller proprietari o con produttori di terze parti noti e in genere mappiamo i controller più popolari alla definizione nel modo più preciso possibile.