Unterstützung für mehrere Gamecontroller

Die meisten Spiele sind für einen einzelnen Nutzer pro Android-Gerät konzipiert. Es ist aber auch möglich, mehrere Nutzer mit Controllern zu unterstützen, die gleichzeitig mit demselben Android-Gerät verbunden sind.

In dieser Lektion werden einige grundlegende Techniken für die Verarbeitung von Eingaben in Ihrem Mehrspielerspiel für ein einzelnes Gerät von mehreren verbundenen Controllern behandelt. Dazu gehört, eine Zuordnung zwischen Spieler-Avataren und jedem Controller-Gerät aufrechtzuerhalten und Controller-Eingabeereignisse entsprechend zu verarbeiten.

Spieler Controller-Geräte-IDs zuordnen

Wenn ein Controller mit einem Android-Gerät verbunden ist, weist das System ihm eine ganzzahlige Geräte-ID zu. Sie können die Geräte-IDs für verbundene Controller abrufen, indem Sie InputDevice.getDeviceIds() aufrufen, wie unter Verify a Game Controller is Connected beschrieben. Sie können dann jede Geräte-ID einem Spieler in Ihrem Spiel zuordnen und Spielaktionen für jeden Spieler separat verarbeiten.

Das Code-Snippet zeigt, wie Sie mit einem SparseArray den Avatar eines Spielers mit einem bestimmten Controller verknüpfen. In diesem Beispiel wird in der Variablen mShips eine Sammlung von Ship-Objekten gespeichert. Wenn ein Nutzer einen neuen Controller anschließt, wird im Spiel ein neuer Spieler-Avatar erstellt. Wenn der zugehörige Controller entfernt wird, wird auch der Avatar entfernt.

Die Callback-Methoden onInputDeviceAdded() und onInputDeviceRemoved() sind Teil der Abstraktionsschicht, die in Controller für verschiedene Android-Versionen unterstützen eingeführt wurde. Durch die Implementierung dieser Listener-Callbacks kann Ihr Spiel die Geräte-ID des Gamepads ermitteln, wenn ein Controller hinzugefügt oder entfernt wird. Diese Erkennung ist mit Android 2.3 (API-Level 9) und höher kompatibel.

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

Mehrere Controllereingaben verarbeiten

Ihr Spiel sollte die folgende Schleife ausführen, um Eingaben von mehreren Controllern zu verarbeiten:

  1. Erkennen, ob ein Eingabeereignis aufgetreten ist.
  2. Ermitteln Sie die Eingangsquelle und ihre Geräte-ID.
  3. Aktualisieren Sie den mit dieser Geräte-ID verknüpften Spieler-Avatar basierend auf der Aktion, die durch den Eingabeereignis-Tastencode oder den Achsenwert angegeben wird.
  4. Benutzeroberfläche rendern und aktualisieren

KeyEvent- und MotionEvent-Eingabeereignisse sind mit Geräte-IDs verknüpft. Ihr Spiel kann diese Informationen nutzen, um zu ermitteln, von welchem Controller das Eingabeereignis stammt, und den mit diesem Controller verknüpften Spieler-Avatar aktualisieren.

Das folgende Code-Snippet zeigt, wie Sie eine Spieler-Avatar-Referenz abrufen, die einer Geräte-ID eines Gamecontrollers entspricht, und das Spiel basierend auf dem Tastendruck des Nutzers auf diesem Controller aktualisieren.

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