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

แม้ว่าเกมส่วนใหญ่ออกแบบมาเพื่อรองรับผู้ใช้ 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);
}

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

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

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

หมายเหตุ: ตามแนวทางปฏิบัติที่ดีที่สุด เมื่อผู้ใช้ เกมคอนโทรลเลอร์ยกเลิกการเชื่อมต่อ คุณควรหยุดเกมชั่วคราวแล้วถามผู้ใช้ ต้องการเชื่อมต่อใหม่