Pada tingkat sistem, Android melaporkan kode peristiwa input dari pengontrol game sebagai kode tombol Android dan nilai sumbu. Dalam game, Anda dapat menerima kode dan nilai ini, kemudian mengonversinya menjadi tindakan spesifik dalam game.
Saat pemain terhubung secara fisik atau menyambungkan secara nirkabel pengontrol game ke
perangkat Android, sistem akan otomatis mendeteksi pengontrol tersebut
sebagai perangkat input dan mulai melaporkan peristiwa inputnya. Game Anda dapat menerima
peristiwa input ini dengan mengimplementasikan metode callback berikut di
Activity
aktif atau View
yang difokuskan (Anda harus
mengimplementasikan callback untuk Activity
atau
View
, tetapi tidak keduanya):
- Dari
Activity
:dispatchGenericMotionEvent(android.view. MotionEvent)
Dipanggil untuk memproses peristiwa gerakan umum seperti pergerakan joystick.
dispatchKeyEvent(android.view.KeyEvent)
Dipanggil untuk memproses peristiwa tombol seperti penekanan atau pelepasan tombol D-pad atau gamepad.
- Dari
View
:onGenericMotionEvent(android.view.MotionEvent)
Dipanggil untuk memproses peristiwa gerakan umum seperti pergerakan joystick.
onKeyDown(int, android.view.KeyEvent)
Dipanggil untuk memproses penekanan tombol fisik seperti tombol D-pad atau gamepad.
onKeyUp(int, android.view.KeyEvent)
Dipanggil untuk memproses pelepasan tombol fisik seperti tombol D-pad atau gamepad.
Pendekatan yang direkomendasikan adalah mencatat peristiwa dari objek View
tertentu yang berinteraksi dengan pengguna.
Periksa objek berikut yang diberikan oleh callback untuk mendapatkan informasi
tentang jenis peristiwa input yang diterima:
KeyEvent
- Objek yang mendeskripsikan peristiwa tombol
arah (D-pad) dan tombol gamepad. Peristiwa tombol disertai dengan
kode tombol yang menunjukkan tombol tertentu yang dipicu, seperti
DPAD_DOWN
atauBUTTON_A
. Anda bisa mendapatkan kode kunci dengan memanggilgetKeyCode()
atau dari callback peristiwa kunci sepertionKeyDown()
. MotionEvent
- Objek yang mendeskripsikan input dari joystick dan gerakan
bahu. Peristiwa gerakan disertai dengan kode tindakan dan serangkaian
nilai sumbu. Kode tindakan menentukan perubahan status yang terjadi
seperti joystick digerakkan. Nilai sumbu mendeskripsikan posisi dan properti
gerakan lain untuk kontrol fisik tertentu, seperti
AXIS_X
atauAXIS_RTRIGGER
. Anda bisa mendapatkan kode tindakan dengan memanggilgetAction()
dan nilai sumbu dengan memanggilgetAxisValue()
.
Tutorial ini berfokus pada cara Anda dapat menangani input dari jenis kontrol fisik yang paling umum (tombol gamepad, tombol arah, dan joystick) dalam layar game dengan mengimplementasikan metode callback View
yang disebutkan di atas dan memproses objek KeyEvent
dan MotionEvent
.
Memverifikasi bahwa pengontrol game telah tersambung
Saat melaporkan peristiwa input, Android tidak membedakan
antara peristiwa yang berasal dari perangkat yang bukan pengontrol game dan peristiwa yang berasal
dari pengontrol game. Misalnya, tindakan layar sentuh menghasilkan
peristiwa AXIS_X
yang mewakili koordinat
X permukaan sentuh, tetapi joystick menghasilkan
peristiwa AXIS_X
yang mewakili posisi X joystick. Jika
game Anda peduli dengan penanganan input pengontrol game, Anda harus terlebih dahulu memeriksa
bahwa peristiwa input berasal dari jenis sumber yang relevan.
Untuk memverifikasi bahwa perangkat input yang terhubung adalah pengontrol game, panggil
getSources()
untuk mendapatkan kolom bit gabungan dari
jenis sumber input yang didukung di perangkat tersebut. Selanjutnya, Anda dapat menguji apakah kolom berikut telah ditetapkan:
- Jenis sumber
SOURCE_GAMEPAD
menunjukkan bahwa perangkat input memiliki tombol gamepad (misalnya,BUTTON_A
). Perlu diperhatikan bahwa jenis sumber ini tidak hanya menunjukkan jika pengontrol game memiliki tombol D-pad, meskipun sebagian besar gamepad biasanya memiliki tombol arah. - Jenis sumber
SOURCE_DPAD
menunjukkan bahwa perangkat input memiliki tombol D-pad (misalnya,DPAD_UP
). - Jenis sumber
SOURCE_JOYSTICK
menunjukkan bahwa perangkat input memiliki stick kontrol analog (misalnya, joystick yang merekam gerakan di sepanjangAXIS_X
danAXIS_Y
).
Cuplikan kode berikut menunjukkan metode helper yang memungkinkan Anda memeriksa apakah perangkat input yang terhubung adalah pengontrol game. Jika ya, metode tersebut akan mengambil ID perangkat untuk pengontrol game. Kemudian, Anda dapat mengaitkan setiap ID perangkat dengan pemain di game Anda, dan memproses tindakan game untuk setiap pemain yang terhubung secara terpisah. Untuk mempelajari lebih lanjut cara mendukung beberapa pengontrol game yang secara bersamaan tersambung di perangkat Android yang sama, lihat Mendukung beberapa pengontrol game.
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; }
Selain itu, sebaiknya periksa setiap kemampuan input yang didukung oleh pengontrol game terhubung. Hal ini mungkin berguna, misalnya, jika Anda ingin game hanya menggunakan input dari serangkaian kontrol fisik yang dipahaminya.
Untuk mendeteksi apakah kode tombol atau kode sumbu tertentu didukung oleh pengontrol game yang tersambung, gunakan teknik ini:
- Di Android 4.4 (API level 19) atau yang lebih tinggi, Anda dapat menentukan apakah kode tombol
didukung pada pengontrol game yang tersambung dengan memanggil
hasKeys(int...)
. - Di Android 3.1 (API level 12) atau yang lebih tinggi, Anda dapat menemukan semua sumbu tersedia
yang didukung oleh pengontrol game tersambung dengan memanggil
getMotionRanges()
terlebih dahulu. Kemudian, pada setiap objekInputDevice.MotionRange
yang ditampilkan, panggilgetAxis()
untuk mendapatkan ID sumbunya.
Memproses penekanan pada tombol gamepad
Gambar 1 menunjukkan cara Android memetakan kode tombol dan nilai sumbu ke kontrol fisik di sebagian besar pengontrol game.
Info dalam gambar tersebut merujuk pada yang berikut ini:
Kode tombol umum yang dihasilkan oleh penekanan tombol gamepad mencakup
BUTTON_A
,
BUTTON_B
,
BUTTON_SELECT
,
dan BUTTON_START
. Beberapa pengontrol
game juga memicu kode tombol DPAD_CENTER
saat bagian tengah crossbar D-pad ditekan. Game
Anda dapat memeriksa kode tombol dengan memanggil getKeyCode()
atau dari callback peristiwa tombol seperti
onKeyDown()
,
dan jika kode tombol mewakili peristiwa yang relevan bagi game Anda, prosesnya sebagai
tindakan game. Tabel 1 mencantumkan tindakan game yang direkomendasikan untuk tombol gamepad
yang paling umum.
Tindakan Game | Kode Tombol |
---|---|
Memulai game di menu utama, atau menjeda/melanjutkan selama game | BUTTON_START * |
Menu tampilan | BUTTON_SELECT *
dan KEYCODE_MENU * |
Sama seperti perilaku navigasi Back Android yang dijelaskan dalam panduan desain Navigation. | KEYCODE_BACK |
Kembali ke item sebelumnya di menu | BUTTON_B |
Mengonfirmasi pilihan, atau melakukan tindakan game utama | BUTTON_A dan
DPAD_CENTER |
* Game Anda tidak boleh bergantung pada keberadaan tombol Start, Select, atau Menu.
Tips: Pertimbangkan untuk menyediakan layar konfigurasi di game Anda agar pengguna dapat mempersonalisasi pemetaan pengontrol game mereka sendiri untuk tindakan game.
Cuplikan berikut menunjukkan cara mengganti
onKeyDown()
untuk
mengaitkan penekanan tombol BUTTON_A
dan
DPAD_CENTER
dengan tindakan game.
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; } }
Catatan: Di Android 4.2 (API
level 17) dan yang lebih rendah, sistem memperlakukan
BUTTON_A
sebagai tombol
Back Android secara default. Jika aplikasi Anda mendukung versi
Android ini, pastikan untuk memperlakukan
BUTTON_A
sebagai tindakan
game utama. Untuk menentukan versi Android SDK
saat ini di perangkat, lihat
nilai Build.VERSION.SDK_INT
.
Memproses input tombol arah
Tombol 4 arah (D-pad) merupakan kontrol fisik yang umum di banyak pengontrol
game. Android melaporkan penekanan D-pad ATAS dan BAWAH sebagai
peristiwa AXIS_HAT_Y
dengan rentang
dari -1.0 (atas) hingga 1.0 (bawah), dan penekanan D-pad KIRI atau KANAN sebagai
peristiwa AXIS_HAT_X
dengan rentang dari -1.0
(kiri) hingga 1.0 (kanan).
Namun, beberapa pengontrol melaporkan penekanan D-pad dengan kode tombol. Jika game Anda memperhatikan penekanan D-pad, Anda harus memperlakukan peristiwa sumbu hat dan kode tombol D-pad sebagai peristiwa input yang sama, seperti yang direkomendasikan di tabel 2.
Tindakan Game | Kode Tombol D-pad | Kode Sumbu Hat |
---|---|---|
Naikkan | KEYCODE_DPAD_UP |
AXIS_HAT_Y (untuk nilai 0 hingga -1,0) |
Turunkan | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (untuk nilai 0 hingga 1,0) |
Pindahkan ke Kiri | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (untuk nilai 0 hingga -1,0) |
Pindahkan ke Kanan | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (untuk nilai 0 hingga 1,0) |
Cuplikan kode berikut menunjukkan class helper yang memungkinkan Anda memeriksa nilai kode tombol dan sumbu hat dari peristiwa input untuk menentukan arah D-pad.
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; } } }
Anda dapat menggunakan class helper ini di game Anda kapan pun Anda ingin memproses
input D-pad (misalnya, di
callback
onGenericMotionEvent()
atau
onKeyDown()
).
Contoh:
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. ... }
Memproses pergerakan joystick
Saat pemain menggerakkan joystick di pengontrol game mereka, Android melaporkan
MotionEvent
yang berisi
kode tindakan ACTION_MOVE
dan posisi
sumbu joystick yang diperbarui. Game Anda dapat menggunakan data yang disediakan oleh
MotionEvent
untuk menentukan apakah pergerakan joystick
yang dipedulikan terjadi.
Perlu diketahui bahwa peristiwa gerakan joystick dapat mengelompokkan beberapa sampel gerakan bersama
dalam satu objek. Objek MotionEvent
berisi
posisi saat ini untuk setiap sumbu joystick serta beberapa posisi historis
untuk setiap sumbu. Saat melaporkan peristiwa gerakan dengan kode tindakan ACTION_MOVE
(seperti gerakan joystick), Android akan mengelompokkan
nilai sumbu demi efisiensi. Nilai historis untuk sumbu terdiri dari
kumpulan nilai yang berbeda yang lebih lama dari nilai sumbu saat ini, dan lebih baru dari
nilai yang dilaporkan dalam peristiwa gerakan sebelumnya. Lihat
referensi MotionEvent
untuk mengetahui detailnya.
Anda dapat menggunakan informasi historis untuk merender pergerakan objek
game berdasarkan input joystick secara lebih akurat. Untuk
mengambil nilai saat ini dan nilai historis, panggil
getAxisValue()
atau getHistoricalAxisValue()
. Anda juga dapat menemukan jumlah titik historis
dalam peristiwa joystick dengan memanggil
getHistorySize()
.
Cuplikan berikut menunjukkan cara mengganti
callback onGenericMotionEvent()
untuk memproses input joystick. Anda harus terlebih dahulu
memproses nilai historis untuk sumbu, lalu memproses posisinya saat ini.
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); } }
Sebelum menggunakan input joystick, Anda perlu menentukan apakah joystick terpusat, kemudian menghitung pergerakan sumbunya berdasarkan informasi tersebut. Joystick biasanya memiliki area datar, yaitu, rentang nilai yang dekat dengan koordinat (0,0) tempat sumbu dianggap terpusat. Jika nilai sumbu yang dilaporkan oleh Android berada dalam area datar, Anda harus memperlakukan pengontrol agar diistirahatkan (yaitu, tidak bergerak di sepanjang kedua sumbu).
Cuplikan di bawah menunjukkan metode helper yang menghitung pergerakan di sepanjang
setiap sumbu. Anda memanggil helper ini di metode processJoystickInput()
yang dijelaskan lebih lanjut di bawah.
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; }
Dengan menggabungkan semua informasi di atas, berikut cara Anda dapat memproses pergerakan joystick dalam game:
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 }
Untuk mendukung pengontrol game dengan fitur yang lebih canggih dari sekadar satu joystick, ikuti praktik terbaik berikut:
- Menangani stick pengontrol ganda. Banyak pengontrol game memiliki
joystick kiri dan kanan. Untuk stick sebelah kiri, Android
melaporkan pergerakan horizontal sebagai peristiwa
AXIS_X
dan pergerakan vertikal sebagai peristiwaAXIS_Y
. Untuk stick sebelah kanan, Android melaporkan pergerakan horizontal sebagai peristiwaAXIS_Z
dan pergerakan vertikal sebagai peristiwaAXIS_RZ
. Pastikan untuk menangani kedua stick pengontrol di kode Anda. -
Menangani penekanan shoulder trigger (dan pastikan game Anda berfungsi dengan peristiwa
AXIS_
danKEYCODE_BUTTON_
). Beberapa pengontrol memiliki tombol bahu kiri dan kanan. Jika ada, pemicu ini akan memunculkan peristiwaAXIS_*TRIGGER
atauKEYCODE_BUTTON_*2
, atau keduanya. Untuk pemicu kiri, ini akan menjadiAXIS_LTRIGGER
danKEYCODE_BUTTON_L2
. Untuk pemicu kanan, nilainya adalahAXIS_RTRIGGER
danKEYCODE_BUTTON_R2
. Peristiwa sumbu hanya terjadi jika pemicu memunculkan rentang nilai antara 0 dan 1, dan beberapa pengontrol dengan output analog memunculkan peristiwa tombol selain peristiwa sumbu. Game harus mendukung peristiwaAXIS_
danKEYCODE_BUTTON_
agar tetap kompatibel dengan semua pengontrol game umum, tetapi pilih peristiwa yang paling sesuai untuk gameplay Anda jika pengontrol melaporkan keduanya. Di Android 4.3 (API level 18) dan yang lebih tinggi, pengontrol yang menghasilkanAXIS_LTRIGGER
juga melaporkan nilai yang identik untuk sumbuAXIS_BRAKE
. Hal yang sama berlaku untukAXIS_RTRIGGER
danAXIS_GAS
. Android melaporkan semua penekanan pemicu analog dengan nilai yang dinormalisasi dari 0,0 (dilepaskan) hingga 1,0 (ditekan sepenuhnya). -
Perilaku dan dukungan tertentu dapat berbeda di lingkungan yang diemulasi. Platform yang diemulasi, seperti Google Play Game, mungkin sedikit berbeda perilakunya berdasarkan kemampuan sistem operasi host. Misalnya, beberapa pengontrol yang memunculkan peristiwa
AXIS_
danKEYCODE_BUTTON_
hanya memunculkan peristiwaAXIS_
, dan dukungan untuk beberapa pengontrol mungkin tidak ada sama sekali.