Android, sistem düzeyinde oyun kontrol cihazlarından gelen giriş etkinliği kodlarını Android tuş 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 cihazlarına fiziksel olarak bağladığında veya kablosuz olarak eşlediğinde sistem, kumandayı giriş cihazı olarak otomatik olarak algılar ve giriş etkinliklerini bildirmeye başlar. Oyununuz, etkin Activity
veya odaklanmış View
'inizde aşağıdaki geri çağırma yöntemlerini uygulayarak bu giriş etkinliklerini alabilir (geri çağırma yöntemlerini Activity
veya View
için uygulamanız gerekir, her ikisi için de uygulamamanız gerekir):
Activity
tarafından gönderildi:dispatchGenericMotionEvent(android.view. MotionEvent)
Kontrol çubuğu hareketleri gibi genel hareket etkinliklerini işlemek için çağrılır.
dispatchKeyEvent(android.view.KeyEvent)
Gamepad veya D-pad düğmesine basma ya da düğmeyi bırakma gibi önemli etkinlikleri işlemek için çağrılır.
View
tarafından gönderildi: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 basma işlemini işlemek için çağrılır.
onKeyUp(int, android.view.KeyEvent)
Oyun kumandası veya D-pad düğmesi gibi fiziksel bir tuşun serbest bırakılmasını işlemek için çağrılır.
Önerilen yaklaşım, etkinlikleri kullanıcının etkileşimde bulunduğu belirli View
nesnesinden 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üğme etkinliklerini tanımlayan bir nesne. Önemli etkinliklere, tetiklenen belirli bir düğmeyi gösteren
DPAD_DOWN
veyaBUTTON_A
gibi bir anahtar kodu eşlik eder. Anahtar kodu,getKeyCode()
yöntemini çağırarak veyaonKeyDown()
gibi önemli etkinlik geri çağırmalarından alabilirsiniz. MotionEvent
- Joystick ve omuz tetik hareketlerinden gelen girişi açıklayan bir nesne. Hareket etkinliklerine bir işlem kodu ve bir dizi eksen değerleri eşlik eder. İşlem kodu, gerçekleşen durum değişikliğini (ör. bir kontrol çubuğu hareket ettirildiğinde) belirtir. Eksen değerleri,
AXIS_X
veyaAXIS_RTRIGGER
gibi belirli bir fiziksel kontrol için konum ve diğer hareket özelliklerini tanımlar.getAction()
işlevini çağırarak işlem kodunu,getAxisValue()
işlevini çağırarak da eksen değerini alabilirsiniz.
Bu derste, yukarıda belirtilen View
geri çağırma yöntemlerini uygulayarak ve KeyEvent
ile MotionEvent
nesnelerini işleyerek oyun ekranındaki en yaygın fiziksel kontrol türlerinden (oyun kumandası düğmeleri, yön düğmeleri ve kontrol çubukları) gelen girişleri nasıl işleyeceğinize odaklanılmaktadır.
Oyun kumandasının bağlı olduğunu doğrulama
Android, giriş etkinliklerini raporlarken oyun kumandası olmayan bir cihazdan gelen etkinlikler ile oyun kumandasından gelen etkinlikler arasında ayrım yapmaz. Örneğin, dokunmatik ekran işlemi, dokunma yüzeyinin X koordinatını temsil eden bir AXIS_X
etkinliği oluştururken kontrol çubuğu, kontrol çubuğunun X konumunu temsil eden bir AXIS_X
etkinliği oluşturur. Oyununuzda oyun kumandası girişinin işlenmesi önemliyse öncelikle giriş etkinliğinin alakalı 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()
işlevini çağırarak söz konusu 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 olduğunu gösterir (ör.BUTTON_A
). Çoğu oyun kumandasında yön kontrolleri olsa da bu kaynak türünün, oyun kumandasında D-pad düğmelerinin olup olmadığını tam olarak belirtmediğini unutmayın.SOURCE_DPAD
kaynak türü, giriş cihazında D-pad düğmeleri (ör.DPAD_UP
) olduğunu gösterir.SOURCE_JOYSTICK
kaynak türü, giriş cihazında analog kontrol çubukları (örneğin,AXIS_X
veAXIS_Y
boyunca hareketleri kaydeden bir kontrol çubuğu) olduğunu gösterir.
Aşağıdaki kod snippet'inde, bağlı giriş cihazlarının oyun kumandası olup olmadığını kontrol etmenizi sağlayan bir yardımcı yöntem gösterilmektedir. Bu durumda yöntem, oyun kumandalarının cihaz kimliklerini alır. Daha sonra her cihaz kimliğini oyununuzdaki bir oyuncuyla ilişkilendirebilir ve bağlı her oyuncu için oyun işlemlerini ayrı ayrı işleyebilirsiniz. Aynı Android cihaza aynı anda bağlı birden fazla oyun denetleyicisini destekleme hakkında daha fazla bilgi edinmek için Birden fazla oyun denetleyicisini destekleme başlıklı makaleyi inceleyin.
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 kontrol etmek isteyebilirsiniz. Bu, örneğin, oyununuzun yalnızca anladığı fiziksel kontrol grubundan gelen girişleri kullanmasını istiyorsanız yararlı olabilir.
Belirli bir tuş 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...)
işlevini çağırarak bağlı bir oyun kumandasında bir tuş kodunun desteklenip desteklenmediğini belirleyebilirsiniz. - Android 3.1 (API düzeyi 12) veya sonraki sürümlerde, bağlı bir oyun kumandasında desteklenen tüm eksenleri bulmak için önce
getMotionRanges()
işlevini çağırmanız gerekir. Daha sonra, döndürülen herInputDevice.MotionRange
nesnesinde, eksen kimliğini almak içingetAxis()
yöntemini çağırın.
Oyun kumandası düğme basışlarını işleme
Şekil 1'de, Android'in tuş kodlarını ve eksen değerlerini çoğu oyun kumandasındaki fiziksel kontrollere nasıl eşleştirdiği gösterilmektedir.
Şekildeki açıklama metinleri aşağıdakilere karşılık gelir:
Oyun kumandası düğmelerine basıldığında oluşturulan yaygın anahtar kodları arasında BUTTON_A
,
BUTTON_B
,
BUTTON_SELECT
ve BUTTON_START
bulunur. Bazı oyun kumandaları, D-pad çapraz çubuğunun ortasına basıldığında da DPAD_CENTER
tuş kodunu tetikler. Oyununuz, getKeyCode()
veya onKeyDown()
gibi önemli etkinlik geri çağırmalarından birini çağırarak anahtar kodunu inceleyebilir ve oyununuzla alakalı bir etkinliği temsil ediyorsa bunu oyun işlemi olarak işleyebilir. Tablo 1'de, en yaygın oyun kumandası düğmeleri için önerilen oyun işlemleri listelenmektedir.
Oyun Aksiyonu | Düğme tuş 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 Geri gezinme davranışıyla aynıdır. | KEYCODE_BACK |
Menüdeki önceki bir öğeye geri gitme | BUTTON_B |
Seçimi onaylayın veya birincil oyun işlemini gerçekleştirin | BUTTON_A ve
DPAD_CENTER |
* Oyununuz Başlat, Seç veya Menü düğmelerinin varlığına bağlı olmamalıdır.
İpucu: Kullanıcıların oyun hareketleri için kendi oyun kumandası eşlemelerini kişiselleştirmelerine olanak tanımak amacıyla oyununuzda bir yapılandırma ekranı sunabilirsiniz.
Aşağıdaki snippet'te, BUTTON_A
ve DPAD_CENTER
düğmelerine basma işlemlerini bir oyun hareketiyle ilişkilendirmek için onKeyDown()
'ü 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
simgesini varsayılan olarak Android Geri anahtarı olarak kabul eder. Uygulamanız bu Android sürümlerini destekliyorsa BUTTON_A
öğesini birincil oyun işlemi olarak kabul ettiğinizden emin olun. Cihazdaki mevcut Android SDK sürümünü belirlemek için Build.VERSION.SDK_INT
değerine bakın.
Yön tuşları girişini işleme
4 yönlü yön çubuğu (D-pad), birçok oyun kontrol cihazında bulunan yaygın bir fiziksel kontroldür. Android, D-pad'in yukarı ve aşağı düğmelerine basılmasını -1,0 (yukarı) ile 1,0 (aşağı) arasında değişen bir aralığa sahip AXIS_HAT_Y
etkinlikleri olarak, D-pad'in sol veya sağ düğmelerine basılmasını ise -1,0 (sol) ile 1,0 (sağ) arasında değişen bir aralığa sahip AXIS_HAT_Y
etkinlikleri olarak raporlar.AXIS_HAT_X
Bunun yerine bazı kumandalar d-pad'e basmaları bir tuş koduyla bildirir. Oyununuzda D-pad tuşlarına basılması önemliyse şapka ekseni etkinliklerini ve D-pad tuş kodlarını tablo 2'de önerildiği gibi aynı giriş etkinlikleri olarak ele almalısınız.
Aksiyon | D-pad tuş kodu | Şapka Ekseni Kodu |
---|---|---|
Yukarı Taşı | KEYCODE_DPAD_UP |
AXIS_HAT_Y (0 ila -1,0 arasındaki değerler için) |
Aşağı Taşı | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (0 - 1,0 değerleri için) |
Sola Taşı | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (0 ila -1,0 arasındaki değerler için) |
Sağa Taşı | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (0 ile 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 tuş kodu değerlerini kontrol etmenize olanak tanıyan 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 (örneğin, onGenericMotionEvent()
veya onKeyDown()
geri çağırmalarında) kullanabilirsiniz.
Örnek:
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şleme
Oyuncular oyun kontrol cihazlarındaki bir kontrol çubuğunu hareket ettirdiğinde Android, ACTION_MOVE
işlem kodunu ve kontrol çubuğunun eksenlerinin güncellenmiş konumlarını içeren bir MotionEvent
bildirir. Oyununuz, önemsediği bir kontrol çubuğu hareketinin olup olmadığını belirlemek için MotionEvent
tarafından sağlanan verileri kullanabilir.
Kontrol çubuğu hareket etkinliklerinin tek bir nesne içinde birden fazla hareket örneğini gruplandırabileceğini unutmayın. MotionEvent
nesnesi, her kontrol çubuğu ekseninin mevcut konumunun yanı sıra her eksen için birden fazla geçmiş konum içerir. Android, ACTION_MOVE
işlem koduyla hareket etkinliklerini raporlarken (ör. kontrol çubuğu hareketleri) verimlilik için eksen değerlerini gruplandırır. Bir eksenin geçmiş değerleri, geçerli eksen değerinden eski ve önceki hareket etkinliklerinde raporlanan değerlerden daha yeni olan farklı değerlerden oluşur. Ayrıntılar için MotionEvent
referansına bakın.
Geçmiş bilgileri kullanarak bir oyun nesnesinin hareketini kontrol çubuğu girişine göre daha doğru şekilde oluşturabilirsiniz. Mevcut ve geçmiş değerleri almak için getAxisValue()
veya getHistoricalAxisValue()
işlevini çağırın. getHistorySize()
işlevini çağırarak 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, 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 ortada olup olmadığını belirlemeniz ve ardından eksen hareketlerini buna göre hesaplamanız gerekir. Kontrol çubuklarında genellikle sabit bir alan bulunur. Bu alan, eksenin ortada olduğu kabul edilen (0,0) koordinatına yakın bir değer aralığıdır. Android tarafından bildirilen eksen değeri düz alandaysa kumandayı hareketsiz (yani her iki eksende hareketsiz) olarak değerlendirmeniz gerekir.
Aşağıdaki snippet'te, her eksen boyunca hareketi hesaplayan bir yardımcı yöntem gösterilmektedir. Bu yardımcıyı, aşağıda açıklanan processJoystickInput()
yönteminde ç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 getirerek oyununuzda kontrol çubuğu hareketlerini nasıl işleyebileceğinizi aşağıda görebilirsiniz:
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ğundan daha gelişmiş özelliklere sahip oyun denetleyicilerini desteklemek için aşağıdaki en iyi uygulamaları uygulayın:
- Çift kumanda çubuğunu tutma. Birçok oyun kumandasında hem sol hem de sağ kontrol çubuğu bulunur. Android, sol çubuk için yatay hareketleri
AXIS_X
etkinlikleri, dikey hareketleri iseAXIS_Y
etkinlikleri olarak bildirir. Android, sağ çubuk için yatay hareketleriAXIS_Z
etkinlikleri, dikey hareketleri iseAXIS_RZ
etkinlikleri olarak raporlar. Kodunuzda her iki kumanda çubuğunu da kullandığınızdan emin olun. -
Kenar tetiği basma işlemlerini kontrol edin (ve oyununuzun
AXIS_
veKEYCODE_BUTTON_
etkinlikleriyle çalıştığından emin olun). Bazı kontrol cihazlarında sol ve sağ omuz tetikleyicileri bulunur. Bu tetikleyiciler mevcut olduğunda birAXIS_*TRIGGER
veyaKEYCODE_BUTTON_*2
etkinliği ya da her ikisi de yayınlanır. Sol tetikleyici için buAXIS_LTRIGGER
veKEYCODE_BUTTON_L2
olur. Doğru tetikleyici için bu değerlerAXIS_RTRIGGER
veKEYCODE_BUTTON_R2
olmalıdır. Eksen etkinlikleri yalnızca tetikleyici 0 ile 1 arasında bir değer aralığı yayarsa gerçekleşir ve analog çıkışa sahip bazı denetleyiciler, eksen etkinliklerine ek olarak düğme etkinlikleri de yayar. Oyunlar, yaygın olarak kullanılan tüm oyun kumandalarıyla uyumlu kalmak için hemAXIS_
hem deKEYCODE_BUTTON_
etkinliklerini desteklemelidir. Ancak bir kumanda her ikisini de bildirirse oyununuz için en uygun etkinliği tercih edin. Android 4.3 (API düzeyi 18) ve sonraki sürümlerde,AXIS_LTRIGGER
üreten bir denetleyiciAXIS_BRAKE
ekseni için de aynı değeri bildirir. Aynı durumAXIS_RTRIGGER
veAXIS_GAS
için de geçerlidir. Android, tüm analog tetikleyici basma işlemlerini 0,0 (bırakılmış) ile 1,0 (tamamen basılmış) arasında normalleştirilmiş bir değerle raporlar. -
Belirli davranışlar ve destek, taklit edilen ortamlarda farklılık gösterebilir. Google Play Games gibi taklit edilen platformların davranışı, barındırıcı işletim sisteminin özelliklerine bağlı olarak biraz farklılık gösterebilir. Örneğin, hem
AXIS_
hem deKEYCODE_BUTTON_
etkinliklerini yayan bazı kumandalar yalnızcaAXIS_
etkinliklerini yayar. Bazı kumandalar için sunulan destek tamamen eksik olabilir.