على الرغم من أنّ معظم الألعاب مصمّمة لدعم مستخدم واحد لكل جهاز Android، يمكن أيضًا دعم مستخدمين متعددين باستخدام وحدات تحكم في الألعاب متصلين في نفس الوقت على نفس جهاز Android.
يتناول هذا الدرس بعض الأساليب الأساسية للتعامل مع الإدخال في هي لعبة متعددة اللاعبين على جهاز من وحدات تحكّم متعدّدة متصلة. وتشمل هذه المعلومات ما يلي: الحفاظ على الربط بين الصور الرمزية للاعب وكل جهاز من أجهزة التحكم معالجة أحداث وحدة التحكم التي يتم إدخالها بشكل مناسب.
ربط اللاعبين بأرقام تعريف أجهزة وحدات التحكّم
عند توصيل ذراع تحكّم في الألعاب بجهاز Android، يطبّق النظام
يعيّن له رقم تعريف جهاز عددًا صحيحًا. يمكنك الحصول على أرقام تعريف الأجهزة المتصلة
وحدات التحكّم في الألعاب من خلال طلب الرقم InputDevice.getDeviceIds()
، على النحو الموضّح في التحقّق من أنّ ذراع التحكّم في الألعاب متصل. يمكنك بعد ذلك ربط كل
رقم تعريف الجهاز للاعب في لعبتك، ومعالجة إجراءات اللعبة لكل لاعب على حدة.
ملاحظة: على الأجهزة التي تعمل بنظام التشغيل Android 4.1 (واجهة برمجة التطبيقات)
المستوى 16 وأعلى، يمكنك الحصول على واصف جهاز الإدخال باستخدام
getDescriptor()
، الذي يُرجع قيمة فريدة
قيمة سلسلة ثابتة لجهاز الإدخال. وعلى عكس رقم تعريف الجهاز، فإن الواصف
لن تتغيّر حتى إذا كان جهاز الإدخال غير متصل أو تمت إعادة توصيله أو
تمت إعادة الضبط.
يوضح مقتطف الرمز أدناه كيفية استخدام SparseArray
لربط الصورة الرمزية للّاعب بوحدة تحكّم معيّنة. في هذا المثال، تشير
يخزِّن المتغيّر mShips
مجموعة من عناصر Ship
. تحوّل في
يتم إنشاء الصورة الرمزية للاعب داخل اللعبة عند إرفاق وحدة تحكم جديدة من قبل المستخدم،
وتتم إزالته عند إزالة وحدة التحكم المرتبطة به.
معاودة الاتصال "onInputDeviceAdded()
" و"onInputDeviceRemoved()
"
تعتبر الطرق جزءًا من طبقة التجريد التي تم تقديمها في
توفير وحدات التحكّم في إصدارات Android من خلال تنفيذ هذه
يمكن للّعبة التعرف على رقم تعريف جهاز وحدة التحكم في الألعاب عند
إضافة أو إزالة وحدة التحكم. يتوافق هذا الاكتشاف مع Android 2.3
(المستوى 9 من واجهة برمجة التطبيقات) والإصدارات الأحدث
Kotlin
private val ships = SparseArray<Ship>() override fun onInputDeviceAdded(deviceId: Int) { getShipForID(deviceId) } override fun onInputDeviceRemoved(deviceId: Int) { removeShipForID(deviceId) } private fun getShipForID(shipID: Int): Ship { return ships.get(shipID) ?: Ship().also { ships.append(shipID, it) } } private fun removeShipForID(shipID: Int) { ships.remove(shipID) }
Java
private final SparseArray<Ship> ships = new SparseArray<Ship>(); @Override public void onInputDeviceAdded(int deviceId) { getShipForID(deviceId); } @Override public void onInputDeviceRemoved(int deviceId) { removeShipForID(deviceId); } private Ship getShipForID(int shipID) { Ship currentShip = ships.get(shipID); if ( null == currentShip ) { currentShip = new Ship(); ships.append(shipID, currentShip); } return currentShip; } private void removeShipForID(int shipID) { ships.remove(shipID); }
معالجة إدخالات وحدة تحكم متعددة
يجب أن تنفّذ لعبتك التكرار الحلقي التالي لمعالجتها الإدخال من وحدات تحكُّم متعددة:
- اكتشاف ما إذا كان حدث إدخال قد وقع أم لا
- حدِّد مصدر الإدخال ورقم تعريف الجهاز الخاص به.
- بالاستناد إلى الإجراء المشار إليه في رمز مفتاح حدث الإدخال أو قيمة المحور، تحديث الصورة الرمزية للّاعب المرتبطة برقم تعريف الجهاز هذا.
- عرض واجهة المستخدم وتعديلها
إدخال KeyEvent
وMotionEvent
للأحداث أرقام تعريف أجهزة مرتبطة بها. تستفيد لعبتك من
لتحديد وحدة التحكّم التي صدر منها حدث الإدخال، وتعديل
الصورة الرمزية للّاعب المرتبطة بوحدة التحكم هذه.
يعرض مقتطف الرمز التالي كيفية الحصول على مرجع الصورة الرمزية للاعب. يتوافق مع رقم تعريف جهاز التحكم في الألعاب، وتحديث اللعبة استنادًا إلى المستخدم في وحدة التحكم هذه.
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) { event.deviceId.takeIf { it != -1 }?.also { deviceId -> val currentShip: Ship = getShipForID(deviceId) // Based on which key was pressed, update the player avatar // (e.g. set the ship headings or fire lasers) return true } } return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { int deviceId = event.getDeviceId(); if (deviceId != -1) { Ship currentShip = getShipForId(deviceId); // Based on which key was pressed, update the player avatar // (e.g. set the ship headings or fire lasers) ... return true; } } return super.onKeyDown(keyCode, event); }
ملاحظة: كإحدى أفضل الممارسات، عندما ينقر المستخدم قطع اتصال ذراع التحكّم في الألعاب، عليك إيقاف اللعبة مؤقتًا والاستفسار عمّا إذا كان المستخدم تريد إعادة الاتصال.