على مستوى النظام، يُبلغ نظام Android عن إدخال رموز الأحداث من وحدات التحكّم في الألعاب كرموز مفاتيح Android وقيم المحاور. يمكنك تلقّي هذه الرموز في لعبتك. وقيمها وتحويلها إلى إجراءات محددة داخل اللعبة.
عندما يتصل اللاعبون بوحدة تحكم في الألعاب أو إقرانها لاسلكيًا
أجهزتهم التي تعمل بنظام التشغيل Android، يكتشف النظام تلقائيًا وحدة التحكم
كجهاز إدخال ويبدأ في الإبلاغ عن أحداث الإدخال. يمكن أن تحصل لعبتك على
أحداث الإدخال هذه من خلال تنفيذ طرق معاودة الاتصال التالية في
Activity
أو View
التركيز (يجب عليك
تنفيذ عمليات الاستدعاء إما Activity
أو
View
، ولكن ليس كليهما):
- من
Activity
:dispatchGenericMotionEvent(android.view. MotionEvent)
يُستخدَم لمعالجة أحداث الحركة العامة، مثل حركات ذراع التحكّم.
dispatchKeyEvent(android.view.KeyEvent)
يتم استدعاؤها لمعالجة الأحداث الرئيسية مثل الصحافة أو إصدار جهاز تحكّم في الألعاب أو زرّ لوحة التحكّم.
- من
View
:onGenericMotionEvent(android.view.MotionEvent)
يُستخدَم لمعالجة أحداث الحركة العامة، مثل حركات ذراع التحكّم.
onKeyDown(int, android.view.KeyEvent)
هي فئة من التطبيقات التي تُسمى لمعالجة ضغطة على مفتاح مادي مثل جهاز التحكم في الألعاب أو زرّ لوحة التحكّم.
onKeyUp(int, android.view.KeyEvent)
يتم استدعاؤها لمعالجة إصدار مفتاح مادي مثل جهاز التحكم في الألعاب أو زرّ لوحة التحكّم.
والمنهج الموصى به هو تسجيل الأحداث من
كائن View
محدد يتفاعل معه المستخدم.
يمكنك فحص الكائنات التالية التي توفِّرها عمليات الاستدعاء للحصول على معلومات.
حول نوع حدث الإدخال الذي تم تلقّيه:
KeyEvent
- كائن يصف الاتجاهات
لوحة التحكّم (D-pad) وأزرار التحكّم في الألعاب. تصاحب الأحداث الرئيسية
key code الذي يشير إلى الزر المحدّد الذي تم تشغيله، مثل
DPAD_DOWN
أوBUTTON_A
. يمكنك الحصول على رمز المفتاح من خلال طلب الرقمgetKeyCode()
أو من المفتاح. عمليات معاودة الاتصال للأحداث، مثلonKeyDown()
MotionEvent
- كائن يصف الإدخال من ذراع التحكّم ومشغّل الكتف
وحركاتك. تكون أحداث الحركة مصحوبةً برمز إجراء ومجموعة من
قيم المحور. يحدد رمز الإجراء تغيير الحالة الذي حدث
مثل تحريك ذراع التحكم. تصف قيم المحور الموضع وتصف قيم
خصائص الحركة لتحكُّم مادي معيّن، مثل
AXIS_X
أوAXIS_RTRIGGER
يمكنك الحصول على رمز الإجراء من خلال استدعاءgetAction()
وقيمة المحور عن طريق يَتِمُّ الْآنَ الِاتِّصَالْ بِـgetAxisValue()
.
يركز هذا الدرس على كيفية التعامل مع المدخلات من أكثر أنواع
عناصر التحكّم المادية (أزرار لوحة الألعاب ولوحات التحكّم
أذرع التحكم) في شاشة لعبة من خلال تنفيذ ما سبق ذكره
View
طريقة لمعاودة الاتصال وعملية المعالجة
كائنان KeyEvent
وMotionEvent
التأكّد من توصيل ذراع التحكّم في الألعاب
عند الإبلاغ عن أحداث الإدخال، لا يميّز Android
بين الأحداث الواردة من جهاز غير وحدة تحكُّم في الألعاب والأحداث الواردة
من ذراع التحكم في الألعاب. على سبيل المثال، يؤدي إجراء شاشة تعمل باللمس إلى إنشاء
حدث AXIS_X
الذي يمثّل علامة X
على سطح اللمس، لكن ذراع التحكم ينتج عنه
حدث AXIS_X
الذي يمثّل الموضع X لذراع التحكّم في حال حذف
تهتم لعبتك بالتعامل مع البيانات التي تدخلها وحدة التحكم في اللعبة، فيجب أن تتحقق أولاً
أنّ حدث الإدخال يأتي من نوع مصدر ذي صلة
للتأكّد من أنّ جهاز الإدخال المتصل هو ذراع تحكّم في الألعاب، يُرجى الاتصال
getSources()
للحصول على حقل بت مجمّع
أنواع مصادر الإدخال المتوافقة مع هذا الجهاز يمكنك بعد ذلك إجراء اختبار لمعرفة ما إذا
يتم ضبط الحقول التالية:
- يشير نوع المصدر
SOURCE_GAMEPAD
إلى أنّ جهاز الإدخال يتضمّن أزرارًا في جهاز التحكّم في الألعاب (على سبيل المثال،BUTTON_A
). لاحظ أن هذا المصدر النوع لا يشير بشكل صارم إلى ما إذا كانت وحدة التحكم في الألعاب تتضمن أزرارًا، على الرغم من أنّ معظم أذرع الألعاب تتضمّن عادةً عناصر تحكُّم توجيهية. - يشير نوع المصدر
SOURCE_DPAD
إلى أنّ كان جهاز الإدخال يتضمن أزرار لوحة التحكّم (على سبيل المثال،DPAD_UP
). - نوع مصدر
SOURCE_JOYSTICK
تشير إلى أن جهاز الإدخال يحتوي على أصابع تحكُّم تناظرية (على سبيل المثال، ذراع تحكُّم يسجّل الحركات على طولAXIS_X
وAXIS_Y
).
يعرض مقتطف الرمز التالي طريقة مساعدة تتيح لك التحقق مما إذا كان أجهزة الإدخال المتصلة هي وحدات التحكم في الألعاب. إذا كان الأمر كذلك، فإن الطريقة تسترد معرّفات الأجهزة لوحدات التحكم في الألعاب. يمكنك بعد ذلك ربط كل جهاز رقم تعريف لاعب في لعبتك، ومعالجة إجراءات اللعبة لكل لاعب مرتبط بشكل منفصل. مزيد من المعلومات حول إتاحة استخدام عدة وحدات تحكّم في الألعاب متصلين في وقت واحد على نفس جهاز Android، راجع إتاحة عدة وحدات تحكّم في الألعاب
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; }
بالإضافة إلى ذلك، قد ترغب في التحقق من إمكانات الإدخال الفردية وحدة تحكُّم في الألعاب متصلة. قد يكون هذا مفيدًا، على سبيل المثال، إذا المطلوب من لعبتك ألا تستخدم سوى الإدخال من مجموعة عناصر التحكم المادية يفهمها.
لاكتشاف ما إذا كان رمز مفتاح أو رمز محور معيّنان متوافقَين مع مفتاح ذراع التحكّم في الألعاب، استخدِم الأساليب التالية:
- في Android 4.4 (المستوى 19 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك تحديد ما إذا كان رمز المفتاح
على وحدة تحكّم ألعاب متّصلة من خلال طلب
hasKeys(int...)
- في Android 3.1 (المستوى 12 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك العثور على جميع المحاور المتاحة.
متوفّرة على وحدة تحكّم ألعاب متّصلة من خلال طلب أول
getMotionRanges()
بعد ذلك، في كل تم إرجاع عنصر واحد (InputDevice.MotionRange
)، يُرجى الاتصالgetAxis()
للحصول على رقم تعريف المحور.
يتم الضغط على أزرار جهاز التحكم في معالجة الألعاب
يوضح الشكل 1 كيف يعين Android رموز المفاتيح وقيم المحاور إلى عناصر التحكم في معظم أذرع التحكم في الألعاب.
![](https://developer.android.com/static/images/training/game-controller-profiles.png?authuser=9&hl=ar)
الشكل 1. ملف شخصي لوحدة تحكُّم عامة في الألعاب
تشير وسائل الشرح في الشكل إلى ما يلي:
تتضمّن رموز المفاتيح الشائعة التي يتم إنشاؤها عند الضغط على أزرار جهاز التحكّم في الألعاب ما يلي:
BUTTON_A
,
BUTTON_B
,
BUTTON_SELECT
,
وBUTTON_START
. لعبة ما
تؤدي وحدات التحكّم أيضًا إلى تشغيل رمز المفتاح DPAD_CENTER
عند الضغط على وسط الشريط المتقاطع على لوحة التحكّم.
بإمكان اللعبة فحص رمز المفتاح من خلال طلب الرقم getKeyCode()
.
أو من استدعاءات الأحداث الرئيسية مثل
onKeyDown()
,
وإذا كان الحدث ذا صلة بلعبتك، تعامل معه على أنه
والحركة في لعبة. يسرد الجدول 1 إجراءات الألعاب المقترَحة الأكثر شيوعًا
أزرار جهاز التحكم في الألعاب.
الجدول 1. الإجراءات المقترَحة في ما يتعلّق بالألعاب على جهاز التحكّم في الألعاب الأزرار.
لعبة حركة | رمز مفتاح الزر |
---|---|
ابدأ اللعبة في القائمة الرئيسية، أو أوقِفها مؤقتًا أو أُعيد تشغيلها أثناءها. | BUTTON_START * |
عرض القائمة | BUTTON_SELECT *
وKEYCODE_MENU * |
نفس سلوك التنقل في نظام Android رجوع الموصوف في تصميم التنقّل الدليل. | KEYCODE_BACK |
الرجوع إلى عنصر سابق في إحدى القوائم | BUTTON_B |
تأكيد الاختيار أو تنفيذ إجراء اللعبة الأساسي | BUTTON_A و
DPAD_CENTER |
* يجب ألا تعتمد لعبتك على قائمة "البداية" أو "الاختيار" أو "القائمة". الأزرار
نصيحة: ننصحك بتوفير شاشة إعداد. في لعبتك للسماح للمستخدمين بتخصيص عمليات ربط ذراع التحكّم في الألعاب إجراءات اللعبة.
يوضح المقتطف التالي كيفية إلغاء
من onKeyDown()
إلى
ربط BUTTON_A
يتم الضغط على زر "DPAD_CENTER
".
من خلال إحدى المهام في اللعبة.
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; } }
ملاحظة: في Android 4.2 (واجهة برمجة التطبيقات
المستوى 17) وأقل، يتعامل النظام مع
BUTTON_A
باعتباره Android
مفتاح رجوع تلقائيًا. إذا كان تطبيقك متوافقًا مع أنظمة التشغيل Android هذه:
الإصدارات، فتأكد من معالجة
"BUTTON_A
" اللعبة الأساسية
اتخاذ القرار. لتحديد حزمة تطوير البرامج (SDK) الحالية لنظام التشغيل Android
على الجهاز، فراجع
قيمة Build.VERSION.SDK_INT
.
إدخال لوحة اتجاهات العملية
لوحة الاتجاهات الرباعية (D-pad) هي أداة تحكّم مادي شائعة في العديد من الألعاب.
ووحدات التحكم. يشير نظام التشغيل Android إلى الضغط على مفتاحَي D-pad للأعلى وللأسفل
AXIS_HAT_Y
حدثًا بنطاق
من -1.0 (لأعلى) إلى 1.0 (أسفل)، اضغط على D-pad LEFT أو RIGHT
حدثان (AXIS_HAT_X
) بنطاق يتراوح بين -1.0
(اليسار) إلى 1.0 (اليمين).
وبدلاً من ذلك، تُبلغ بعض وحدات التحكّم عن الضغطات على لوحة التحكّم باستخدام رمز مفتاح. إذا كانت لعبتك بضغطات لوحة التحكّم، فيجب أن تتعامل مع أحداث محور القبعة ولوحة التحكّم. الرموز الرئيسية كأحداث الإدخال نفسها، على النحو الموصى به في الجدول 2.
الجدول 2. الإجراءات التلقائية المقترَحة في اللعبة لمفتاح لوحة التحكّم الرموز وقيم محور القبعات.
لعبة حركة | رمز مفتاح لوحة التحكّم | رمز محور القبعة |
---|---|---|
نقل للأعلى | KEYCODE_DPAD_UP |
AXIS_HAT_Y (للقيم من 0 إلى -1.0) |
نقل للأسفل | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (للقيم من 0 إلى 1.0) |
نقل لليسار | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (للقيم من 0 إلى -1.0) |
نقل لليمين | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (للقيم من 0 إلى 1.0) |
يعرض مقتطف الرمز التالي فئة مساعد تتيح لك التحقق من القبعة والمحور وقيم رمز المفتاح من حدث إدخال لتحديد اتجاه لوحة التحكّم.
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; } } }
يمكنك استخدام فئة المساعدة هذه في لعبتك أينما تريد معالجتها.
يتم إدخال البيانات من خلال لوحة التحكّم (على سبيل المثال، في
onGenericMotionEvent()
أو
onKeyDown()
عمليات الاسترداد).
مثلاً:
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. ... }
معالجة حركات ذراع التحكّم
عندما يحرّك اللاعبون ذراع التحكّم على ذراع التحكّم في الألعاب، يبلغ Android عن
MotionEvent
الذي يحتوي على
رمز الإجراء ACTION_MOVE
والمُعدّل
مواضع محاور ذراع التحكم. يمكن أن تستخدم لعبتك البيانات المقدَّمة من
MotionEvent
لتحديد ما إذا كانت حركة ذراع التحكّم
مهمًا له.
يُرجى العلم أنّ أحداث حركة ذراع التحكّم قد تجمع عينات متعددة من الحركة معًا.
داخل كائن واحد. يحتوي الكائن MotionEvent
على
الموضع الحالي لكل محور ذراع التحكم بالإضافة إلى البيانات السابقة
المواضع لكل محور. عند الإبلاغ عن أحداث الحركة باستخدام رمز الإجراء ACTION_MOVE
(مثل حركات ذراع التحكّم)، يجمّع Android
المحور الخاص بالكفاءة. تتألف القيم السابقة للمحور من
مجموعة من القيم المميزة الأقدم من قيمة المحور الحالي، وأحدث من
القيم المذكورة في أي أحداث حركة سابقة. يمكنك الاطّلاع على
يُرجى الاطّلاع على مرجع MotionEvent
للحصول على التفاصيل.
يمكنك استخدام المعلومات السابقة لعرض اللعبة بدقة أكبر
لحركة الكائن بناءً على إدخال ذراع التحكم. إلى
واسترجاع القيم الحالية والسابقة
getAxisValue()
أو getHistoricalAxisValue()
يمكنك أيضًا العثور على عدد مرات
في حدث ذراع التحكّم من خلال استدعاء
getHistorySize()
يوضح المقتطف التالي كيفية إلغاء
معاودة الاتصال onGenericMotionEvent()
لمعالجة إدخال ذراع التحكّم. يجب عليك أولاً
وتعالج القيم التاريخية للمحور، ثم تعالج موضعه الحالي.
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); } }
قبل استخدام إدخال ذراع التحكم، يجب عليك تحديد ما إذا كان ذراع التحكم ثم احسب تحركات محوره وفقًا لذلك. أذرع التحكم التي يتم استخدامها عادةً مساحة مسطَّحة، أي نطاق من القيم بالقرب من الإحداثي (0,0) الذي يُعد المحور فيه متمركزًا. إذا كانت قيمة المحور التي تم الإبلاغ عنها بواسطة يقع Android ضمن المنطقة المسطحة، لذا يجب التعامل مع وحدة التحكم استراحة (أي لا تتحرك على طول كلا المحورين).
يوضِّح المقتطف أدناه طريقة مساعِدة تحتسب الحركة على طول
كل محور. لقد استدعيت هذا المساعد باستخدام طريقة processJoystickInput()
بمزيد من التفصيل أدناه.
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; }
من خلال وضع كل شيء معًا، إليك كيفية معالجة حركات ذراع التحكم في لعبتك:
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 }
لدعم وحدات التحكم في الألعاب الأكثر تطورًا ميزات أخرى أكثر من ذراع تحكم واحد، اتبع أفضل الممارسات التالية:
- يجب التعامل مع عصي وحدة التحكّم المزدوجة. تتمتع العديد من وحدات التحكم في الألعاب
ذراع التحكم الأيسر والأيمن معًا. بالنسبة إلى العصا اليسرى، يعمل Android
تسجيل الحركات الأفقية كأحداث
AXIS_X
والحركات العمودية كأحداثAXIS_Y
. بالنسبة إلى ذراع التحكّم الأيمن، يعرض نظام Android الحركات الأفقية كـAXIS_Z
من الأحداث والحركات العمودية كـ حدثان (AXIS_RZ
). احرص على التعامل مع كل من وحدات التحكم في التعليمة البرمجية. - التعامل مع الضغطات على مشغّل الكتف (مع توفير إدخال بديل
). تم تثبيت بعض وحدات التحكم باليدين اليسرى واليمنى.
والمشغلات. في حال توفّر هذه المشغِّلات، يُبلغ نظام Android عن الضغط على المشغّل الأيسر
كحدث
AXIS_LTRIGGER
و الضغط على زر السهم المتّجه لليمين حدثAXIS_RTRIGGER
. على Android 4.3 (المستوى 18 من واجهة برمجة التطبيقات)، وهي وحدة تحكم تُنتج تبلغ أيضًاAXIS_LTRIGGER
عن قيمة متطابقة للمحورAXIS_BRAKE
. تشير رسالة الأشكال البيانية ينطبق الشيء نفسه علىAXIS_RTRIGGER
AXIS_GAS
يبلغ Android عن كل المشغل التناظري بقيمة تمت تسويتها من 0.0 (تم إصدارها) إلى 1.0 (ضغطة كاملة). لا تحتوي جميع وحدات التحكم على مشغلات، لذا ضع في اعتبارك السماح للّاعبين بتنفيذ تلك إجراءات اللعبة باستخدام أزرار أخرى.