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

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

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

نقشه پخش‌کننده‌ها به شناسه‌های دستگاه کنترل‌کننده

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

توجه: در دستگاه‌های دارای Android 4.1 (سطح API 16) و بالاتر، می‌توانید توصیفگر دستگاه ورودی را با استفاده از getDescriptor() دریافت کنید که یک مقدار رشته ثابت منحصر به فرد را برای دستگاه ورودی برمی‌گرداند. برخلاف شناسه دستگاه، مقدار توصیفگر تغییر نخواهد کرد حتی اگر دستگاه ورودی قطع، وصل یا پیکربندی مجدد شود.

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

متدهای پاسخ به تماس onInputDeviceAdded() و onInputDeviceRemoved() بخشی از لایه انتزاعی معرفی شده در پشتیبانی از کنترلرها در سراسر نسخه های اندروید هستند. با اجرای این تماس‌های شنونده، بازی شما می‌تواند شناسه دستگاه کنترل‌کننده بازی را هنگام اضافه یا حذف یک کنترلر شناسایی کند. این تشخیص با اندروید 2.3 (سطح API 9) و بالاتر سازگار است.

کاتلین

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

توجه: به عنوان بهترین روش، هنگامی که کنترلر بازی کاربر قطع می شود، باید بازی را متوقف کنید و بپرسید که آیا کاربر می خواهد دوباره وصل شود.