Mendukung beberapa pengontrol game

Meskipun sebagian besar game didesain untuk mendukung satu pengguna per perangkat Android, game juga dapat mendukung beberapa pengguna dengan pengontrol game yang terhubung secara bersamaan di perangkat Android yang sama.

Tutorial ini membahas beberapa teknik dasar untuk menangani input dalam game multiplayer satu perangkat dari beberapa pengontrol yang terhubung. Hal ini termasuk mempertahankan pemetaan antara avatar pemain dan setiap perangkat pengontrol serta memproses peristiwa input pengontrol dengan tepat.

Memetakan pemain ke ID perangkat pengontrol

Saat pengontrol game terhubung ke perangkat Android, sistem akan menetapkan ID perangkat bilangan bulat untuk pengontrol tersebut. Anda bisa mendapatkan ID perangkat untuk pengontrol game yang terhubung dengan memanggil InputDevice.getDeviceIds(), seperti yang ditunjukkan dalam Memverifikasi bahwa Pengontrol Game Terhubung. Kemudian, Anda dapat mengaitkan setiap ID perangkat dengan pemain di game Anda, dan memproses tindakan game untuk setiap pemain secara terpisah.

Catatan: Pada perangkat yang menjalankan Android 4.1 (API level 16) dan yang lebih tinggi, Anda dapat memperoleh deskriptor perangkat input menggunakan getDescriptor(), yang menampilkan nilai string persisten yang unik untuk perangkat input. Tidak seperti ID perangkat, nilai deskripsi tidak akan berubah meskipun perangkat input terputus, terhubung kembali, atau dikonfigurasi ulang.

Cuplikan kode di bawah ini menunjukkan cara menggunakan SparseArray untuk mengaitkan avatar pemain dengan pengontrol tertentu. Dalam contoh ini, variabel mShips menyimpan kumpulan objek Ship. Avatar pemain baru dibuat dalam game saat pengontrol baru dikaitkan oleh pengguna, dan dihapus saat pengontrol terkaitnya dihapus.

Metode callback onInputDeviceAdded() dan onInputDeviceRemoved() adalah bagian dari lapisan abstraksi yang diperkenalkan dalam Mendukung Pengontrol di Seluruh Versi Android. Dengan menerapkan callback pemroses ini, game Anda dapat mengidentifikasi ID perangkat pengontrol game saat pengontrol ditambahkan atau dihapus. Deteksi ini kompatibel dengan Android 2.3 (API level 9) dan yang lebih tinggi.

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

Memproses beberapa input pengontrol

Game Anda harus menjalankan loop berikut untuk memproses input dari beberapa pengontrol:

  1. Mendeteksi apakah peristiwa input terjadi.
  2. Mengidentifikasi sumber input dan ID perangkatnya.
  3. Berdasarkan tindakan yang ditunjukkan oleh kode tombol peristiwa input atau nilai sumbu, perbarui avatar pemain yang dikaitkan dengan ID perangkat tersebut.
  4. Merender dan memperbarui antarmuka pengguna.

Peristiwa input KeyEvent dan MotionEvent memiliki ID perangkat yang terkait dengannya. Game Anda dapat memanfaatkan hal ini untuk menentukan dari pengontrol mana peristiwa input berasal, dan memperbarui avatar pemain yang terkait dengan pengontrol tersebut.

Cuplikan kode berikut menunjukkan cara agar Anda bisa mendapatkan referensi avatar pemain yang sesuai dengan ID perangkat pengontrol game, dan mengupdate game berdasarkan tekan tombol oleh pengguna di pengontrol tersebut.

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

Catatan: Sebagai praktik terbaik, saat pengontrol game pengguna terputus sambungannya, Anda harus menjeda game dan menanyakan apakah pengguna ingin terhubung kembali.