إتاحة استخدام عدة أذرع تحكُّم في الألعاب

على الرغم من أنّ معظم الألعاب مصمّمة لدعم مستخدم واحد لكل جهاز 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);
}

معالجة إدخالات وحدة تحكم متعددة

يجب أن تنفّذ لعبتك التكرار الحلقي التالي لمعالجتها الإدخال من وحدات تحكُّم متعددة:

  1. اكتشاف ما إذا كان حدث إدخال قد وقع أم لا
  2. حدِّد مصدر الإدخال ورقم تعريف الجهاز الخاص به.
  3. بالاستناد إلى الإجراء المشار إليه في رمز مفتاح حدث الإدخال أو قيمة المحور، تحديث الصورة الرمزية للّاعب المرتبطة برقم تعريف الجهاز هذا.
  4. عرض واجهة المستخدم وتعديلها

إدخال 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);
}

ملاحظة: كإحدى أفضل الممارسات، عندما ينقر المستخدم قطع اتصال ذراع التحكّم في الألعاب، عليك إيقاف اللعبة مؤقتًا والاستفسار عمّا إذا كان المستخدم تريد إعادة الاتصال.