Поддержка нескольких игровых контроллеров

Хотя большинство игр предназначены для поддержки одного пользователя на устройстве Android, также возможна поддержка нескольких пользователей с игровыми контроллерами, которые одновременно подключены к одному устройству Android.

В этом уроке рассматриваются некоторые основные методы обработки ввода в многопользовательской игре на одном устройстве с нескольких подключенных контроллеров. Это включает в себя поддержание сопоставления между аватарами игроков и каждым устройством контроллера и соответствующую обработку входных событий контроллера.

Сопоставьте игроков с идентификаторами устройств контроллера

Когда игровой контроллер подключен к устройству Android, система присваивает ему целочисленный идентификатор устройства. Вы можете получить идентификаторы устройств для подключенных игровых контроллеров, вызвав InputDevice.getDeviceIds() , как показано в разделе «Проверка подключения игрового контроллера» . Затем вы можете связать каждый идентификатор устройства с игроком в вашей игре и обрабатывать игровые действия для каждого игрока отдельно.

Примечание. На устройствах под управлением Android 4.1 (уровень API 16) и выше вы можете получить дескриптор устройства ввода с помощью getDescriptor() , который возвращает уникальное постоянное строковое значение для устройства ввода. В отличие от идентификатора устройства, значение дескриптора не изменится, даже если устройство ввода будет отключено, повторно подключено или переконфигурировано.

В приведенном ниже фрагменте кода показано, как использовать SparseArray для связи аватара игрока с определенным контроллером. В этом примере переменная mShips хранит коллекцию объектов Ship . Новый аватар игрока создается в игре, когда пользователь прикрепляет новый контроллер, и удаляется, когда удаляется связанный с ним контроллер.

Методы обратного вызова onInputDeviceAdded() и onInputDeviceRemoved() являются частью уровня абстракции, представленного в разделе «Поддержка контроллеров в разных версиях Android» . Реализуя эти обратные вызовы прослушивателя, ваша игра может идентифицировать идентификатор устройства игрового контроллера при добавлении или удалении контроллера. Это обнаружение совместимо с Android 2.3 (уровень API 9) и выше.

Котлин

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

Ява

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

Обработка нескольких входных данных контроллера

Ваша игра должна выполнить следующий цикл для обработки ввода от нескольких контроллеров:

  1. Определите, произошло ли событие ввода.
  2. Определите источник входного сигнала и идентификатор его устройства.
  3. На основе действия, указанного кодом клавиши входного события или значением оси, обновите аватар игрока, связанный с этим идентификатором устройства.
  4. Отрисуйте и обновите пользовательский интерфейс.

С событиями ввода KeyEvent и MotionEvent связаны идентификаторы устройств. Ваша игра может воспользоваться этим, чтобы определить, с какого контроллера пришло событие ввода, и обновить аватар игрока, связанный с этим контроллером.

В следующем фрагменте кода показано, как можно получить ссылку на аватар игрока, соответствующую идентификатору устройства игрового контроллера, и обновить игру на основе нажатия кнопки пользователя на этом контроллере.

Котлин

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

Ява

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

Примечание. Рекомендуется приостановить игру и спросить, хочет ли пользователь повторно подключиться, если игровой контроллер пользователя отключается.