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):
Activity
kaynağından:dispatchGenericMotionEvent(android.view. MotionEvent)
Kontrol çubuğu hareketleri gibi genel hareket etkinliklerini işlemek için çağrılır.
dispatchKeyEvent(android.view.KeyEvent)
Oyun kumandasına veya D-pad düğmesine basmak ya da serbest bırakmak gibi önemli etkinlikleri işlemek için çağrılır.
View
kaynağından:onGenericMotionEvent(android.view.MotionEvent)
Kontrol çubuğu hareketleri gibi genel hareket etkinliklerini işlemek için çağrılır.
onKeyDown(int, android.view.KeyEvent)
Oyun kumandası veya D-pad düğmesi gibi fiziksel bir tuşa basılma işlemini gerçekleştirmek için çağrılır.
onKeyUp(int, android.view.KeyEvent)
Oyun kumandası veya D-pad düğmesi gibi fiziksel bir anahtarı serbest bırakma işlemi için çağrılır.
Ö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
veyaBUTTON_A
gibi belirli bir düğmenin tetiklendiğini belirten bir anahtar kodu eşlik eder. Anahtar kodunugetKeyCode()
yöntemini çağırarak veyaonKeyDown()
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
veyaAXIS_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ğerinigetAxisValue()
ç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
veAXIS_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 herInputDevice.MotionRange
nesnesindegetAxis()
ç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.
Ş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.
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.
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 iseAXIS_Y
etkinlik olarak raporlar. Android, sağ çubuk için yatay hareketleriAXIS_Z
etkinliği, dikey hareketleri iseAXIS_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ı durumAXIS_RTRIGGER
veAXIS_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.