پشتیبانی از چندین کنترلر بازی
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
در حالی که بیشتر بازیها برای پشتیبانی از یک کاربر در هر دستگاه اندرویدی طراحی شدهاند، همچنین میتوان از چندین کاربر با کنترلرهای بازی که به طور همزمان در یک دستگاه اندرویدی متصل هستند، پشتیبانی کرد.
این درس برخی از تکنیکهای اساسی برای مدیریت ورودی در بازی چندنفره یک دستگاه شما از چندین کنترلر متصل را پوشش میدهد. این شامل حفظ نقشه بین آواتارهای بازیکن و هر دستگاه کنترلر و پردازش مناسب رویدادهای ورودی کنترلر است.
نقشه پخشکنندهها به شناسههای دستگاه کنترلکننده
هنگامی که یک کنترلر بازی به یک دستگاه 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);
}
ورودی چند کنترلر را پردازش کنید
بازی شما باید حلقه زیر را برای پردازش ورودی از چندین کنترلر اجرا کند:
- تشخیص اینکه آیا یک رویداد ورودی رخ داده است یا خیر.
- منبع ورودی و شناسه دستگاه آن را شناسایی کنید.
- بر اساس عملکردی که با کد کلید رویداد ورودی یا مقدار محور نشان داده شده است، آواتار پخش کننده مرتبط با آن شناسه دستگاه را بهروزرسانی کنید.
- رندر و به روز رسانی رابط کاربری.
رویدادهای ورودی 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);
}
توجه: به عنوان بهترین روش، هنگامی که کنترلر بازی کاربر قطع می شود، باید بازی را متوقف کنید و بپرسید که آیا کاربر می خواهد دوباره وصل شود.
محتوا و نمونه کدها در این صفحه مشمول پروانههای توصیفشده در پروانه محتوا هستند. جاوا و OpenJDK علامتهای تجاری یا علامتهای تجاری ثبتشده Oracle و/یا وابستههای آن هستند.
تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی.
[[["درک آسان","easyToUnderstand","thumb-up"],["مشکلم را برطرف کرد","solvedMyProblem","thumb-up"],["غیره","otherUp","thumb-up"]],[["اطلاعاتی که نیاز دارم وجود ندارد","missingTheInformationINeed","thumb-down"],["بیشازحد پیچیده/ مراحل بسیار زیاد","tooComplicatedTooManySteps","thumb-down"],["قدیمی","outOfDate","thumb-down"],["مشکل ترجمه","translationIssue","thumb-down"],["مشکل کد / نمونهها","samplesCodeIssue","thumb-down"],["غیره","otherDown","thumb-down"]],["تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی."],[],[],null,["# Support multiple game controllers\n\nWhile most games are designed to support a single user per Android device,\nit's also possible to support multiple users with game controllers that are\nconnected simultaneously on the same Android device.\n\nThis lesson covers some basic techniques for handling input in your single\ndevice multiplayer game from multiple connected controllers. This includes\nmaintaining a mapping between player avatars and each controller device and\nprocessing controller input events appropriately.\n\nMap players to controller device IDs\n------------------------------------\n\nWhen a game controller is connected to an Android device, the system\nassigns it an integer device ID. You can obtain the device IDs for connected\ngame controllers by calling [InputDevice.getDeviceIds()](/reference/android/view/InputDevice#getDeviceIds()), as shown in [Verify a Game Controller is Connected](/develop/ui/views/touch-and-input/game-controllers/controller-input#input). You can then associate each\ndevice ID with a player in your game, and process game actions for each player separately.\n\n**Note:** On devices running Android 4.1 (API\nlevel 16) and higher, you can obtain an input device's descriptor using\n[getDescriptor()](/reference/android/view/InputDevice#getDescriptor()), which returns a unique\npersistent string value for the input device. Unlike a device ID, the descriptor\nvalue won't change even if the input device is disconnected, reconnected, or\nreconfigured.\n\nThe code snippet below shows how to use a [SparseArray](/reference/android/util/SparseArray)\nto associate a player's avatar with a specific controller. In this example, the\n`mShips` variable stores a collection of `Ship` objects. A new\nplayer avatar is created in-game when a new controller is attached by a user,\nand removed when its associated controller is removed.\n\nThe `onInputDeviceAdded()` and `onInputDeviceRemoved()` callback\nmethods are part of the abstraction layer introduced in\n[Supporting Controllers Across Android Versions](/training/game-controllers/compatibility#status_callbacks}). By implementing these\nlistener callbacks, your game can identify the game controller's device ID when a\ncontroller is added or removed. This detection is compatible with Android 2.3\n(API level 9) and higher. \n\n### Kotlin\n\n```kotlin\nprivate val ships = SparseArray\u003cShip\u003e()\n\noverride fun onInputDeviceAdded(deviceId: Int) {\n getShipForID(deviceId)\n}\n\noverride fun onInputDeviceRemoved(deviceId: Int) {\n removeShipForID(deviceId)\n}\n\nprivate fun getShipForID(shipID: Int): Ship {\n return ships.get(shipID) ?: Ship().also {\n ships.append(shipID, it)\n }\n}\n\nprivate fun removeShipForID(shipID: Int) {\n ships.remove(shipID)\n}\n```\n\n### Java\n\n```java\nprivate final SparseArray\u003cShip\u003e ships = new SparseArray\u003cShip\u003e();\n\n@Override\npublic void onInputDeviceAdded(int deviceId) {\n getShipForID(deviceId);\n}\n\n@Override\npublic void onInputDeviceRemoved(int deviceId) {\n removeShipForID(deviceId);\n}\n\nprivate Ship getShipForID(int shipID) {\n Ship currentShip = ships.get(shipID);\n if ( null == currentShip ) {\n currentShip = new Ship();\n ships.append(shipID, currentShip);\n }\n return currentShip;\n}\n\nprivate void removeShipForID(int shipID) {\n ships.remove(shipID);\n}\n```\n\nProcess multiple controller input\n---------------------------------\n\nYour game should execute the following loop to process\ninput from multiple controllers:\n\n1. Detect whether an input event occurred.\n2. Identify the input source and its device ID.\n3. Based on the action indicated by the input event key code or axis value, update the player avatar associated with that device ID.\n4. Render and update the user interface.\n\n[KeyEvent](/reference/android/view/KeyEvent) and [MotionEvent](/reference/android/view/MotionEvent) input\nevents have device IDs associated with them. Your game can take advantage of\nthis to determine which controller the input event came from, and update the\nplayer avatar associated with that controller.\n\nThe following code snippet shows how you might get a player avatar reference\ncorresponding to a game controller device ID, and update the game based on the\nuser's button press on that controller. \n\n### Kotlin\n\n```kotlin\noverride fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {\n if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) {\n event.deviceId.takeIf { it != -1 }?.also { deviceId -\u003e\n val currentShip: Ship = getShipForID(deviceId)\n // Based on which key was pressed, update the player avatar\n // (e.g. set the ship headings or fire lasers)\n return true\n }\n }\n return super.onKeyDown(keyCode, event)\n}\n```\n\n### Java\n\n```java\n@Override\npublic boolean onKeyDown(int keyCode, KeyEvent event) {\n if ((event.getSource() & InputDevice.SOURCE_GAMEPAD)\n == InputDevice.SOURCE_GAMEPAD) {\n int deviceId = event.getDeviceId();\n if (deviceId != -1) {\n Ship currentShip = getShipForId(deviceId);\n // Based on which key was pressed, update the player avatar\n // (e.g. set the ship headings or fire lasers)\n ...\n return true;\n }\n }\n return super.onKeyDown(keyCode, event);\n}\n```\n\n**Note:**As a best practice, when a user's\ngame controller disconnects, you should pause the game and ask if the user\nwants to reconnect."]]