Kumanda işlemlerini gerçekleştirme

Android, sistem düzeyinde, oyun denetleyicilerden gelen etkinlik kodlarını Android anahtar kodları ve eksen değerleri olarak bildirir. Oyununuzda bu kodları ve değerleri alıp belirli oyun içi işlemlere dönüştürebilirsiniz.

Oyuncular bir oyun kumandasını Android destekli cihazlarına fiziksel olarak bağlandığında veya kablosuz olarak eşlediğinde sistem, kumandayı otomatik olarak giriş cihazı olarak algılar ve giriş etkinliklerini raporlamaya başlar. Oyununuz, bu giriş etkinliklerini, etkin Activity veya odaklanılan View öğelerinize aşağıdaki geri çağırma yöntemlerini uygulayarak alabilir (geri çağırmaları ya Activity ya da View için uygulamanız gerekir ancak ikisi için de uygulamamalısınız):

Önerilen yaklaşım, kullanıcının etkileşimde bulunduğu belirli View nesnesinden etkinlikleri yakalamaktır. Alınan giriş etkinliğinin türü hakkında bilgi almak için geri çağırmaların sağladığı aşağıdaki nesneleri inceleyin:

KeyEvent
Yön tuşları (D-pad) ve oyun kumandası düğmesi etkinliklerini açıklayan bir nesnedir. Önemli etkinliklere, DPAD_DOWN veya BUTTON_A gibi belirli bir düğmenin tetiklendiğini belirten bir anahtar kodu eşlik eder. Anahtar kodunu getKeyCode() yöntemini çağırarak veya onKeyDown() gibi önemli etkinlik geri çağırmalarından edinebilirsiniz.
MotionEvent
Kontrol çubuğundan ve omuz tetikleyici hareketlerinden gelen girişleri tanımlayan bir nesnedir. Hareket etkinliklerine bir işlem kodu ve bir dizi eksen değeri eşlik eder. İşlem kodu, gerçekleşen durum değişikliğini belirtir (örneğin, bir kontrol çubuğunun hareket etmesi). Eksen değerleri, AXIS_X veya AXIS_RTRIGGER gibi belirli bir fiziksel kontrol için konum ve diğer hareket özelliklerini açıklar. İşlem kodunu, getAction() çağrısı yaparak ve eksen değerini getAxisValue() çağrısı yaparak elde edebilirsiniz.

Bu ders, yukarıda bahsedilen View geri çağırma yöntemlerini uygulayarak ve KeyEvent ile MotionEvent nesnelerini işleyerek oyun ekranında en yaygın fiziksel kontrol türlerinden (oyun kumandası düğmeleri, yön tuşları ve kontrol çubukları) girişleri nasıl yönetebileceğinize odaklanmaktadır.

Oyun kumandasının bağlandığını doğrulama

Android, giriş etkinliklerini bildirirken, oyun kumandası olmayan bir cihazdan gelen etkinlikler ile oyun kumandasından gelen etkinlikleri ayırt etmez. Örneğin, dokunmatik ekran işlemi, dokunma yüzeyinin X koordinatını temsil eden bir AXIS_X etkinliği oluştururken bir kontrol çubuğu, kontrol çubuğunun X konumunu temsil eden bir AXIS_X etkinliği oluşturur. Oyununuz, oyun denetleyicisi girişini işlemeye önem veriyorsa öncelikle giriş etkinliğinin ilgili bir kaynak türünden gelip gelmediğini kontrol etmeniz gerekir.

Bağlı bir giriş cihazının oyun kumandası olduğunu doğrulamak için getSources() çağrısı yaparak bu cihazda desteklenen giriş kaynağı türlerinin birleşik bit alanını alın. Ardından aşağıdaki alanların ayarlanıp ayarlanmadığını test edebilirsiniz:

  • SOURCE_GAMEPAD kaynak türü, giriş cihazında oyun kumandası düğmeleri (örneğin, BUTTON_A) olduğunu belirtir. Çoğu oyun kumandasında genellikle yön kontrolleri olsa da bu kaynak türünün, oyun kumandasında D-pad düğmeleri olup olmadığını kesin olarak belirtmediğini unutmayın.
  • SOURCE_DPAD kaynak türü, giriş cihazında D-pad düğmeleri (örneğin, DPAD_UP) olduğunu belirtir.
  • SOURCE_JOYSTICK kaynak türü, giriş cihazında analog kontrol çubuklarının (örneğin, AXIS_X ve AXIS_Y boyunca hareketleri kaydeden bir kontrol çubuğu) olduğunu belirtir.

Aşağıdaki kod snippet'i, bağlı giriş cihazlarının oyun kumandası olup olmadığını kontrol etmenizi sağlayan yardımcı bir yöntem gösterir. Bu durumda yöntem, oyun kumandaları için cihaz kimliklerini alır. Daha sonra her cihaz kimliğini oyununuzdaki bir oyuncuyla ilişkilendirebilir ve bağlı her oyuncunun oyun işlemlerini ayrı ayrı işleyebilirsiniz. Aynı Android cihaza aynı anda bağlı olan birden fazla oyun kumandasını destekleme hakkında daha fazla bilgi edinmek için Birden fazla oyun kumandasını destekleme bölümüne bakın.

Kotlin

fun getGameControllerIds(): List<Int> {
    val gameControllerDeviceIds = mutableListOf<Int>()
    val deviceIds = InputDevice.getDeviceIds()
    deviceIds.forEach { deviceId ->
        InputDevice.getDevice(deviceId).apply {

            // Verify that the device has gamepad buttons, control sticks, or both.
            if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD
                    || sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK) {
                // This device is a game controller. Store its device ID.
                gameControllerDeviceIds
                        .takeIf { !it.contains(deviceId) }
                        ?.add(deviceId)
            }
        }
    }
    return gameControllerDeviceIds
}

Java

public ArrayList<Integer> getGameControllerIds() {
    ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>();
    int[] deviceIds = InputDevice.getDeviceIds();
    for (int deviceId : deviceIds) {
        InputDevice dev = InputDevice.getDevice(deviceId);
        int sources = dev.getSources();

        // Verify that the device has gamepad buttons, control sticks, or both.
        if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
                || ((sources & InputDevice.SOURCE_JOYSTICK)
                == InputDevice.SOURCE_JOYSTICK)) {
            // This device is a game controller. Store its device ID.
            if (!gameControllerDeviceIds.contains(deviceId)) {
                gameControllerDeviceIds.add(deviceId);
            }
        }
    }
    return gameControllerDeviceIds;
}

Buna ek olarak, bağlı bir oyun kumandası tarafından desteklenen bağımsız giriş özelliklerini de kontrol edebilirsiniz. Örneğin, oyununuzun yalnızca anladığı fiziksel kontrol grubundaki girişleri kullanmasını istiyorsanız bu özellik faydalı olabilir.

Belirli bir anahtar kodunun veya eksen kodunun bağlı bir oyun kumandası tarafından desteklenip desteklenmediğini tespit etmek için aşağıdaki teknikleri kullanın:

  • Android 4.4 (API düzeyi 19) veya sonraki sürümlerde, hasKeys(int...) çağrısı yaparak bağlı bir oyun kumandasında anahtar kodunun desteklenip desteklenmediğini belirleyebilirsiniz.
  • Android 3.1 (API düzeyi 12) veya sonraki sürümlerde, önce getMotionRanges() çağrısı yaparak bağlı bir oyun denetleyicisinin desteklediği tüm kullanılabilir eksenleri bulabilirsiniz. Ardından, döndürülen her InputDevice.MotionRange nesnesinde getAxis() çağrısı yaparak eksen kimliğini alın.

Oyun kumandası düğmesine basmaları işleme

Şekil 1'de Android'in çoğu oyun kumandasındaki anahtar kodları ve eksen değerlerini fiziksel kontrollerle nasıl eşleştirdiği gösterilmektedir.

Şekil 1. Genel oyun kumandası için profil.

Şekildeki açıklama metinleri aşağıdakileri ifade eder:

Oyun kumandası düğmesine basılmasıyla oluşturulan yaygın anahtar kodları arasında BUTTON_A, BUTTON_B, BUTTON_SELECT ve BUTTON_START yer alır. Bazı oyun kumandaları da D-pad çapraz çubuğunun ortasına basıldığında DPAD_CENTER tuş kodunu tetikler. Oyununuz, getKeyCode() yöntemini veya onKeyDown() gibi önemli etkinlik geri çağırmalarını kullanarak anahtar kodunu inceleyebilir. Ayrıca, oyununuzla ilgili bir etkinliği temsil ediyorsa bunu bir oyun işlemi olarak işleyebilir. Tablo 1'de, en yaygın oyun kumandası düğmeleri için önerilen oyun işlemleri listelenmiştir.

Tablo 1. Oyun kumandası düğmeleri için önerilen oyun işlemleri.

Oyun Aksiyon Düğme Tuşu Kodu
Oyunu ana menüden başlatın veya oyun sırasında duraklatın/duraklatmayı kaldırın BUTTON_START*
Menüyü göster BUTTON_SELECT* ve KEYCODE_MENU*
Gezinme tasarım kılavuzunda açıklanan Android'in Geri gezinme davranışıyla aynıdır. KEYCODE_BACK
Menüde önceki bir öğeye geri gitme BUTTON_B
Seçimi onayla veya oyunla ilgili birincil işlemi gerçekleştir BUTTON_A ve DPAD_CENTER

* Oyununuz Başlat, Seç veya Menü düğmelerinin varlığına dayalı olmamalıdır.

İpucu: Kullanıcıların oyun işlemleri için kendi oyun kumandalarını kişiselleştirmelerine izin vermek amacıyla oyununuzda bir yapılandırma ekranı sağlayın.

Aşağıdaki snippet'te, BUTTON_A ve DPAD_CENTER düğmelerine basmaları bir oyun işlemiyle ilişkilendirmek için onKeyDown() özelliğini nasıl geçersiz kılabileceğiniz gösterilmektedir.

Kotlin

class GameView(...) : View(...) {
    ...

    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
        var handled = false
        if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) {
            if (event.repeatCount == 0) {
                when (keyCode) {
                    // Handle gamepad and D-pad button presses to navigate the ship
                    ...

                    else -> {
                        keyCode.takeIf { isFireKey(it) }?.run {
                            // Update the ship object to fire lasers
                            ...
                            handled = true
                        }
                    }
                }
            }
            if (handled) {
                return true
            }
        }
        return super.onKeyDown(keyCode, event)
    }

    // Here we treat Button_A and DPAD_CENTER as the primary action
    // keys for the game.
    private fun isFireKey(keyCode: Int): Boolean =
            keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A
}

Java

public class GameView extends View {
    ...

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        boolean handled = false;
        if ((event.getSource() & InputDevice.SOURCE_GAMEPAD)
                == InputDevice.SOURCE_GAMEPAD) {
            if (event.getRepeatCount() == 0) {
                switch (keyCode) {
                    // Handle gamepad and D-pad button presses to
                    // navigate the ship
                    ...

                    default:
                         if (isFireKey(keyCode)) {
                             // Update the ship object to fire lasers
                             ...
                             handled = true;
                         }
                     break;
                }
            }
            if (handled) {
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    private static boolean isFireKey(int keyCode) {
        // Here we treat Button_A and DPAD_CENTER as the primary action
        // keys for the game.
        return keyCode == KeyEvent.KEYCODE_DPAD_CENTER
                || keyCode == KeyEvent.KEYCODE_BUTTON_A;
    }
}

Not: Android 4.2 (API düzeyi 17) ve önceki sürümlerde sistem BUTTON_A adlı cihazı varsayılan olarak Android Geri tuşu olarak değerlendirir. Uygulamanız bu Android sürümlerini destekliyorsa BUTTON_A oyununu birincil oyun işlemi olarak değerlendirdiğinizden emin olun. Cihazdaki geçerli Android SDK sürümünü belirlemek için Build.VERSION.SDK_INT değerine bakın.

İşlem yön tuşları girişi

4 yönlü yön tuşları (D-pad), birçok oyun denetleyicisinde yaygın olarak kullanılan bir fiziksel kontroldür. Android, D-pad'e YUKARI ve AŞAĞI basmaları -1,0 (yukarı) ile 1,0 (aşağı) aralığında AXIS_HAT_Y etkinlikleri olarak ve D-pad SOL veya SAĞ tuşuna 1,0 (sol) ile 1,0 (sağ) aralığında AXIS_HAT_X etkinlikleri olarak bastığında bildirir.

Bunun yerine bazı kumandalar D-pad'e basıldığında bir tuş koduyla işlem yapıldığını bildirir. Oyununuz D-pad'e basmayı önemsiyorsa şapka ekseni etkinliklerini ve D-pad tuş kodlarını tablo 2'de önerildiği şekilde aynı giriş etkinlikleri olarak işlemeniz gerekir.

Tablo 2. D-pad tuş kodları ve şapka ekseni değerleri için önerilen varsayılan oyun işlemleri.

Oyun Aksiyon D-pad Tuş Kodu Şapka Eksen Kodu
Yukarı Taşı KEYCODE_DPAD_UP AXIS_HAT_Y (0 ile -1,0 arasındaki değerler için)
Aşağı Taşı KEYCODE_DPAD_DOWN AXIS_HAT_Y (0-1,0 arasındaki değerler için)
Sola Taşı KEYCODE_DPAD_LEFT AXIS_HAT_X (0 ile -1,0 arasındaki değerler için)
Sağa Taşı KEYCODE_DPAD_RIGHT AXIS_HAT_X (0-1,0 arasındaki değerler için)

Aşağıdaki kod snippet'inde, D-pad yönünü belirlemek için bir giriş etkinliğindeki şapka eksenini ve anahtar kodu değerlerini kontrol etmenizi sağlayan bir yardımcı sınıf gösterilmektedir.

Kotlin

class Dpad {

    private var directionPressed = -1 // initialized to -1

    fun getDirectionPressed(event: InputEvent): Int {
        if (!isDpadDevice(event)) {
            return -1
        }

        // If the input event is a MotionEvent, check its hat axis values.
        (event as? MotionEvent)?.apply {

            // Use the hat axis value to find the D-pad direction
            val xaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_X)
            val yaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_Y)

            directionPressed = when {
                // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
                // LEFT and RIGHT direction accordingly.
                xaxis.compareTo(-1.0f) == 0 -> Dpad.LEFT
                xaxis.compareTo(1.0f) == 0 -> Dpad.RIGHT
                // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
                // UP and DOWN direction accordingly.
                yaxis.compareTo(-1.0f) == 0 -> Dpad.UP
                yaxis.compareTo(1.0f) == 0 -> Dpad.DOWN
                else -> directionPressed
            }
        }
        // If the input event is a KeyEvent, check its key code.
        (event as? KeyEvent)?.apply {

            // Use the key code to find the D-pad direction.
            directionPressed = when(event.keyCode) {
                KeyEvent.KEYCODE_DPAD_LEFT -> Dpad.LEFT
                KeyEvent.KEYCODE_DPAD_RIGHT -> Dpad.RIGHT
                KeyEvent.KEYCODE_DPAD_UP -> Dpad.UP
                KeyEvent.KEYCODE_DPAD_DOWN -> Dpad.DOWN
                KeyEvent.KEYCODE_DPAD_CENTER ->  Dpad.CENTER
                else -> directionPressed
            }
        }
        return directionPressed
    }

    companion object {
        internal const val UP = 0
        internal const val LEFT = 1
        internal const val RIGHT = 2
        internal const val DOWN = 3
        internal const val CENTER = 4

        fun isDpadDevice(event: InputEvent): Boolean =
            // Check that input comes from a device with directional pads.
            event.source and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD
    }
}

Java

public class Dpad {
    final static int UP       = 0;
    final static int LEFT     = 1;
    final static int RIGHT    = 2;
    final static int DOWN     = 3;
    final static int CENTER   = 4;

    int directionPressed = -1; // initialized to -1

    public int getDirectionPressed(InputEvent event) {
        if (!isDpadDevice(event)) {
           return -1;
        }

        // If the input event is a MotionEvent, check its hat axis values.
        if (event instanceof MotionEvent) {

            // Use the hat axis value to find the D-pad direction
            MotionEvent motionEvent = (MotionEvent) event;
            float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
            float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);

            // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
            // LEFT and RIGHT direction accordingly.
            if (Float.compare(xaxis, -1.0f) == 0) {
                directionPressed =  Dpad.LEFT;
            } else if (Float.compare(xaxis, 1.0f) == 0) {
                directionPressed =  Dpad.RIGHT;
            }
            // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
            // UP and DOWN direction accordingly.
            else if (Float.compare(yaxis, -1.0f) == 0) {
                directionPressed =  Dpad.UP;
            } else if (Float.compare(yaxis, 1.0f) == 0) {
                directionPressed =  Dpad.DOWN;
            }
        }

        // If the input event is a KeyEvent, check its key code.
        else if (event instanceof KeyEvent) {

           // Use the key code to find the D-pad direction.
            KeyEvent keyEvent = (KeyEvent) event;
            if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
                directionPressed = Dpad.LEFT;
            } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
                directionPressed = Dpad.RIGHT;
            } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
                directionPressed = Dpad.UP;
            } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
                directionPressed = Dpad.DOWN;
            } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
                directionPressed = Dpad.CENTER;
            }
        }
        return directionPressed;
    }

    public static boolean isDpadDevice(InputEvent event) {
        // Check that input comes from a device with directional pads.
        if ((event.getSource() & InputDevice.SOURCE_DPAD)
             != InputDevice.SOURCE_DPAD) {
             return true;
         } else {
             return false;
         }
     }
}

Bu yardımcı sınıfı, oyununuzda D-pad girişini işlemek istediğiniz her yerde kullanabilirsiniz (örneğin, onGenericMotionEvent() veya onKeyDown() geri çağırmalarında).

Örneğin:

Kotlin

private val dpad = Dpad()
...
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
    if (Dpad.isDpadDevice(event)) {
        when (dpad.getDirectionPressed(event)) {
            Dpad.LEFT -> {
                // Do something for LEFT direction press
                ...
                return true
            }
            Dpad.RIGHT -> {
                // Do something for RIGHT direction press
                ...
                return true
            }
            Dpad.UP -> {
                // Do something for UP direction press
                ...
                return true
            }
            ...
        }
    }

    // Check if this event is from a joystick movement and process accordingly.
    ...
}

Java

Dpad dpad = new Dpad();
...
@Override
public boolean onGenericMotionEvent(MotionEvent event) {

    // Check if this event if from a D-pad and process accordingly.
    if (Dpad.isDpadDevice(event)) {

       int press = dpad.getDirectionPressed(event);
       switch (press) {
            case LEFT:
                // Do something for LEFT direction press
                ...
                return true;
            case RIGHT:
                // Do something for RIGHT direction press
                ...
                return true;
            case UP:
                // Do something for UP direction press
                ...
                return true;
            ...
        }
    }

    // Check if this event is from a joystick movement and process accordingly.
    ...
}

Kontrol çubuğu hareketlerini işleyin

Oyuncular oyun kumandalarında kontrol çubuğunu hareket ettirdiklerinde Android, ACTION_MOVE işlem kodunu ve kontrol çubuğunun eksenlerinin güncellenmiş konumlarını içeren bir MotionEvent bildirir. Oyununuz, kontrol çubuğu hareketinin yaşanmış olup olmadığını belirlemek için MotionEvent tarafından sağlanan verileri kullanabilir.

Kontrol çubuğu hareketi etkinliklerinin tek bir nesne içinde birden fazla hareket örneğini toplu olarak oluşturabileceğini unutmayın. MotionEvent nesnesi, her kontrol çubuğu ekseni için geçerli konumun yanı sıra her eksen için birden çok geçmiş konumu içerir. Android, hareket etkinliklerini ACTION_MOVE işlem koduyla raporlarken (kontrol çubuğu hareketleri gibi) verimlilik için eksen değerlerini toplu olarak işler. Bir eksenin geçmiş değerleri, mevcut eksen değerinden daha eski ve önceki hareket etkinliklerinde bildirilen değerlerden daha yeni olan farklı değerlerden oluşur. Ayrıntılar için MotionEvent referansına bakın.

Kontrol çubuğu girişine göre bir oyun nesnesinin hareketini daha doğru bir şekilde oluşturmak için geçmiş bilgileri kullanabilirsiniz. Geçerli ve geçmiş değerleri almak için getAxisValue() veya getHistoricalAxisValue() çağrısı yapın. Ayrıca, getHistorySize() çağrısı yaparak kontrol çubuğu etkinliğindeki geçmiş noktaların sayısını da bulabilirsiniz.

Aşağıdaki snippet'te, kontrol çubuğu girişini işlemek için onGenericMotionEvent() geri çağırmasını nasıl geçersiz kılabileceğiniz gösterilmektedir. Önce bir eksenin geçmiş değerlerini işlemeniz, ardından mevcut konumunu işlemeniz gerekir.

Kotlin

class GameView(...) : View(...) {

    override fun onGenericMotionEvent(event: MotionEvent): Boolean {

        // Check that the event came from a game controller
        return if (event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK
                && event.action == MotionEvent.ACTION_MOVE) {

            // Process the movements starting from the
            // earliest historical position in the batch
            (0 until event.historySize).forEach { i ->
                // Process the event at historical position i
                processJoystickInput(event, i)
            }

            // Process the current movement sample in the batch (position -1)
            processJoystickInput(event, -1)
            true
        } else {
            super.onGenericMotionEvent(event)
        }
    }
}

Java

public class GameView extends View {

    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {

        // Check that the event came from a game controller
        if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) ==
                InputDevice.SOURCE_JOYSTICK &&
                event.getAction() == MotionEvent.ACTION_MOVE) {

            // Process all historical movement samples in the batch
            final int historySize = event.getHistorySize();

            // Process the movements starting from the
            // earliest historical position in the batch
            for (int i = 0; i < historySize; i++) {
                // Process the event at historical position i
                processJoystickInput(event, i);
            }

            // Process the current movement sample in the batch (position -1)
            processJoystickInput(event, -1);
            return true;
        }
        return super.onGenericMotionEvent(event);
    }
}

Kontrol çubuğu girişini kullanmadan önce, kontrol çubuğunun ortalanıp ortalanmadığını belirlemeniz ve eksen hareketlerini buna göre hesaplamanız gerekir. Kontrol çubukları genellikle düz bir alana, yani eksenin ortalandığı kabul edilen (0,0) koordinatına yakın bir değer aralığına sahiptir. Android tarafından bildirilen eksen değeri düz alana denk geliyorsa kumandayı hareketsiz (yani her iki eksende hareketsiz) olarak ele almanız gerekir.

Aşağıdaki snippet'te, her bir eksendeki hareketi hesaplayan bir yardımcı yöntem gösterilmektedir. Bu yardımcıyı aşağıda ayrıntılı olarak açıklanan processJoystickInput() yöntemiyle çağırırsınız.

Kotlin

private fun getCenteredAxis(
        event: MotionEvent,
        device: InputDevice,
        axis: Int,
        historyPos: Int
): Float {
    val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source)

    // A joystick at rest does not always report an absolute position of
    // (0,0). Use the getFlat() method to determine the range of values
    // bounding the joystick axis center.
    range?.apply {
        val value: Float = if (historyPos < 0) {
            event.getAxisValue(axis)
        } else {
            event.getHistoricalAxisValue(axis, historyPos)
        }

        // Ignore axis values that are within the 'flat' region of the
        // joystick axis center.
        if (Math.abs(value) > flat) {
            return value
        }
    }
    return 0f
}

Java

private static float getCenteredAxis(MotionEvent event,
        InputDevice device, int axis, int historyPos) {
    final InputDevice.MotionRange range =
            device.getMotionRange(axis, event.getSource());

    // A joystick at rest does not always report an absolute position of
    // (0,0). Use the getFlat() method to determine the range of values
    // bounding the joystick axis center.
    if (range != null) {
        final float flat = range.getFlat();
        final float value =
                historyPos < 0 ? event.getAxisValue(axis):
                event.getHistoricalAxisValue(axis, historyPos);

        // Ignore axis values that are within the 'flat' region of the
        // joystick axis center.
        if (Math.abs(value) > flat) {
            return value;
        }
    }
    return 0;
}

Tüm bunları bir araya getirdiğimizde, oyununuzda kontrol çubuğu hareketlerini şu şekilde işleyebilirsiniz:

Kotlin

private fun processJoystickInput(event: MotionEvent, historyPos: Int) {

    val inputDevice = event.device

    // Calculate the horizontal distance to move by
    // using the input value from one of these physical controls:
    // the left control stick, hat axis, or the right control stick.
    var x: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos)
    if (x == 0f) {
        x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos)
    }
    if (x == 0f) {
        x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos)
    }

    // Calculate the vertical distance to move by
    // using the input value from one of these physical controls:
    // the left control stick, hat switch, or the right control stick.
    var y: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos)
    if (y == 0f) {
        y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos)
    }
    if (y == 0f) {
        y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos)
    }

    // Update the ship object based on the new x and y values
}

Java

private void processJoystickInput(MotionEvent event,
        int historyPos) {

    InputDevice inputDevice = event.getDevice();

    // Calculate the horizontal distance to move by
    // using the input value from one of these physical controls:
    // the left control stick, hat axis, or the right control stick.
    float x = getCenteredAxis(event, inputDevice,
            MotionEvent.AXIS_X, historyPos);
    if (x == 0) {
        x = getCenteredAxis(event, inputDevice,
                MotionEvent.AXIS_HAT_X, historyPos);
    }
    if (x == 0) {
        x = getCenteredAxis(event, inputDevice,
                MotionEvent.AXIS_Z, historyPos);
    }

    // Calculate the vertical distance to move by
    // using the input value from one of these physical controls:
    // the left control stick, hat switch, or the right control stick.
    float y = getCenteredAxis(event, inputDevice,
            MotionEvent.AXIS_Y, historyPos);
    if (y == 0) {
        y = getCenteredAxis(event, inputDevice,
                MotionEvent.AXIS_HAT_Y, historyPos);
    }
    if (y == 0) {
        y = getCenteredAxis(event, inputDevice,
                MotionEvent.AXIS_RZ, historyPos);
    }

    // Update the ship object based on the new x and y values
}

Tek bir kontrol çubuğunun ötesinde daha gelişmiş özelliklere sahip oyun kumandalarını desteklemek için aşağıdaki en iyi uygulamaları izleyin:

  • Çift kumanda çubuğunu kullanın. Çoğu oyun kumandasında hem sol hem sağ kontrol çubuğu vardır. Android, sol çubuk için yatay hareketleri AXIS_X etkinlik, dikey hareketleri ise AXIS_Y etkinlik olarak raporlar. Android, sağ çubuk için yatay hareketleri AXIS_Z etkinliği, dikey hareketleri ise AXIS_RZ etkinlik olarak raporlar. Kodunuzda her iki kumanda çubuğunu da işlemeyi unutmayın.
  • Omuz tetikleyicisi basmalarını işleme (ancak alternatif giriş yöntemleri sağlayın). Bazı kumandalarda sol ve sağ omuz tetikleyicileri bulunur. Bu tetikleyiciler mevcutsa Android, sol tetikleyici basımını AXIS_LTRIGGER etkinliği olarak ve sağ tetikleyici basışını AXIS_RTRIGGER etkinliği olarak bildirir. Android 4.3'te (API düzeyi 18) AXIS_LTRIGGER üreten bir denetleyici, AXIS_BRAKE ekseni için de aynı değeri bildirir. Aynı durum AXIS_RTRIGGER ve AXIS_GAS için de geçerlidir. Android, 0,0 (yayınlandı) ile 1,0 (tam olarak basıldı) arasında normalleştirilmiş bir değerle tüm analog tetikleyici basımlarını bildirir. Tüm kumandalarda tetikleyici yoktur, bu nedenle oyuncuların bu oyun işlemlerini diğer düğmelerle gerçekleştirmesine izin vermeyi düşünün.