Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo brindar compatibilidad con varios controladores para juegos

Si bien la mayoría de los juegos están diseñados para admitir un solo usuario por dispositivo Android, también se pueden admitir varios usuarios con controladores en juegos que se conectan simultáneamente en el mismo dispositivo Android.

En esta lección, se explican algunas técnicas básicas para administrar la entrada de varios controladores conectados en tu juego multijugador en un dispositivo único. Entre ellas se incluyen mantener una asignación entre los avatares de los jugadores y cada dispositivo controlador, y procesar los eventos de entrada de los controladores de manera adecuada.

Cómo asignar jugadores a los ID de dispositivos controladores

Cuando se conecta un controlador de juegos a un dispositivo Android, el sistema le asigna un número entero como ID de dispositivo. Si quieres obtener los ID de dispositivos de los controladores para juegos conectados, llama a InputDevice.getDeviceIds(), como se muestra en Cómo verificar que un controlador para juegos esté conectado. Luego, puedes asociar cada ID de dispositivo con un jugador en tu juego y procesar las acciones del juego para cada jugador por separado.

Nota: En los dispositivos que ejecutan Android 4.1 (API nivel 16) y versiones posteriores, puedes obtener un descriptor del dispositivo de entrada con getDescriptor(), que muestra un valor de string único persistente para el dispositivo de entrada. A diferencia de un ID de dispositivo, el valor del descriptor no cambiará aunque se desconecte o se vuelva a conectar el dispositivo de entrada, o se modifique su configuración.

En el fragmento de código que aparece debajo, se muestra cómo usar un SparseArray para asociar el avatar de un jugador con un controlador específico. En este ejemplo, la variable mShips almacena una colección de objetos Ship. Se crea un avatar de jugador nuevo en el juego cuando el usuario conecta un controlador nuevo y se lo quita cuando se desconecta el controlador asociado.

Los métodos de devolución de llamada onInputDeviceAdded() y onInputDeviceRemoved() forman parte de la capa de abstracción que se presenta en Cómo brindar compatibilidad con controladores en diferentes versiones de Android. Al implementar estas devoluciones de llamadas del objeto de escucha, tu juego puede identificar el ID de dispositivo del controlador para juegos cuando se agrega o quita un controlador. Esta detección es compatible con Android 2.3 (API nivel 9) y versiones posteriores.

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

Cómo procesar la entrada de varios controladores

Tu juego debería ejecutar el siguiente bucle para procesar la entrada de varios controladores:

  1. Detecta si hubo un evento de entrada.
  2. Identifica la fuente de entrada y su ID de dispositivo.
  3. En función de la acción que indica el valor del eje o el código de tecla del evento de entrada, actualiza el avatar del jugador asociado con el ID de dispositivo.
  4. Procesa y actualiza la interfaz de usuario.

Los eventos de entrada KeyEvent y MotionEvent tienen ID de dispositivos asociados a ellos. Tu juego puede aprovecharlos para determinar desde qué controlador se produjo el evento de entrada y actualizar el avatar del jugador asociado a este.

En el siguiente fragmento de código, se muestra cómo puedes obtener una referencia del avatar de un jugador que corresponde al ID de dispositivo del controlador para juegos y actualizar el juego en función del botón que el usuario presionó en ese 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);
    }
    

Nota: Como práctica recomendada, cuando se desconecte el controlador para juegos de un usuario, deberías pausar el juego y preguntarle si quiere volver a conectarlo.