แม้ว่าเกมส่วนใหญ่จะออกแบบมาให้รองรับผู้ใช้คนเดียวต่ออุปกรณ์ที่ใช้ Android แต่ก็สามารถรองรับผู้ใช้หลายคนด้วยเกมคอนโทรลเลอร์ที่เชื่อมต่อพร้อมกันในอุปกรณ์ที่ใช้ Android เครื่องเดียวกันได้เช่นกัน
บทเรียนนี้จะครอบคลุมเทคนิคพื้นฐานบางอย่างในการจัดการอินพุตในเกมแบบผู้เล่นหลายคนบนอุปกรณ์เครื่องเดียวจากตัวควบคุมที่เชื่อมต่อหลายตัว ซึ่งรวมถึง การรักษาการแมประหว่างอวตารของผู้เล่นกับอุปกรณ์ควบคุมแต่ละเครื่อง และ การประมวลผลเหตุการณ์อินพุตของตัวควบคุมอย่างเหมาะสม
แมปผู้เล่นกับรหัสอุปกรณ์ของคอนโทรลเลอร์
เมื่อเชื่อมต่อเกมคอนโทรลเลอร์กับอุปกรณ์ที่ใช้ Android ระบบจะกำหนดรหัสอุปกรณ์ที่เป็นจำนวนเต็มให้
คุณขอรับรหัสอุปกรณ์สำหรับเกมคอนโทรลเลอร์ที่เชื่อมต่อได้โดยการเรียกใช้ InputDevice.getDeviceIds() ตามที่แสดงในยืนยันว่าเกมคอนโทรลเลอร์เชื่อมต่ออยู่ จากนั้นคุณจะเชื่อมโยงรหัสอุปกรณ์แต่ละเครื่องกับผู้เล่นในเกม และประมวลผลการกระทำในเกมสำหรับผู้เล่นแต่ละคนแยกกันได้
ข้อมูลโค้ดแสดงวิธีใช้ SparseArray เพื่อเชื่อมโยงอวาตาร์ของผู้เล่นกับคอนโทรลเลอร์ที่เฉพาะเจาะจง ในตัวอย่างนี้ mShips
ตัวแปรจะจัดเก็บคอลเล็กชันของออบเจ็กต์ Ship ระบบจะสร้างอวาตาร์ผู้เล่นใหม่ในเกมเมื่อผู้ใช้เชื่อมต่อคอนโทรลเลอร์ใหม่ และจะนำออกเมื่อมีการนำคอนโทรลเลอร์ที่เชื่อมโยงออก
เมธอดเรียกกลับ onInputDeviceAdded() และ onInputDeviceRemoved()
เป็นส่วนหนึ่งของเลเยอร์การแยกข้อมูลที่เปิดตัวในการรองรับตัวควบคุมใน
Android เวอร์ชันต่างๆ
การใช้การเรียกกลับของ Listener เหล่านี้จะช่วยให้เกมระบุรหัสอุปกรณ์ของ
เกมคอนโทรลเลอร์ได้เมื่อมีการเพิ่มหรือนำคอนโทรลเลอร์ออก การตรวจหา
นี้ใช้ได้กับ 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);
}