การป้อนข้อมูลด้วยเมาส์

หัวข้อนี้จะอธิบายวิธีใช้การป้อนข้อมูลด้วยเมาส์สำหรับ Google Play Games บน PC สำหรับเกมที่โหมดการแปลอินพุตให้ประสบการณ์การใช้งานที่ไม่เหมาะสม

โดยทั่วไปผู้เล่น PC จะมีแป้นพิมพ์และเมาส์แทนหน้าจอสัมผัส คุณจึงควรพิจารณาว่าเกมของคุณรองรับการป้อนข้อมูลด้วยเมาส์หรือไม่ โดยค่าเริ่มต้น Google Play Games บน PC จะแปลงเหตุการณ์การคลิกเมาส์ซ้ายเป็นการแตะเสมือนจริงเพียงครั้งเดียว ซึ่งเรียกว่า "โหมดการแปลอินพุต"

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

  • สถานะวางเมาส์เหนือสำหรับเมนูตามบริบทแทนการกดการดำเนินการค้างไว้
  • คลิกขวาเพื่อดูการดำเนินการอื่นๆ ที่เกิดขึ้นเมื่อกดค้างหรือในเมนูตามบริบท
  • การมองด้วยเมาส์สำหรับเกมแอ็กชันมุมมองบุคคลที่หนึ่งหรือบุคคลที่สามแทนการใช้การกดและลาก

คุณต้องปิดใช้โหมดการแปลการป้อนข้อมูลเพื่อรองรับรูปแบบ UI ที่ใช้กันทั่วไปใน PC

การจัดการการป้อนข้อมูลสำหรับ Google Play Games บน PC จะเหมือนกับของ ChromeOS การเปลี่ยนแปลงที่รองรับ PC จะปรับปรุงเกมของคุณสำหรับผู้เล่น Android ทุกคนด้วย

ปิดใช้โหมดการแปลอินพุต

ในไฟล์ AndroidManifest.xml ให้ประกาศฟีเจอร์ android.hardware.type.pc ซึ่งหมายความว่าเกมของคุณใช้ฮาร์ดแวร์ PC และปิดใช้โหมดการแปลอินพุต นอกจากนี้ การเพิ่ม required="false" ยังช่วยให้มั่นใจได้ว่าเกมจะยังคงติดตั้งในโทรศัพท์และแท็บเล็ตได้โดยไม่ต้องใช้เมาส์ เช่น

<manifest ...>
  <uses-feature
      android:name="android.hardware.type.pc"
      android:required="false" />
  ...
</manifest>

Google Play Games บน PC เวอร์ชันที่ใช้งานจริงจะเปลี่ยนไปใช้โหมดที่ถูกต้องเมื่อเปิดตัวเกม เมื่อทำงานในโปรแกรมจำลองของนักพัฒนาซอฟต์แวร์ คุณต้องคลิกขวาที่ไอคอนแถบงาน เลือกตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ แล้วคลิกโหมด PC(KiwiMouse) เพื่อรับอินพุตเมาส์ดิบ

ภาพหน้าจอของ &quot;โหมด PC(KiwiMouse)&quot; ที่เลือกในเมนูตามบริบท

หลังจากนั้น ระบบจะรายงานการเคลื่อนไหวของเมาส์ตาม View.ongenericMotionEvent โดยแหล่งที่มา SOURCE_MOUSE ระบุว่าเป็นเหตุการณ์ของเมาส์

Kotlin

gameView.setOnGenericMotionListener { _, motionEvent ->
    var handled = false
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // handle the mouse event here
        handled = true
    }
    handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // handle the mouse event here
        return true;
    }
    return false;
});

ดูรายละเอียดเกี่ยวกับการจัดการอินพุตเมาส์ได้ที่เอกสารประกอบของ ChromeOS

การจัดการการเคลื่อนไหวของเมาส์

หากต้องการตรวจจับการเคลื่อนไหวของเมาส์ ให้ฟังเหตุการณ์ ACTION_HOVER_ENTER, ACTION_HOVER_EXIT และ ACTION_HOVER_MOVE

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

Kotlin

gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when(motionEvent.action) {
           MotionEvent.ACTION_HOVER_ENTER -> Log.d("MA", "Mouse entered at ${motionEvent.x}, ${motionEvent.y}")
           MotionEvent.ACTION_HOVER_EXIT -> Log.d("MA", "Mouse exited at ${motionEvent.x}, ${motionEvent.y}")
           MotionEvent.ACTION_HOVER_MOVE -> Log.d("MA", "Mouse hovered at ${motionEvent.x}, ${motionEvent.y}")
       }
       handled = true
   }

   handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_HOVER_ENTER:
                Log.d("MA", "Mouse entered at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_HOVER_EXIT:
                Log.d("MA", "Mouse exited at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_HOVER_MOVE:
                Log.d("MA", "Mouse hovered at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
        }
        return true;
    }
    return false;
});

การจัดการปุ่มเมาส์

คอมพิวเตอร์มีปุ่มเมาส์ทั้งซ้ายและขวามาอย่างยาวนานแล้ว ซึ่งทำให้องค์ประกอบแบบอินเทอร์แอกทีฟมีการดำเนินการทั้งหลักและรอง ในเกม การแตะการกระทำต่างๆ เช่น การแตะปุ่ม ควรแมปกับคลิกซ้าย ส่วนการแตะค้างไว้ควรแมปกับคลิกขวา ในเกมกลยุทธ์แบบเรียลไทม์ คุณอาจใช้การคลิกซ้ายเพื่อเลือกและคลิกขวาเพื่อย้าย เกมยิงมุมมองบุคคลที่หนึ่งอาจกำหนดการยิงหลักและรองเป็นคลิกซ้ายและขวา เกมวิ่งที่ไม่มีจุดสิ้นสุดอาจใช้การคลิกซ้ายเพื่อกระโดดและคลิกขวาเพื่อพุ่ง เรายังไม่ได้เพิ่มการรองรับเหตุการณ์การคลิกกลาง

หากต้องการจัดการการกดปุ่ม ให้ใช้ ACTION_DOWN และ ACTION_UP จากนั้นใช้ getActionButton เพื่อระบุปุ่มที่เรียกใช้การดำเนินการ หรือ getButtonState เพื่อดูสถานะของปุ่มทั้งหมด

ในตัวอย่างนี้จะใช้ enum เพื่อช่วยแสดงผลลัพธ์ของ getActionButton

Kotlin

enum class MouseButton {
   LEFT,
   RIGHT,
   UNKNOWN;
   companion object {
       fun fromMotionEvent(motionEvent: MotionEvent): MouseButton {
           return when (motionEvent.actionButton) {
               MotionEvent.BUTTON_PRIMARY -> LEFT
               MotionEvent.BUTTON_SECONDARY -> RIGHT
               else -> UNKNOWN
           }
       }
   }
}

Java

enum MouseButton {
    LEFT,
    RIGHT,
    MIDDLE,
    UNKNOWN;
    static MouseButton fromMotionEvent(MotionEvent motionEvent) {
        switch (motionEvent.getActionButton()) {
            case MotionEvent.BUTTON_PRIMARY:
                return MouseButton.LEFT;
            case MotionEvent.BUTTON_SECONDARY:
                return MouseButton.RIGHT;
            default:
                return MouseButton.UNKNOWN;
        }
    }
}

ในตัวอย่างนี้ ระบบจะจัดการการดําเนินการคล้ายกับเหตุการณ์การโฮเวอร์

Kotlin

// Handle the generic motion event
gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when (motionEvent.action) {
           MotionEvent.ACTION_BUTTON_PRESS -> Log.d(
               "MA",
               "${MouseButton.fromMotionEvent(motionEvent)} pressed at ${motionEvent.x}, ${motionEvent.y}"
           )
           MotionEvent.ACTION_BUTTON_RELEASE -> Log.d(
               "MA",
               "${MouseButton.fromMotionEvent(motionEvent)} released at ${motionEvent.x}, ${motionEvent.y}"
           )
       }
       handled = true
   }

   handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_BUTTON_PRESS:
                Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " pressed at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_BUTTON_RELEASE:
                Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " released at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
        }
        return true;
    }
    return false;
});

จัดการการเลื่อนด้วยลูกล้อของเมาส์

เราขอแนะนำให้คุณใช้ปุ่มลูกกลิ้งของเมาส์แทนการใช้ท่าทางสัมผัสเพื่อซูม หรือแตะและลากพื้นที่เลื่อนในเกม

หากต้องการอ่านค่าของล้อเลื่อน ให้รอฟังเหตุการณ์ ACTION_SCROLL เดลต้าเนื่องจากเฟรมสุดท้ายดึงได้โดยใช้ getAxisValue ร่วมกับ AXIS_VSCROLL สำหรับออฟเซ็ตแนวตั้งและ AXIS_HSCROLL สำหรับออฟเซ็ตแนวนอน เช่น

Kotlin

gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when (motionEvent.action) {
           MotionEvent.ACTION_SCROLL -> {
               val scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL)
               val scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL)
               Log.d("MA", "Mouse scrolled $scrollX, $scrollY")
           }
       }
       handled = true
   }
   handled
}

Java

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_SCROLL:
                float scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL);
                float scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL);
                Log.d("MA", "Mouse scrolled " + scrollX + ", " + scrollY);
                break;
        }
        return true;
    }
    return false;
});

บันทึกอินพุตจากเมาส์

บางเกมจำเป็นต้องควบคุมเคอร์เซอร์เมาส์อย่างเต็มรูปแบบ เช่น เกมแอ็กชันมุมมองบุคคลที่หนึ่งหรือบุคคลที่สามซึ่งจับคู่การเคลื่อนไหวของเมาส์กับการเคลื่อนไหวของกล้อง หากต้องการควบคุมเมาส์แต่เพียงผู้เดียว ให้เรียกใช้ View.requestPointerCapture()

requestPointerCapture() จะใช้งานได้เมื่อลําดับชั้นมุมมองที่มีมุมมองของคุณมีโฟกัสเท่านั้น ด้วยเหตุนี้ คุณจึงไม่ได้รับการบันทึกตัวชี้ในการเรียกกลับ onCreate คุณควรรอการโต้ตอบของผู้เล่นเพื่อจับเคอร์เซอร์เมาส์ เช่น เมื่อโต้ตอบกับเมนูหลัก หรือใช้การเรียกกลับ onWindowFocusChanged เช่น

Kotlin

override fun onWindowFocusChanged(hasFocus: Boolean) {
   super.onWindowFocusChanged(hasFocus)

   if (hasFocus) {
       gameView.requestPointerCapture()
   }
}

Java

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    if (hasFocus) {
        View gameView = findViewById(R.id.game_view);
        gameView.requestPointerCapture();
    }
}

ระบบจะส่งเหตุการณ์ที่บันทึกโดย requestPointerCapture() ไปยังมุมมองที่โฟกัสได้ซึ่งลงทะเบียนไว้ OnCapturedPointerListener เช่น

Kotlin

gameView.focusable = View.FOCUSABLE
gameView.setOnCapturedPointerListener { _, motionEvent ->
    Log.d("MA", "${motionEvent.x}, ${motionEvent.y}, ${motionEvent.actionButton}")
    true
}

Java

gameView.setFocusable(true);
gameView.setOnCapturedPointerListener((view, motionEvent) -> {
    Log.d("MA", motionEvent.getX() + ", " + motionEvent.getY() + ", " + motionEvent.getActionButton());
    return true;
});

หากต้องการปล่อยการจับภาพเมาส์แบบพิเศษ เช่น เพื่อให้ผู้เล่นโต้ตอบกับเมนูหยุดชั่วคราว ให้เรียกใช้ View.releasePointerCapture()