Supporto di più controller di gioco

Anche se la maggior parte dei giochi è progettata per supportare un singolo utente per dispositivo Android, è anche possibile supportare più utenti con controller di gioco connessi contemporaneamente sullo stesso dispositivo Android.

Questa lezione riguarda alcune tecniche di base per la gestione dell'input nei gioco multiplayer sul dispositivo da più controller collegati. Sono inclusi mantenere una mappatura tra gli avatar dei giocatori e ogni controller e degli eventi di input del controller in modo appropriato.

Mappare i player agli ID dispositivo del controller

Quando un controller di gioco è collegato a un dispositivo Android, il sistema gli assegna un ID dispositivo intero. Puoi ottenere gli ID dispositivo per dispositivi connessi chiamata InputDevice.getDeviceIds(), come mostrato nella sezione Verificare che un controller di gioco sia connesso. Puoi quindi associare ogni ID dispositivo con un giocatore nel gioco ed elabora le azioni di gioco per ogni giocatore separatamente.

Nota: sui dispositivi con Android 4.1 (API livello 16) e superiore, puoi ottenere il descrittore di un dispositivo di input utilizzando getDescriptor(), che restituisce un valore valore di stringa permanente per il dispositivo di input. A differenza di un ID dispositivo, il descrittore non cambierà anche se il dispositivo di input è scollegato, ricollegato o riconfigurate.

Lo snippet di codice riportato di seguito mostra come utilizzare un SparseArray per associare l'avatar di un giocatore a un controller specifico. In questo esempio, La variabile mShips archivia una raccolta di Ship oggetti. Un nuovo l'avatar del giocatore viene creato in-game quando un utente collega un nuovo controller e quando viene rimosso il controller associato.

Il callback onInputDeviceAdded() e onInputDeviceRemoved() fanno parte dello strato di astrazione introdotto . Supporto di controller su tutte le versioni di Android. Implementando questi di ascolto, il gioco può identificare l'ID dispositivo del controller di gioco quando viene aggiunto o rimosso. Questo rilevamento è compatibile con Android 2.3 (livello API 9) e superiori.

Kotlin

private val ships = SparseArray<Ship>()

override fun onInputDeviceAdded(deviceId: Int) {
    getShipForID(deviceId)
}

override fun onInputDeviceRemoved(deviceId: Int) {
    removeShipForID(deviceId)
}

private fun getShipForID(shipID: Int): Ship {
    return ships.get(shipID) ?: Ship().also {
        ships.append(shipID, it)
    }
}

private fun removeShipForID(shipID: Int) {
    ships.remove(shipID)
}

Java

private final SparseArray<Ship> ships = new SparseArray<Ship>();

@Override
public void onInputDeviceAdded(int deviceId) {
    getShipForID(deviceId);
}

@Override
public void onInputDeviceRemoved(int deviceId) {
    removeShipForID(deviceId);
}

private Ship getShipForID(int shipID) {
    Ship currentShip = ships.get(shipID);
    if ( null == currentShip ) {
        currentShip = new Ship();
        ships.append(shipID, currentShip);
    }
    return currentShip;
}

private void removeShipForID(int shipID) {
    ships.remove(shipID);
}

Elabora input di più controller

Il gioco deve eseguire il seguente loop per elaborare input da più controller:

  1. Rileva se si è verificato un evento di input.
  2. Identifica l'origine di input e il relativo ID dispositivo.
  3. In base all'azione indicata dal codice chiave dell'evento di input o dal valore dell'asse, aggiornare l'avatar del player associato a quell'ID dispositivo.
  4. Esegui il rendering e aggiorna l'interfaccia utente.

Input di KeyEvent e MotionEvent sono associati a un ID dispositivo. Il tuo gioco può sfruttare questo per determinare da quale controller proviene l'evento di input e aggiornare l'avatar del giocatore associato a quel controller.

Il seguente snippet di codice mostra come potresti ottenere un riferimento per l'avatar di un player corrispondente all'ID dispositivo di un controller di gioco e aggiorna il gioco in base al premere il pulsante dell'utente su quel controller.

Kotlin

override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
    if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) {
        event.deviceId.takeIf { it != -1 }?.also { deviceId ->
            val currentShip: Ship = getShipForID(deviceId)
            // Based on which key was pressed, update the player avatar
            // (e.g. set the ship headings or fire lasers)
            return true
        }
    }
    return super.onKeyDown(keyCode, event)
}

Java

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((event.getSource() & InputDevice.SOURCE_GAMEPAD)
                == InputDevice.SOURCE_GAMEPAD) {
        int deviceId = event.getDeviceId();
        if (deviceId != -1) {
            Ship currentShip = getShipForId(deviceId);
            // Based on which key was pressed, update the player avatar
            // (e.g. set the ship headings or fire lasers)
            ...
            return true;
        }
    }
    return super.onKeyDown(keyCode, event);
}

Nota : come best practice, quando un utente il controller di gioco si disconnette, devi mettere in pausa il gioco e chiedere se l'utente vuole riconnettersi.