Dữ liệu nhập từ chuột

Chủ đề này hướng dẫn cách triển khai thao tác đầu vào bằng chuột cho Google Play Games trên máy tính khi trò chơi có chế độ dịch dữ liệu đầu vào không mang lại trải nghiệm lý tưởng cho người chơi.

Người chơi trên máy tính thường sử dụng bàn phím và chuột thay vì màn hình cảm ứng. Do đó, điều quan trọng cần xem xét là liệu trò chơi của bạn có hỗ trợ xử lý thao tác đầu vào bằng chuột hay không. Theo mặc định, Google Play Games trên máy tính sẽ chuyển đổi mỗi sự kiện nhấp chuột trái thành một sự kiện nhấn một lần ảo. Đây được gọi là "chế độ dịch dữ liệu đầu vào".

Mặc dù chế độ này khiến trò chơi của bạn hoạt động với một vài thay đổi, nhưng nó không mang lại trải nghiệm tự nhiên thoải mái cho người chơi trên máy tính. Để làm được điều đó, bạn nên triển khai những nội dung sau:

  • Áp dụng các trạng thái khi di chuột thay vì các hành động nhấn và giữ cho trình đơn theo bối cảnh
  • Nhấp chuột phải để thực hiện các hành động thay thế vốn diễn ra khi nhấn và giữ hoặc trong một trình đơn theo bối cảnh
  • Sử dụng mouselook thay vì sự kiện nhấn và kéo cho các trò chơi hành động góc nhìn người thứ nhất và thứ ba

Để hỗ trợ các mẫu giao diện người dùng phổ biến trên máy tính, bạn phải tắt chế độ dịch dữ liệu đầu vào.

Hoạt động xử lý dữ liệu đầu vào cho Google Play Games trên máy tính giống hoàn toàn như trong ChromeOS. Những thay đổi hỗ trợ máy tính cũng góp phần cải thiện trò chơi của bạn cho tất cả người chơi trên Android.

Tắt chế độ dịch dữ liệu đầu vào

Trong tệp AndroidManifest.xml, hãy khai báo tính năng android.hardware.type.pc. Điều này cho biết rằng trò chơi của bạn sử dụng phần cứng của máy tính và tắt chế độ dịch dữ liệu đầu vào. Ngoài ra, việc thêm required="false" giúp đảm bảo trò chơi của bạn vẫn có thể được cài đặt trên điện thoại và máy tính bảng mà không cần chuột. Ví dụ:

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

Phiên bản phát hành công khai của Google Play Games trên máy tính sẽ chuyển sang chế độ phù hợp khi trò chơi ra mắt. Khi chạy trong trình mô phỏng dành cho nhà phát triển, bạn cần nhấp chuột phải vào biểu tượng thanh tác vụ, chọn Tuỳ chọn cho nhà phát triển rồi chọn Chế độ máy tính (KiwiMouse) để nhận thao tác đầu vào thô bằng chuột.

Ảnh chụp màn hình của mục "Chế độ máy tính (KiwiMouse)" được chọn trong trình đơn theo bối cảnh

Sau khi làm như vậy, chuyển động của chuột sẽ được báo cáo bằng View.onGenericMotionEvent với nguồn SOURCE_MOUSE cho biết đó là một sự kiện chuột.

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

Để biết thông tin chi tiết về cách xử lý thao tác đầu vào bằng chuột, hãy xem phần Tài liệu dành cho ChromeOS.

Xử lý chuyển động của chuột

Để phát hiện chuyển động của chuột, vui lòng theo dõi các sự kiện ACTION_HOVER_ENTER, ACTION_HOVER_EXITACTION_HOVER_MOVE.

Bạn nên sử dụng tính năng này để phát hiện khi người dùng di chuột qua các nút hoặc đối tượng trong trò chơi. Qua đó, bạn có thể hiển thị hộp gợi ý hoặc triển khai trạng thái di chuột qua để đánh dấu nội dung mà người chơi sắp chọn. Ví dụ:

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

Xử lý các nút trên chuột

Từ lâu, chuột máy tính đã có cả nút chuột trái và nút chuột phải, hoạt động như các phần tử tương tác cho cả hành động chính lẫn hành động phụ. Trong trò chơi, các thao tác nhấn như nhấn vào nút trong trò chơi tốt nhất nên được ánh xạ đến hành động nhấp chuột trái, còn các thao tác chạm và giữ mang lại cảm giác tự nhiên nhất khi được ánh xạ đến hành động nhấp chuột phải. Trong các trò chơi chiến lược theo thời gian thực, bạn cũng có thể sử dụng chuột trái để chọn và nhấp chuột phải khi cần di chuyển. Người chơi trò chơi bắn súng góc nhìn người thứ nhất có thể dùng vũ khí chính với chuột trái và vũ khí phụ với chuột phải. Người chơi trò chơi chạy vô tận có thể nhấp chuột trái để nhảy và nhấp chuột phải để lướt. Chúng tôi chưa hỗ trợ sự kiện nhấp chuột giữa.

Để xử lý các lần nhấn nút, hãy sử dụng ACTION_DOWNACTION_UP. Sau đó, sử dụng getActionButton để xác định nút nào đã kích hoạt hành động hoặc getButtonState để biết trạng thái của tất cả các nút.

Trong ví dụ dưới đây, một giá trị enum được dùng để hiển thị kết quả của 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;
        }
    }
}

Trong ví dụ dưới đây, thao tác được xử lý tương tự như các sự kiện di chuột:

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

Xử lý thao tác cuộn con lăn chuột

Bạn nên sử dụng con lăn chuột thay cho cử chỉ chụm để thu phóng hoặc chạm và kéo các vùng cuộn trong trò chơi.

Để đọc các giá trị của con lăn chuột, vui lòng theo dõi sự kiện ACTION_SCROLL. Delta kể từ khung hình cuối cùng có thể được truy xuất bằng getAxisValue với AXIS_VSCROLL khi cuộn theo chiều dọc và AXIS_HSCROLL khi cuộn theo chiều ngang. Ví dụ:

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

Ghi nhận thao tác đầu vào bằng chuột

Một số trò chơi cần có toàn quyền kiểm soát con trỏ chuột (chẳng hạn như trò chơi hành động góc nhìn người thứ nhất hoặc thứ ba) để ánh xạ chuyển động của chuột với chuyển động của màn hình. Để sử dụng chế độ độc quyền kiểm soát chuột, hãy gọi View.requestPointerCapture().

requestPointerCapture() chỉ hoạt động khi hệ phân cấp khung hiển thị chứa khung hiển thị của bạn có tâm điểm. Do đó, bạn không thể thu nạp con trỏ trong lệnh gọi lại onCreate. Bạn nên đợi người chơi tương tác để thu nạp con trỏ chuột (chẳng hạn như khi họ tương tác với trình đơn chính) hoặc sử dụng lệnh gọi lại onWindowFocusChanged. Ví dụ:

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

Những sự kiện mà requestPointerCapture() ghi lại sẽ được gửi đến khung hiển thị có thể làm tâm điểm đã đăng ký OnCapturedPointerListener. Ví dụ:

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

Để huỷ chế độ độc quyền kiểm soát chuột, chẳng hạn như trong trường hợp người chơi cần tương tác với trình đơn tạm dừng, hãy gọi View.releasePointerCapture().