Embora a maioria dos jogos seja projetada para oferecer suporte a um único usuário por dispositivo Android, também é possível oferecer suporte a vários usuários com controles de jogos que estão conectados simultaneamente no mesmo dispositivo Android.
Esta lição aborda algumas técnicas básicas para lidar com entradas em seu jogo multiplayer de dispositivo com vários controles conectados. Isso inclui manter um mapeamento entre os avatares dos jogadores e cada dispositivo controlador processar corretamente os eventos de entrada do controlador.
Mapear jogadores de acordo com códigos de dispositivo dos controles
Quando um controle de jogo está conectado a um dispositivo Android, o sistema
atribui a ele um ID de dispositivo inteiro. Você pode obter os IDs de dispositivos para
controles de jogos chamando InputDevice.getDeviceIds()
, conforme mostrado em Verificar se um controle de jogo está conectado. Em seguida, é possível associar cada
o ID do dispositivo com um jogador e processar as ações do jogo para cada jogador separadamente.
Observação: em dispositivos com o Android 4.1 (API
nível 16) e superiores, é possível obter o descritor de um dispositivo de entrada usando
getDescriptor()
, que retorna um valor
valor de string persistente do dispositivo de entrada. Diferentemente do ID de um dispositivo, o descritor
valor não será alterado mesmo se o dispositivo de entrada for desconectado, reconectado ou
ser reconfigurada.
O snippet de código abaixo mostra como usar um SparseArray
para associar o avatar de um jogador a um controle específico. Neste exemplo,
A variável mShips
armazena uma coleção de objetos Ship
. Um novo
o avatar do jogador é criado no jogo quando um novo controle é conectado por um usuário.
e removido quando o controlador associado é removido.
Os callbacks onInputDeviceAdded()
e onInputDeviceRemoved()
.
fazem parte da camada de abstração introduzida no
Compatibilidade com controles em várias versões do Android. Ao implementar essas
callbacks de listener, o jogo poderá identificar o ID do dispositivo do controle de jogo quando um
é adicionado ou removido. Esta detecção é compatível com o Android 2.3
(nível 9 da API) e mais recentes.
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); }
Processar a entrada de vários controles
Seu jogo precisa executar esta repetição para processar entrada de vários controles:
- Detectar se ocorreu um evento de entrada.
- Identificar a origem da entrada e o código do dispositivo correspondente.
- Com base na ação indicada pelo código da tecla do evento de entrada ou pelo valor do eixo, atualizar o avatar do jogador associado a esse ID do dispositivo.
- Renderizar e atualizar a interface do usuário.
Entrada de KeyEvent
e MotionEvent
têm IDs de dispositivo associados a eles. Seu jogo pode aproveitar
para determinar de qual controlador veio o evento de entrada e atualizar o
avatar do jogador associado a esse controle.
O snippet de código a seguir mostra como acessar uma referência ao avatar de um jogador correspondente a um ID de controle de jogo e atualiza o jogo com base no o botão do usuário pressionar nesse controlador.
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); }
Observação: como prática recomendada, quando a conexão o controle de jogo se desconectar, pause o jogo e pergunte se o usuário quer se reconectar.