Birden fazla oyun kumandasını destekleme

Çoğu oyun, Android cihaz başına tek bir kullanıcıyı destekleyecek şekilde tasarlanmış olsa da aynı Android cihaza eş zamanlı olarak bağlanan oyun kumandalarına sahip birden fazla kullanıcıyı desteklemek de mümkündür.

Bu derste, tek cihazlı çok oyunculu oyununuzda birden fazla bağlı kumandadan gelen girişleri yönetmeyle ilgili bazı temel teknikler ele alınmaktadır. Bu, oyuncu avatarları ile her bir kumanda cihazı arasında bir eşlemenin korunmasını ve denetleyici giriş etkinliklerinin uygun şekilde işlenmesini içerir.

Oynatıcıları kumandanın cihaz kimlikleriyle eşleme

Oyun kumandası bir Android cihaza bağlandığında sistem, ona tam sayı cihaz kimliği atar. Oyun Denetleyicisinin Bağlı Olduğunu Doğrulama bölümünde gösterildiği gibi, InputDevice.getDeviceIds() yöntemini çağırarak bağlı oyun kumandalarının cihaz kimliklerini alabilirsiniz. Daha sonra her cihaz kimliğini oyununuzdaki bir oyuncuyla ilişkilendirebilir ve her oyuncunun oyun işlemlerini ayrı ayrı işleyebilirsiniz.

Not: Android 4.1 (API düzeyi 16) ve sonraki sürümleri çalıştıran cihazlarda, giriş cihazı için benzersiz bir kalıcı dize değeri döndüren getDescriptor() ile giriş cihazının tanımlayıcısını alabilirsiniz. Cihaz kimliğinin aksine, giriş cihazının bağlantısı kesilse, yeniden bağlansa veya yeniden yapılandırılmış olsa bile açıklayıcı değer değişmez.

Aşağıdaki kod snippet'i, bir oyuncunun avatarını belirli bir kumandayla ilişkilendirmek için SparseArray özelliğinin nasıl kullanılacağını göstermektedir. Bu örnekte mShips değişkeni, Ship nesne koleksiyonunu depolar. Bir kullanıcı tarafından yeni bir kumanda eklendiğinde yeni bir oyuncu avatarı oluşturulur ve ilişkili kumanda kaldırıldığında oyun içinde kaldırılır.

onInputDeviceAdded() ve onInputDeviceRemoved() geri çağırma yöntemleri, Android Sürümlerinde Denetleyicileri Destekleme bölümünde açıklanan soyutlama katmanının bir parçasıdır. Bu dinleyici geri çağırmalarını uygulayarak, bir denetleyici eklendiğinde veya kaldırıldığında oyununuz oyun denetleyicinin cihaz kimliğini tanımlayabilir. Bu algılama özelliği, Android 2.3 (API düzeyi 9) ve sonraki sürümlerle uyumludur.

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

Birden fazla denetleyici girişini işleyin

Oyununuz, birden fazla denetleyiciden gelen girişleri işlemek için aşağıdaki döngüyü yürütülmelidir:

  1. Bir giriş etkinliğinin gerçekleşip gerçekleşmediğini algılar.
  2. Giriş kaynağını ve cihaz kimliğini tanımlayın.
  3. Giriş etkinliği anahtar kodu veya eksen değeri tarafından belirtilen işleme göre söz konusu cihaz kimliğiyle ilişkili oyuncu avatarını güncelleyin.
  4. Kullanıcı arayüzünü oluşturun ve güncelleyin.

KeyEvent ve MotionEvent giriş etkinliklerinin, kendileriyle ilişkilendirilmiş cihaz kimlikleri var. Oyununuz bu özellikten yararlanarak giriş etkinliğinin hangi kumandadan geldiğini belirleyebilir ve bu kumandayla ilişkilendirilmiş oyuncu avatarını güncelleyebilir.

Aşağıdaki kod snippet'i, oyun kumandası cihaz kimliğine karşılık gelen bir oyuncu avatarı referansını nasıl alabileceğinizi ve oyunu, kullanıcının kumandadaki düğmesine basarak nasıl güncelleyeceğinizi gösterir.

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

Not: En iyi uygulama olarak, bir kullanıcının oyun kumandası bağlantısı kesildiğinde oyunu duraklatmanız ve kullanıcının yeniden bağlanmak isteyip istemediğini sormanız gerekir.