Większość gier jest przeznaczona dla jednego użytkownika na urządzeniu z Androidem, ale można też obsługiwać wielu użytkowników za pomocą kontrolerów do gier, które są połączone jednocześnie na tym samym urządzeniu z Androidem.
W tej lekcji omówimy podstawowe techniki obsługi danych wejściowych w grze wieloosobowej na jednym urządzeniu z wielu podłączonych kontrolerów. Obejmuje to utrzymywanie mapowania między awatarami graczy a poszczególnymi urządzeniami sterującymi i odpowiednie przetwarzanie zdarzeń wejściowych kontrolera.
Mapowanie graczy na identyfikatory urządzeń sterujących
Gdy kontroler do gier jest podłączony do urządzenia z Androidem, system przypisuje mu identyfikator urządzenia w postaci liczby całkowitej. Identyfikatory podłączonych kontrolerów do gier możesz uzyskać, wywołując funkcję InputDevice.getDeviceIds(), jak pokazano w sekcji Sprawdzanie, czy kontroler do gier jest podłączony. Następnie możesz powiązać każdy identyfikator urządzenia z graczem w swojej grze i oddzielnie przetwarzać działania każdego gracza.
Fragment kodu pokazuje, jak za pomocą SparseArray powiązać awatar gracza z określonym kontrolerem. W tym przykładzie zmienna mShips zawiera kolekcję obiektów Ship. Gdy użytkownik podłączy nowy kontroler, w grze zostanie utworzony nowy awatar gracza. Zostanie on usunięty, gdy powiązany z nim kontroler zostanie odłączony.
Metody wywołania zwrotnego onInputDeviceAdded() i onInputDeviceRemoved()
są częścią warstwy abstrakcji wprowadzonej w artykule Obsługa kontrolerów na różnych wersjach Androida.
Dzięki implementacji tych wywołań zwrotnych odbiornika gra może identyfikować identyfikator urządzenia kontrolera po dodaniu lub usunięciu kontrolera. Wykrywanie jest zgodne z Androidem 2.3 (API na poziomie 9) i nowszymi wersjami.
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);
}
Przetwarzanie danych wejściowych z wielu kontrolerów
Aby przetwarzać dane wejściowe z wielu kontrolerów, gra powinna wykonywać tę pętlę:
- wykrywać, czy wystąpiło zdarzenie wejściowe;
- Określ źródło wejściowe i jego identyfikator urządzenia.
- Na podstawie działania wskazanego przez kod klucza zdarzenia wejściowego lub wartość osi zaktualizuj awatar gracza powiązany z tym identyfikatorem urządzenia.
- renderować i aktualizować interfejs użytkownika,
Zdarzenia wejściowe KeyEvent i MotionEvent są powiązane z identyfikatorami urządzeń. Twoja gra może to wykorzystać, aby określić, z którego kontrolera pochodzi zdarzenie wejściowe, i zaktualizować awatar gracza powiązany z tym kontrolerem.
Poniższy fragment kodu pokazuje, jak uzyskać odniesienie do awatara gracza odpowiadające identyfikatorowi urządzenia kontrolera do gier i zaktualizować grę na podstawie naciśnięcia przycisku przez użytkownika na tym kontrolerze.
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);
}