Хотя большинство игр предназначены для поддержки одного пользователя на устройстве 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); }
Обработка нескольких входных данных контроллера
Ваша игра должна выполнить следующий цикл для обработки ввода от нескольких контроллеров:
- Определите, произошло ли событие ввода.
- Определите источник входного сигнала и идентификатор его устройства.
- На основе действия, указанного кодом клавиши входного события или значением оси, обновите аватар игрока, связанный с этим идентификатором устройства.
- Отрисуйте и обновите пользовательский интерфейс.
С событиями ввода 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); }
Примечание. Рекомендуется приостановить игру и спросить, хочет ли пользователь повторно подключиться, если игровой контроллер пользователя отключается.