รองรับอุปกรณ์ควบคุมเกมหลายตัว

แม้ว่าเกมส่วนใหญ่จะออกแบบมาให้รองรับผู้ใช้คนเดียวต่ออุปกรณ์ที่ใช้ 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);
}

ประมวลผลอินพุตของตัวควบคุมหลายตัว

เกมของคุณควรเรียกใช้ลูปต่อไปนี้เพื่อประมวลผลอินพุตจากคอนโทรลเลอร์หลายตัว

  1. ตรวจหาว่ามีเหตุการณ์อินพุตเกิดขึ้นหรือไม่
  2. ระบุแหล่งที่มาของอินพุตและรหัสอุปกรณ์
  3. อัปเดตอวาตาร์ของผู้เล่นที่เชื่อมโยงกับรหัสอุปกรณ์นั้นตามการกระทําที่ระบุโดยรหัสคีย์ของเหตุการณ์อินพุตหรือค่าแกน
  4. แสดงผลและอัปเดตอินเทอร์เฟซผู้ใช้

เหตุการณ์อินพุต 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);
}