تقع على عاتقك مسؤولية إذا كنت تدعم وحدات تحكُّم الألعاب في لعبتك. للتأكّد من أنّ لعبتك تستجيب باستمرار لوحدات التحكّم في جميع الأجهزة تعمل على إصدارات مختلفة من Android. يتيح ذلك للعبتك الوصول إلى ويمكن أن يستمتع اللاعبون بتجربة لعب سلسة وحدات التحكم حتى عند تبديل أجهزة Android أو ترقيتها.
يوضح هذا الدرس كيفية استخدام واجهات برمجة التطبيقات المتوفرة في الإصدار 4.1 من نظام التشغيل Android والإصدارات الأحدث بطريقة متوافقة مع الأنظمة القديمة، ما يتيح للعبتك توفير ما يلي الميزات المتاحة على الأجهزة التي تعمل بنظام التشغيل Android 3.1 والإصدارات الأحدث:
- يمكن أن ترصد اللعبة ما إذا تمت إضافة ذراع تحكّم جديد في الألعاب أو تغييره أو إزالته.
- يمكن أن تستعلم اللعبة من إمكانات وحدة التحكّم في الألعاب.
- يمكن للّعبة التعرّف على أحداث الحركة الواردة من ذراع التحكّم في الألعاب.
تستند الأمثلة في هذا الدرس إلى أداة التنفيذ المرجعية.
التي يوفّرها النموذج "ControllerSample.zip
" المتاح للتنزيل
أعلاه. يعرض هذا النموذج كيفية تنفيذ InputManagerCompat
.
للتوافق مع إصدارات مختلفة من Android. لتجميع العينة، يمكنك
أن يستخدم الإصدار Android 4.1 (المستوى 16 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. بمجرد تجميعه، يعمل نموذج التطبيق
تعمل على أي جهاز يعمل بنظام التشغيل Android 3.1 (المستوى 12 لواجهة برمجة التطبيقات) أو أعلى بصفته الإصدار
الهدف.
الاستعداد لواجهات برمجة تطبيقات مختصرة لاستخدامها في وحدة التحكّم في الألعاب
لنفترض أنك تريد أن تتمكن من تحديد ما إذا كان اتصال وحدة التحكم في الألعاب تغيير الحالة على الأجهزة التي تعمل بنظام التشغيل Android 3.1 (المستوى 12 لواجهة برمجة التطبيقات). ومع ذلك، تتوفر واجهات برمجة التطبيقات في الإصدار 4.1 (المستوى 16 من واجهة برمجة التطبيقات) والإصدارات الأحدث فقط، لذلك إلى توفير طريقة تنفيذ تتوافق مع الإصدار 4.1 من نظام التشغيل Android والإصدارات الأحدث أثناء توفير آلية احتياطية متوافقة مع إصدارات Android 3.1 إلى Android 4.0.
ولمساعدتك في تحديد الميزات التي تتطلب مثل هذه الآلية الاحتياطية الإصدارات القديمة، يسرد الجدول 1 الاختلافات في دعم ذراع التحكم في الألعاب بين الإصدارَين Android 3.1 (المستوى 12 لواجهة برمجة التطبيقات) و4.1 (مستوى واجهة برمجة التطبيقات) 16.
الجدول 1. واجهات برمجة التطبيقات التي تتيح استخدام وحدات التحكّم في الألعاب بإصدارات Android المختلفة.
معلومات مسؤول التحكّم بالبيانات | واجهة برمجة تطبيقات وحدة التحكم | المستوى 12 من واجهة برمجة التطبيقات | المستوى 16 من واجهة برمجة التطبيقات |
---|---|---|---|
تحديد الجهاز | getInputDeviceIds() |
• | |
getInputDevice() |
• | ||
getVibrator() |
• | ||
SOURCE_JOYSTICK |
• | • | |
SOURCE_GAMEPAD |
• | • | |
حالة الاتصال بالإنترنت | onInputDeviceAdded() |
• | |
onInputDeviceChanged() |
• | ||
onInputDeviceRemoved() |
• | ||
تحديد حدث الإدخال | اضغط على لوحة التحكّم (
KEYCODE_DPAD_UP ,
KEYCODE_DPAD_DOWN ,
KEYCODE_DPAD_LEFT ,
KEYCODE_DPAD_RIGHT ,
KEYCODE_DPAD_CENTER ) |
• | • |
الضغط على زر لوحة الألعاب (
BUTTON_A ,
BUTTON_B ,
BUTTON_THUMBL ,
BUTTON_THUMBR ,
BUTTON_SELECT ,
BUTTON_START ,
BUTTON_R1 ,
BUTTON_L1 ,
BUTTON_R2 ,
BUTTON_L2 ) |
• | • | |
حركة تبديل ذراع التحكم والقبعة (
AXIS_X ,
AXIS_Y ,
AXIS_Z ,
AXIS_RZ ,
AXIS_HAT_X ,
AXIS_HAT_Y ) |
• | • | |
ضغط المشغِّل التناظري (
AXIS_LTRIGGER ,
AXIS_RTRIGGER ) |
• | • |
يمكنك استخدام التجريد لإنشاء دعم لوحدة تحكم الألعاب الواعية بالإصدارات عبر المنصات. يتضمن هذا النهج الخطوات التالية:
- تحديد واجهة Java وسيطة تستبعد تنفيذ ميزات وحدة التحكم في الألعاب التي تتطلبها لعبتك.
- إنشاء تنفيذ خادم وكيل للواجهة التي تستخدم واجهات برمجة التطبيقات في Android 4.1 والإصدارات الأحدث.
- إنشاء تنفيذ مخصّص للواجهة التي تستخدم واجهات برمجة التطبيقات المتاحة بين إصدارات Android 3.1 وAndroid 4.0.
- أنشئ منطقًا للتبديل بين هذه التطبيقات في وقت التشغيل، وبدء استخدام الواجهة في لعبتك
لإلقاء نظرة عامة على كيفية استخدام التجريد للتأكد من أن التطبيقات تعمل بطريقة متوافقة مع الأنظمة القديمة عبر إصدارات Android المختلفة، راجِع صناعة واجهات المستخدم المتوافقة مع الأنظمة القديمة
إضافة واجهة للتوافق مع الأنظمة القديمة
لتوفير التوافق مع الأنظمة القديمة، يمكنك إنشاء واجهة مخصصة ثم وإضافة عمليات تنفيذ خاصة بالإصدار. تتمثل إحدى ميزات هذا النهج في أنه تتيح لك إجراء نسخ مطابق للواجهات العامة على Android 4.1 (المستوى 16 من واجهة برمجة التطبيقات) التي أدعم وحدات التحكم في الألعاب.
Kotlin
// The InputManagerCompat interface is a reference example. // The full code is provided in the ControllerSample.zip sample. interface InputManagerCompat { val inputDeviceIds: IntArray fun getInputDevice(id: Int): InputDevice fun registerInputDeviceListener( listener: InputManager.InputDeviceListener, handler: Handler? ) fun unregisterInputDeviceListener(listener:InputManager.InputDeviceListener) fun onGenericMotionEvent(event: MotionEvent) fun onPause() fun onResume() interface InputDeviceListener { fun onInputDeviceAdded(deviceId: Int) fun onInputDeviceChanged(deviceId: Int) fun onInputDeviceRemoved(deviceId: Int) } }
Java
// The InputManagerCompat interface is a reference example. // The full code is provided in the ControllerSample.zip sample. public interface InputManagerCompat { ... public InputDevice getInputDevice(int id); public int[] getInputDeviceIds(); public void registerInputDeviceListener( InputManagerCompat.InputDeviceListener listener, Handler handler); public void unregisterInputDeviceListener( InputManagerCompat.InputDeviceListener listener); public void onGenericMotionEvent(MotionEvent event); public void onPause(); public void onResume(); public interface InputDeviceListener { void onInputDeviceAdded(int deviceId); void onInputDeviceChanged(int deviceId); void onInputDeviceRemoved(int deviceId); } ... }
توفّر واجهة InputManagerCompat
الطرق التالية:
getInputDevice()
- المرايا
getInputDevice()
. الحصول علىInputDevice
يمثّل إمكانيات وحدة التحكّم في الألعاب. getInputDeviceIds()
- المرايا
getInputDeviceIds()
. تعرض صفيفًا من الأعداد الصحيحة، كل وهي معرّف لجهاز إدخال مختلف. يكون هذا مفيدًا إذا كنت تقوم بإنشاء لعبة يتيح استخدامها عدة لاعبين وتريد معرفة عدد اللاعبين حتى تصبح وحدات التحكّم متصلة. registerInputDeviceListener()
- المرايا
registerInputDeviceListener()
. يتيح لك التسجيل ليتم إعلامك عند بدء إضافة جهاز أو تغييره أو إزالته. unregisterInputDeviceListener()
- المرايا
unregisterInputDeviceListener()
. إلغاء تسجيل أداة معالجة الحدث في جهاز إدخال onGenericMotionEvent()
- المرايا
onGenericMotionEvent()
. السماح للعبتك باعتراض الطلبات والتعامل معها عناصرMotionEvent
وقيم المحاور التي تمثل الأحداث مثل حركات ذراع التحكّم وضغطات المشغّل التناظري onPause()
- يوقف الاستطلاع في أحداث وحدات التحكم في الألعاب عند إيقاف النشاط الرئيسي مؤقتًا أو عندما تتوقف اللعبة عن التركيز
onResume()
- يبدأ التصويت بشأن أحداث وحدة التحكم في الألعاب عند يتم استئناف النشاط الرئيسي أو عند بدء اللعبة وتشغيلها خلال المقدّمة
InputDeviceListener
- يعكس
InputManager.InputDeviceListener
من واجهة pyplot. تسمح للّعبة بمعرفة ما إذا تمت إضافة ذراع تحكّم في الألعاب أو تغييرها أو إضافة وحدة تحكّم في الألعاب. تمت إزالته.
الخطوة التالية، إنشاء عمليات تنفيذ لـ InputManagerCompat
ناجحة
عبر إصدارات الأنظمة الأساسية المختلفة. إذا كانت لعبتك تعمل بنظام التشغيل Android 4.1 أو
ويستدعي طريقة InputManagerCompat
، فإن تنفيذ الخادم الوكيل
الطريقة المكافئة في InputManager
.
ومع ذلك، إذا كانت لعبتك تعمل بإصدارات Android من 3.1 إلى 4.0، سيتم تطبيق
معالجة الطلبات إلى InputManagerCompat
طرق باستخدام
فقط واجهات برمجة التطبيقات التي تم تقديمها في وقت لا يتجاوز الإصدار Android 3.1. بغض النظر عن
يُستخدم التنفيذ الخاص بإصدار معيّن في وقت التشغيل، ويجري التنفيذ
تظهر نتيجة المكالمة بشفافية.
![](https://developer.android.com/static/images/training/backward-compatible-inputmanager.png?authuser=9&hl=ar)
الشكل 1. رسم تخطيطي لفئة الواجهة والإصدار الخاص وعمليات التنفيذ.
تنفيذ الواجهة على نظام التشغيل Android 4.1 والإصدارات الأحدث
InputManagerCompatV16
عبارة عن تنفيذ
InputManagerCompat
التي تعمل على إنشاء وكيل لاستدعاءات الطريقة
InputManager
وInputManager.InputDeviceListener
الفعلية. تشير رسالة الأشكال البيانية
يتم الحصول على InputManager
من النظام.
Context
Kotlin
// The InputManagerCompatV16 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. public class InputManagerV16( context: Context, private val inputManager: InputManager = context.getSystemService(Context.INPUT_SERVICE) as InputManager, private val listeners: MutableMap<InputManager.InputDeviceListener, V16InputDeviceListener> = mutableMapOf() ) : InputManagerCompat { override val inputDeviceIds: IntArray = inputManager.inputDeviceIds override fun getInputDevice(id: Int): InputDevice = inputManager.getInputDevice(id) override fun registerInputDeviceListener( listener: InputManager.InputDeviceListener, handler: Handler? ) { V16InputDeviceListener(listener).also { v16listener -> inputManager.registerInputDeviceListener(v16listener, handler) listeners += listener to v16listener } } // Do the same for unregistering an input device listener ... override fun onGenericMotionEvent(event: MotionEvent) { // unused in V16 } override fun onPause() { // unused in V16 } override fun onResume() { // unused in V16 } } class V16InputDeviceListener( private val idl: InputManager.InputDeviceListener ) : InputManager.InputDeviceListener { override fun onInputDeviceAdded(deviceId: Int) { idl.onInputDeviceAdded(deviceId) } // Do the same for device change and removal ... }
Java
// The InputManagerCompatV16 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. public class InputManagerV16 implements InputManagerCompat { private final InputManager inputManager; private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> listeners; public InputManagerV16(Context context) { inputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); listeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>(); } @Override public InputDevice getInputDevice(int id) { return inputManager.getInputDevice(id); } @Override public int[] getInputDeviceIds() { return inputManager.getInputDeviceIds(); } static class V16InputDeviceListener implements InputManager.InputDeviceListener { final InputManagerCompat.InputDeviceListener mIDL; public V16InputDeviceListener(InputDeviceListener idl) { mIDL = idl; } @Override public void onInputDeviceAdded(int deviceId) { mIDL.onInputDeviceAdded(deviceId); } // Do the same for device change and removal ... } @Override public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener); inputManager.registerInputDeviceListener(v16Listener, handler); listeners.put(listener, v16Listener); } // Do the same for unregistering an input device listener ... @Override public void onGenericMotionEvent(MotionEvent event) { // unused in V16 } @Override public void onPause() { // unused in V16 } @Override public void onResume() { // unused in V16 } }
تنفيذ الواجهة على إصدارات Android 3.1 وحتى Android 4.0
لإنشاء تطبيق InputManagerCompat
يتوافق مع الإصدارات من 3.1 إلى Android 4.0 وحتى 4.0، يمكنك استخدام
الكائنات التالية:
SparseArray
من أرقام تعريف الأجهزة لتتبُّع وحدات التحكّم في الألعاب المرتبطة بالجهازHandler
لمعالجة أحداث الجهاز. عند بدء تشغيل التطبيق أو استئنافه، يتلقّىHandler
رسالة لبدء الاستطلاع. لإلغاء ربط وحدة التحكّم في الألعاب سيبدأHandler
للتحقّق من كل وحدة تحكّم معروفة في الألعاب مرتبطة ومعرفة ما إذا كان رقم تعريف الجهاز عاد. تشير القيمة المعروضةnull
إلى أنّ ذراع التحكّم في الألعاب غير متصل. يتوقفHandler
عن التصويت عندما يكون التطبيق متوقف مؤقتًا.Map
منInputManagerCompat.InputDeviceListener
الأخرى. ستستخدم المستمعين لتحديث حالة اتصال التتبع ذراع التحكّم في الألعاب.
Kotlin
// The InputManagerCompatV9 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. class InputManagerV9( val devices: SparseArray<Array<Long>> = SparseArray(), private val listeners: MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf() ) : InputManagerCompat { private val defaultHandler: Handler = PollingMessageHandler(this) … }
Java
// The InputManagerCompatV9 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. public class InputManagerV9 implements InputManagerCompat { private final SparseArray<long[]> devices; private final Map<InputDeviceListener, Handler> listeners; private final Handler defaultHandler; … public InputManagerV9() { devices = new SparseArray<long[]>(); listeners = new HashMap<InputDeviceListener, Handler>(); defaultHandler = new PollingMessageHandler(this); } }
تنفيذ عنصر PollingMessageHandler
يمتد
Handler
، وإلغاء
handleMessage()
. تتحقّق هذه الطريقة مما إذا تم تثبيت ذراع التحكّم في الألعاب المرفق.
غير متصلين وتُعلم المستمعين المسجلين.
Kotlin
private class PollingMessageHandler( inputManager: InputManagerV9, private val mInputManager: WeakReference<InputManagerV9> = WeakReference(inputManager) ) : Handler() { override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { MESSAGE_TEST_FOR_DISCONNECT -> { mInputManager.get()?.also { imv -> val time = SystemClock.elapsedRealtime() val size = imv.devices.size() for (i in 0 until size) { imv.devices.valueAt(i)?.also { lastContact -> if (time - lastContact[0] > CHECK_ELAPSED_TIME) { // check to see if the device has been // disconnected val id = imv.devices.keyAt(i) if (null == InputDevice.getDevice(id)) { // Notify the registered listeners // that the game controller is disconnected imv.devices.remove(id) } else { lastContact[0] = time } } } } sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME) } } } } }
Java
private static class PollingMessageHandler extends Handler { private final WeakReference<InputManagerV9> inputManager; PollingMessageHandler(InputManagerV9 im) { inputManager = new WeakReference<InputManagerV9>(im); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MESSAGE_TEST_FOR_DISCONNECT: InputManagerV9 imv = inputManager.get(); if (null != imv) { long time = SystemClock.elapsedRealtime(); int size = imv.devices.size(); for (int i = 0; i < size; i++) { long[] lastContact = imv.devices.valueAt(i); if (null != lastContact) { if (time - lastContact[0] > CHECK_ELAPSED_TIME) { // check to see if the device has been // disconnected int id = imv.devices.keyAt(i); if (null == InputDevice.getDevice(id)) { // Notify the registered listeners // that the game controller is disconnected imv.devices.remove(id); } else { lastContact[0] = time; } } } } sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME); } break; } } }
لبدء إجراء الاستطلاعات وإيقافها لإلغاء ربط وحدة التحكّم في الألعاب، عليك إلغاء الإعداد. هاتين الطريقتين:
Kotlin
private const val MESSAGE_TEST_FOR_DISCONNECT = 101 private const val CHECK_ELAPSED_TIME = 3000L class InputManagerV9( val devices: SparseArray<Array<Long>> = SparseArray(), private val listeners: MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf() ) : InputManagerCompat { ... override fun onPause() { defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT) } override fun onResume() { defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME) } ... }
Java
private static final int MESSAGE_TEST_FOR_DISCONNECT = 101; private static final long CHECK_ELAPSED_TIME = 3000L; @Override public void onPause() { defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT); } @Override public void onResume() { defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME); }
لرصد إضافة جهاز إدخال، يمكنك إلغاء
طريقة onGenericMotionEvent()
. عندما يُبلغ النظام عن حدث حركة،
تحقَّق مما إذا كان مصدر هذا الحدث هو رقم تعريف جهاز تم تتبعه أو من
معرّف الجهاز الجديد. إذا كان رقم تعريف الجهاز جديدًا، يُرجى إعلام المستمعين المسجَّلين.
Kotlin
override fun onGenericMotionEvent(event: MotionEvent) { // detect new devices val id = event.deviceId val timeArray: Array<Long> = mDevices.get(id) ?: run { // Notify the registered listeners that a game controller is added ... arrayOf<Long>().also { mDevices.put(id, it) } } timeArray[0] = SystemClock.elapsedRealtime() }
Java
@Override public void onGenericMotionEvent(MotionEvent event) { // detect new devices int id = event.getDeviceId(); long[] timeArray = mDevices.get(id); if (null == timeArray) { // Notify the registered listeners that a game controller is added ... timeArray = new long[1]; mDevices.put(id, timeArray); } long time = SystemClock.elapsedRealtime(); timeArray[0] = time; }
يتم تنفيذ إشعار المستمعين باستخدام
عنصر Handler
لإرسال DeviceEvent
الكائن Runnable
في قائمة انتظار الرسائل. DeviceEvent
يحتوي على مرجع إلى InputManagerCompat.InputDeviceListener
. فعندما
تعمل DeviceEvent
، وهي طريقة معاودة الاتصال المناسبة لخدمة المستمع
لإرسال إشارة إلى ما إذا تمت إضافة وحدة التحكّم في الألعاب أو تغييرها أو إزالتها.
Kotlin
class InputManagerV9( val devices: SparseArray<Array<Long>> = SparseArray(), private val listeners: MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf() ) : InputManagerCompat { ... override fun registerInputDeviceListener( listener: InputManager.InputDeviceListener, handler: Handler? ) { listeners[listener] = handler ?: defaultHandler } override fun unregisterInputDeviceListener(listener: InputManager.InputDeviceListener) { listeners.remove(listener) } private fun notifyListeners(why: Int, deviceId: Int) { // the state of some device has changed listeners.forEach { listener, handler -> DeviceEvent.getDeviceEvent(why, deviceId, listener).also { handler?.post(it) } } } ... } private val sObjectQueue: Queue<DeviceEvent> = ArrayDeque<DeviceEvent>() private class DeviceEvent( private var mMessageType: Int, private var mId: Int, private var mListener: InputManager.InputDeviceListener ) : Runnable { companion object { fun getDeviceEvent(messageType: Int, id: Int, listener: InputManager.InputDeviceListener) = sObjectQueue.poll()?.apply { mMessageType = messageType mId = id mListener = listener } ?: DeviceEvent(messageType, id, listener) } override fun run() { when(mMessageType) { ON_DEVICE_ADDED -> mListener.onInputDeviceAdded(mId) ON_DEVICE_CHANGED -> mListener.onInputDeviceChanged(mId) ON_DEVICE_REMOVED -> mListener.onInputDeviceChanged(mId) else -> { // Handle unknown message type } } } }
Java
@Override public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { listeners.remove(listener); if (handler == null) { handler = defaultHandler; } listeners.put(listener, handler); } @Override public void unregisterInputDeviceListener(InputDeviceListener listener) { listeners.remove(listener); } private void notifyListeners(int why, int deviceId) { // the state of some device has changed if (!listeners.isEmpty()) { for (InputDeviceListener listener : listeners.keySet()) { Handler handler = listeners.get(listener); DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener); handler.post(odc); } } } private static class DeviceEvent implements Runnable { private int mMessageType; private int mId; private InputDeviceListener mListener; private static Queue<DeviceEvent> sObjectQueue = new ArrayDeque<DeviceEvent>(); ... static DeviceEvent getDeviceEvent(int messageType, int id, InputDeviceListener listener) { DeviceEvent curChanged = sObjectQueue.poll(); if (null == curChanged) { curChanged = new DeviceEvent(); } curChanged.mMessageType = messageType; curChanged.mId = id; curChanged.mListener = listener; return curChanged; } @Override public void run() { switch (mMessageType) { case ON_DEVICE_ADDED: mListener.onInputDeviceAdded(mId); break; case ON_DEVICE_CHANGED: mListener.onInputDeviceChanged(mId); break; case ON_DEVICE_REMOVED: mListener.onInputDeviceRemoved(mId); break; default: // Handle unknown message type ... break; } // Put this runnable back in the queue sObjectQueue.offer(this); } }
لديك الآن عمليتَا تنفيذ لـ InputManagerCompat
: إحداهما
تعمل على الأجهزة التي تعمل بنظام التشغيل Android 4.1 أو الإصدارات الأحدث،
تعمل على الأجهزة التي تعمل بإصدارات Android 3.1 إلى Android 4.0.
استخدام طريقة التنفيذ الخاصة بإصدار معيّن
يتم تنفيذ منطق التبديل الخاص بالإصدار في فئة تعمل مصنعًا.
Kotlin
object Factory { fun getInputManager(context: Context): InputManagerCompat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { InputManagerV16(context) } else { InputManagerV9() } }
Java
public static class Factory { public static InputManagerCompat getInputManager(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { return new InputManagerV16(context); } else { return new InputManagerV9(); } } }
يمكنك الآن إنشاء مثيل كائن InputManagerCompat
ببساطة
عليك تسجيل InputManagerCompat.InputDeviceListener
على جهازك الرئيسي
View
بسبب منطق تبديل الإصدارات الذي قمت بتعيينه
ستستخدم لعبتك تلقائيًا طريقة التنفيذ المناسبة
إصدار Android الذي يعمل عليه الجهاز.
Kotlin
class GameView(context: Context) : View(context), InputManager.InputDeviceListener { private val inputManager: InputManagerCompat = Factory.getInputManager(context).apply { registerInputDeviceListener(this@GameView, null) ... } ... }
Java
public class GameView extends View implements InputDeviceListener { private InputManagerCompat inputManager; ... public GameView(Context context, AttributeSet attrs) { inputManager = InputManagerCompat.Factory.getInputManager(this.getContext()); inputManager.registerInputDeviceListener(this, null); ... } }
بعد ذلك، تجاوز
طريقة onGenericMotionEvent()
في طريقة العرض الرئيسية، كما هو موضّح في
التعامل مع حدث MotionEvent من لعبة
وحدة التحكّم من المفترض أن تتمكّن لعبتك الآن من معالجة أحداث وحدة التحكّم في الألعاب.
باستمرار على الأجهزة التي تعمل بنظام التشغيل Android 3.1 (المستوى 12 لواجهة برمجة التطبيقات) والإصدارات الأحدث.
Kotlin
override fun onGenericMotionEvent(event: MotionEvent): Boolean { inputManager.onGenericMotionEvent(event) // Handle analog input from the controller as normal ... return super.onGenericMotionEvent(event) }
Java
@Override public boolean onGenericMotionEvent(MotionEvent event) { inputManager.onGenericMotionEvent(event); // Handle analog input from the controller as normal ... return super.onGenericMotionEvent(event); }
يمكنك العثور على التنفيذ الكامل لرمز التوافق هذا في
تم توفير صف واحد (GameView
) في النموذج ControllerSample.zip
.
متوفر للتنزيل أعلاه.