پشتیبانی از چندین کنترلر بازی

در حالی که اکثر بازی‌ها طوری طراحی شده‌اند که از یک کاربر در هر دستگاه اندروید پشتیبانی کنند، می‌توان با استفاده از دسته‌های بازی که به طور همزمان به یک دستگاه اندروید متصل هستند، از چندین کاربر نیز پشتیبانی کرد.

این درس برخی از تکنیک‌های اساسی برای مدیریت ورودی در بازی چند نفره تک دستگاهی شما از چندین کنترلر متصل را پوشش می‌دهد. این شامل حفظ نگاشت بین آواتارهای بازیکن و هر دستگاه کنترلر و پردازش مناسب رویدادهای ورودی کنترلر می‌شود.

نگاشت بازیکنان به شناسه‌های دستگاه کنترلر

وقتی یک دسته بازی به یک دستگاه اندروید متصل می‌شود، سیستم یک شناسه دستگاه عدد صحیح به آن اختصاص می‌دهد. می‌توانید شناسه‌های دستگاه را برای دسته‌های بازی متصل با فراخوانی InputDevice.getDeviceIds() به دست آورید، همانطور که در بخش «بررسی اتصال دسته بازی» نشان داده شده است . سپس می‌توانید هر شناسه دستگاه را با یک بازیکن در بازی خود مرتبط کنید و اقدامات بازی را برای هر بازیکن به طور جداگانه پردازش کنید.

قطعه کد زیر نحوه استفاده از SparseArray برای مرتبط کردن آواتار یک بازیکن با یک کنترلر خاص نشان می‌دهد. در این مثال، متغیر mShips مجموعه‌ای از اشیاء Ship را ذخیره می‌کند. وقتی یک کنترلر جدید توسط یک کاربر متصل می‌شود، یک آواتار بازیکن جدید در بازی ایجاد می‌شود و وقتی کنترلر مرتبط با آن حذف می‌شود، آواتار بازیکن نیز حذف می‌شود.

متدهای فراخوانی onInputDeviceAdded() و onInputDeviceRemoved() بخشی از لایه انتزاعی معرفی شده در Supporting Controllers Across Android Versions هستند. با پیاده‌سازی این فراخوانی‌های شنونده، بازی شما می‌تواند شناسه دستگاه کنترلر بازی را هنگام اضافه یا حذف شدن یک کنترلر شناسایی کند. این تشخیص با اندروید ۲.۳ (سطح API ۹) و بالاتر سازگار است.

کاتلین

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)
}

جاوا

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 دارای شناسه‌های دستگاه مرتبط با خود هستند. بازی شما می‌تواند از این مزیت برای تعیین اینکه رویداد ورودی از کدام کنترلر آمده است، استفاده کند و آواتار بازیکن مرتبط با آن کنترلر را به‌روزرسانی کند.

قطعه کد زیر نشان می‌دهد که چگونه می‌توانید مرجع آواتار بازیکن مربوط به شناسه دستگاه کنترلر بازی را دریافت کنید و بازی را بر اساس فشار دادن دکمه توسط کاربر روی آن کنترلر به‌روزرسانی کنید.

کاتلین

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)
}

جاوا

@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);
}