รองรับอุปกรณ์ควบคุมเกมหลายตัว
จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน
บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ
แม้ว่าเกมส่วนใหญ่ออกแบบมาเพื่อรองรับผู้ใช้ 1 คนต่ออุปกรณ์ Android 1 เครื่อง
คุณยังสามารถรองรับผู้ใช้หลายคนด้วยตัวควบคุมเกมที่
ที่เชื่อมต่อพร้อมกันได้ในอุปกรณ์ Android เครื่องเดียวกัน
บทเรียนนี้ครอบคลุมเทคนิคพื้นฐานบางประการสำหรับการจัดการการป้อนข้อมูลในซิงเกิลของคุณ
เกมที่มีอุปกรณ์แบบผู้เล่นหลายคนจากตัวควบคุมหลายรายการที่เชื่อมต่ออยู่ ซึ่งรวมถึง
การดูแลรักษาการแมประหว่างรูปโปรไฟล์ผู้เล่นและอุปกรณ์ควบคุมแต่ละเครื่อง และ
ประมวลผลเหตุการณ์อินพุตตัวควบคุมอย่างเหมาะสม
แมปผู้เล่นกับรหัสอุปกรณ์ตัวควบคุม
เมื่อเกมคอนโทรลเลอร์เชื่อมต่อกับอุปกรณ์ Android ระบบจะ
กำหนดรหัสอุปกรณ์เป็นจำนวนเต็ม คุณสามารถรับรหัสอุปกรณ์สำหรับการเชื่อมต่อ
ตัวควบคุมเกมโดยโทรหา InputDevice.getDeviceIds()
ดังที่แสดงในยืนยันว่าตัวควบคุมเกมเชื่อมต่อแล้ว จากนั้น คุณสามารถเชื่อมโยง
รหัสอุปกรณ์ที่มีผู้เล่นอยู่ในเกม และประมวลผลการดำเนินการในเกมสำหรับผู้เล่นแต่ละคนแยกกัน
หมายเหตุ: ในอุปกรณ์ที่ใช้ Android 4.1 (API
ระดับ 16) ขึ้นไป คุณสามารถดูตัวบอกลักษณะของอุปกรณ์อินพุตได้โดยใช้
getDescriptor()
ซึ่งแสดงผลค่าที่ไม่ซ้ำกัน
ค่าสตริงถาวรสำหรับอุปกรณ์อินพุต ตัวบ่งชี้ต่างจากรหัสอุปกรณ์
จะไม่เปลี่ยนแปลงแม้ว่าอุปกรณ์อินพุตจะไม่ได้เชื่อมต่อ เชื่อมต่อใหม่ หรือ
กำหนดค่าใหม่หรือไม่
ข้อมูลโค้ดด้านล่างแสดงวิธีใช้ SparseArray
เพื่อเชื่อมโยงอวาตาร์ของผู้เล่นกับตัวควบคุมที่เจาะจง ในตัวอย่างนี้
ตัวแปร mShips
จัดเก็บคอลเล็กชันของออบเจ็กต์ Ship
รายการ ใหม่
ระบบจะสร้างรูปโปรไฟล์ของผู้เล่นในเกมเมื่อผู้ใช้แนบตัวควบคุมใหม่
และนำออกเมื่อมีการนำตัวควบคุมที่เกี่ยวข้องออก
การติดต่อกลับของ onInputDeviceAdded()
และ onInputDeviceRemoved()
เป็นส่วนหนึ่งของชั้นแอบสแตรกต์ที่แนะนำใน
การรองรับตัวควบคุมใน Android เวอร์ชันต่างๆ โดยการใช้สิ่งเหล่านี้
Listener Callback เกมของคุณสามารถระบุรหัสอุปกรณ์ของตัวควบคุมเกมเมื่อ
มีการเพิ่มหรือนำตัวควบคุมออก การตรวจหานี้เข้ากันได้กับ Android 2.3
(API ระดับ 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);
}
หมายเหตุ: ตามแนวทางปฏิบัติที่ดีที่สุด เมื่อผู้ใช้
เกมคอนโทรลเลอร์ยกเลิกการเชื่อมต่อ คุณควรหยุดเกมชั่วคราวแล้วถามผู้ใช้
ต้องการเชื่อมต่อใหม่
ตัวอย่างเนื้อหาและโค้ดในหน้าเว็บนี้ขึ้นอยู่กับใบอนุญาตที่อธิบายไว้ในใบอนุญาตการใช้เนื้อหา Java และ OpenJDK เป็นเครื่องหมายการค้าหรือเครื่องหมายการค้าจดทะเบียนของ Oracle และ/หรือบริษัทในเครือ
อัปเดตล่าสุด 2025-07-26 UTC
[[["เข้าใจง่าย","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-26 UTC"],[],[],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."]]