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 puedes admitir múltiples usuarios con controles de juegos conectadas simultáneamente en el mismo dispositivo Android.

Esta lección abarca algunas técnicas básicas para manejar la entrada en tu juego multijugador en dispositivos desde varios controles conectados. Esto incluye mantener una asignación entre los avatares de los jugadores y cada dispositivo controlador y los eventos de entrada del controlador de forma adecuada.

Cómo asignar jugadores a los ID de dispositivos controladores

Cuando se conecta un control de juegos a un dispositivo Android, el sistema le asigna un ID de dispositivo de número entero. Puedes obtener los IDs de dispositivos conectados controles de juegos llamando a InputDevice.getDeviceIds(), como se muestra en Cómo verificar si un control de 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 dispositivos con Android 4.1 (API nivel 16) y versiones posteriores, podrás obtener el descriptor de un dispositivo de entrada usando getDescriptor(), que muestra un único de cadena persistente para el dispositivo de entrada. A diferencia de un ID de dispositivo, el descriptor valor no cambiará incluso si el dispositivo de entrada se desconecta, se vuelve a conectar o no se deben volver a configurar.

En el siguiente fragmento de código, 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. Un nuevo el avatar del jugador se crea en el juego cuando un usuario conecta un nuevo controlador. y se quita cuando se quita el controlador asociado.

Devolución de llamada onInputDeviceAdded() y onInputDeviceRemoved() son parte de la capa de abstracción presentada en Compatibilidad con controladores en diferentes versiones de Android. Si implementas estas de objetos de escucha, tu juego puede identificar el ID de dispositivo del controlador para juegos cuando un agregar o quitar un controlador. Esta detección es compatible con Android 2.3 (nivel de API 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 entrada de múltiples controladores:

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

Entrada de KeyEvent y MotionEvent los eventos tienen IDs de dispositivo asociados. Tu juego puede aprovechar esto para determinar de qué controlador provino el evento de entrada y actualizar el el avatar del jugador asociado con ese controlador.

En el siguiente fragmento de código, se muestra cómo podrías obtener una referencia del avatar de un jugador. correspondiente al ID de dispositivo del control de juegos y actualizar el juego según el presionar el botón del usuario en ese control.

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 la ventana de usuario el control de juegos se desconecta, debes pausar el juego y preguntar quiere volver a conectarse.