Input mouse

Topik ini membahas cara menerapkan input mouse untuk Google Play Game di PC bagi game yang mode terjemahan inputnya tidak memberikan pengalaman pemain yang ideal.

Pemain PC biasanya memiliki keyboard dan mouse, bukan layar sentuh, sehingga penting untuk mempertimbangkan apakah game Anda mengakomodasi input mouse. Secara default, Google Play Game di PC mengonversi peristiwa mouse klik kiri menjadi satu peristiwa ketuk virtual. Hal ini dikenal sebagai "mode terjemahan input".

Meskipun membuat game berfungsi dengan beberapa perubahan, mode ini tidak memberikan pengalaman game native kepada pemain PC. Untuk itu, sebaiknya Anda mengimplementasikan hal berikut:

  • Status arahkan kursor untuk menu konteks, bukan tindakan tekan dan tahan
  • Klik kanan untuk tindakan alternatif yang dilakukan dengan menekan lama atau di menu konteks
  • Mouselook untuk game aksi orang pertama atau ketiga, bukan peristiwa tekan dan tarik

Untuk mendukung pola UI yang umum di PC, Anda harus menonaktifkan mode terjemahan input.

Penanganan input untuk Google Play Game di PC identik dengan ChromeOS. Perubahan yang mendukung PC juga meningkatkan kualitas game Anda untuk semua pemain Android.

Menonaktifkan mode terjemahan input

Dalam file AndroidManifest.xml, deklarasikan fitur android.hardware.type.pc. Tindakan ini menunjukkan bahwa game Anda menggunakan hardware PC dan menonaktifkan mode terjemahan input. Selain itu, menambahkan required="false" akan membantu memastikan bahwa game Anda masih dapat diinstal di ponsel dan tablet tanpa mouse. Contoh:

<manifest ...>
  <uses-feature
      android:name="android.hardware.type.pc"
      android:required="false" />
  ...
</manifest>

Versi produksi Google Play Game di PC beralih ke mode yang benar saat game diluncurkan. Saat berjalan di emulator developer, Anda harus mengklik kanan ikon taskbar, memilih Developer Options, lalu PC mode(KiwiMouse) untuk menerima input mouse raw.

Screenshot &quot;PC mode(KiwiMouse)&quot; yang dipilih di menu konteks

Setelah Anda melakukannya, gerakan mouse dilaporkan oleh View.onGenericMotionEvent dengan sumber SOURCE_MOUSE yang menunjukkan bahwa peristiwa tersebut adalah peristiwa mouse.

Kotlin

gameView.setOnGenericMotionListener { _, motionEvent ->
    var handled = false
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // handle the mouse event here
        handled = true
    }
    handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // handle the mouse event here
        return true;
    }
    return false;
});

Untuk mengetahui detail tentang cara menangani input mouse, lihat dokumentasi ChromeOS.

Menangani gerakan mouse

Untuk mendeteksi gerakan mouse, proses peristiwa ACTION_HOVER_ENTER, ACTION_HOVER_EXIT, dan ACTION_HOVER_MOVE.

Cara ini paling baik digunakan untuk mendeteksi pengguna yang mengarahkan kursor ke tombol atau objek dalam game, yang memberi Anda kesempatan untuk menampilkan kotak petunjuk atau menerapkan status pengarahan mouse untuk menyoroti pilihan yang akan dipilih pemain. Contoh:

Kotlin

gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when(motionEvent.action) {
           MotionEvent.ACTION_HOVER_ENTER -> Log.d("MA", "Mouse entered at ${motionEvent.x}, ${motionEvent.y}")
           MotionEvent.ACTION_HOVER_EXIT -> Log.d("MA", "Mouse exited at ${motionEvent.x}, ${motionEvent.y}")
           MotionEvent.ACTION_HOVER_MOVE -> Log.d("MA", "Mouse hovered at ${motionEvent.x}, ${motionEvent.y}")
       }
       handled = true
   }

   handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_HOVER_ENTER:
                Log.d("MA", "Mouse entered at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_HOVER_EXIT:
                Log.d("MA", "Mouse exited at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_HOVER_MOVE:
                Log.d("MA", "Mouse hovered at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
        }
        return true;
    }
    return false;
});

Menangani tombol mouse

PC memiliki tombol mouse kiri dan kanan, yang memberikan elemen interaktif baik tindakan utama maupun sekunder. Dalam game, tindakan ketuk seperti mengetuk tombol akan paling baik dipetakan untuk klik kiri dan tindakan sentuh lama akan terasa paling alami dengan klik kanan. Dalam game strategi real-time, Anda juga dapat menggunakan klik kiri untuk memilih dan klik kanan untuk bergerak. First person shooter mungkin menetapkan tugas tembak utama dan sekunder ke klik kiri dan kanan. Infinite runner dapat menggunakan klik kiri untuk melompat dan klik kanan untuk berlari. Kami belum menambahkan dukungan untuk peristiwa klik tengah.

Untuk menangani penekanan tombol, gunakan ACTION_DOWN dan ACTION_UP. Selanjutnya, gunakan getActionButton untuk menentukan tombol mana yang memicu tindakan atau getButtonState untuk mendapatkan status semua tombol.

Dalam contoh ini, enum digunakan untuk membantu menampilkan hasil getActionButton:

Kotlin

enum class MouseButton {
   LEFT,
   RIGHT,
   UNKNOWN;
   companion object {
       fun fromMotionEvent(motionEvent: MotionEvent): MouseButton {
           return when (motionEvent.actionButton) {
               MotionEvent.BUTTON_PRIMARY -> LEFT
               MotionEvent.BUTTON_SECONDARY -> RIGHT
               else -> UNKNOWN
           }
       }
   }
}

Java

enum MouseButton {
    LEFT,
    RIGHT,
    MIDDLE,
    UNKNOWN;
    static MouseButton fromMotionEvent(MotionEvent motionEvent) {
        switch (motionEvent.getActionButton()) {
            case MotionEvent.BUTTON_PRIMARY:
                return MouseButton.LEFT;
            case MotionEvent.BUTTON_SECONDARY:
                return MouseButton.RIGHT;
            default:
                return MouseButton.UNKNOWN;
        }
    }
}

Dalam contoh ini, tindakan ditangani mirip dengan peristiwa arahkan kursor:

Kotlin

// Handle the generic motion event
gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when (motionEvent.action) {
           MotionEvent.ACTION_BUTTON_PRESS -> Log.d(
               "MA",
               "${MouseButton.fromMotionEvent(motionEvent)} pressed at ${motionEvent.x}, ${motionEvent.y}"
           )
           MotionEvent.ACTION_BUTTON_RELEASE -> Log.d(
               "MA",
               "${MouseButton.fromMotionEvent(motionEvent)} released at ${motionEvent.x}, ${motionEvent.y}"
           )
       }
       handled = true
   }

   handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_BUTTON_PRESS:
                Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " pressed at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_BUTTON_RELEASE:
                Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " released at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
        }
        return true;
    }
    return false;
});

Menangani scrolling roda mouse

Sebaiknya gunakan roda scroll mouse sebagai ganti gestur cubit untuk memperbesar atau sentuh dan tarik area scroll dalam game Anda.

Untuk membaca nilai roda scroll, proses peristiwa ACTION_SCROLL. Delta sejak frame terakhir dapat diambil menggunakan getAxisValue dengan AXIS_VSCROLL untuk offset vertikal dan AXIS_HSCROLL untuk offset horizontal. Contoh:

Kotlin

gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when (motionEvent.action) {
           MotionEvent.ACTION_SCROLL -> {
               val scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL)
               val scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL)
               Log.d("MA", "Mouse scrolled $scrollX, $scrollY")
           }
       }
       handled = true
   }
   handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_SCROLL:
                float scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL);
                float scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL);
                Log.d("MA", "Mouse scrolled " + scrollX + ", " + scrollY);
                break;
        }
        return true;
    }
    return false;
});

Merekam input mouse

Beberapa game perlu sepenuhnya mengontrol kursor mouse seperti game aksi orang pertama atau ketiga yang memetakan gerakan mouse ke gerakan kamera. Untuk mengambil kontrol eksklusif mouse, panggil View.requestPointerCapture().

requestPointerCapture() hanya berfungsi saat hierarki tampilan yang berisi tampilan Anda memiliki fokus. Karena alasan ini, Anda tidak dapat memperoleh rekaman kursor di callback onCreate. Anda harus menunggu interaksi pemain untuk merekam kursor mouse, seperti saat berinteraksi dengan menu utama, atau menggunakan callback onWindowFocusChanged. Contoh:

Kotlin

override fun onWindowFocusChanged(hasFocus: Boolean) {
   super.onWindowFocusChanged(hasFocus)

   if (hasFocus) {
       gameView.requestPointerCapture()
   }
}

Java

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    if (hasFocus) {
        View gameView = findViewById(R.id.game_view);
        gameView.requestPointerCapture();
    }
}

Peristiwa yang ditangkap oleh requestPointerCapture() akan dikirim ke tampilan yang dapat difokuskan yang mendaftarkan OnCapturedPointerListener. Contoh:

Kotlin

gameView.focusable = View.FOCUSABLE
gameView.setOnCapturedPointerListener { _, motionEvent ->
    Log.d("MA", "${motionEvent.x}, ${motionEvent.y}, ${motionEvent.actionButton}")
    true
}

Java

gameView.setFocusable(true);
gameView.setOnCapturedPointerListener((view, motionEvent) -> {
    Log.d("MA", motionEvent.getX() + ", " + motionEvent.getY() + ", " + motionEvent.getActionButton());
    return true;
});

Untuk merilis rekaman mouse eksklusif, seperti mengizinkan pemain berinteraksi dengan menu jeda, panggil View.releasePointerCapture().