Google Play Games đang ở giai đoạn thử nghiệm công khai.

Nhập bằng chuột

Chủ đề này hướng dẫn cách triển khai nhập liệu bằng chuột cho Google Play Games đối với 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ợ nhập liệu bằng chuột hay không. Theo mặc định, Google Play Games chuyển đổi mọi sự kiện nhấp chuột trái thành một sự kiện nhấn ảo đơn. Đâ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:

  • Di chuột qua các trạng thái đối với trình đơn theo bối cảnh thay vì thực hiện thao tác nhấn và giữ
  • Nhấp chuột phải vào các hành động thay thế 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 cho người thứ nhất và thứ 3 trong các trò chơi hành động chứ không phải là sự kiện nhấn và kéo

Để 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ý đầu vào cho Google Play Games giống y hệt 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 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 thấy 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 chính thức của Google Play Games sẽ chuyển sang chế độ chính xác 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 Tùy chọn cho nhà phát triển, sau đó nhấp vào Tương đối để nhận dữ liệu đầu vào thô qua chuột.

Ảnh chụp màn hình của mục &quot;Tương đối&quot; được chọn trong trình đơn theo bối cảnh

Sau khi thao tác xong, bạn cần di chuyển chuột đượ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 nhập bằng chuột, vui lòng 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, cho phép bạn hiển thị hộp gợi ý hoặc triển khai trạng thái di chuột để đá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 chuột

Từ lâu, máy tính đã có cả nút chuột trái và chuột phải, cung cấp các phần tử tương tác cho cả hành động chính lẫn hành động phụ. Trong một trò chơi, các hành động nhấn như nhấn vào nút được ánh xạ theo cách phù hợp nhất đến thao tác nhấp chuột trái, ở đó các thao tác nhấn và giữ được thể hiện theo cách tự nhiên nhất khi nhấp vào 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 bắn súng ở vị trí đầu tiên có thể chỉ định lửa chính và phụ qua thao tác nhấp chuột trái và chuột phải. Bạn có thể sử dụng thao tác nhấp chuột trái để nhảy và nhấp chuột phải để lao tới trong trò chơi chạy vô hạn.

Để 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ụ này, một giá trị enum được dùng để hiển thị kết quả của getActionButton:

Kotlin

enum class MouseButton {
   LEFT,
   RIGHT,
   MIDDLE,
   UNKNOWN;
   companion object {
       fun fromMotionEvent(motionEvent: MotionEvent): MouseButton {
           return when (motionEvent.actionButton) {
               MotionEvent.BUTTON_PRIMARY -> LEFT
               MotionEvent.BUTTON_SECONDARY -> RIGHT
               MotionEvent.BUTTON_TERTIARY -> MIDDLE
               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;
            case MotionEvent.BUTTON_TERTIARY:
                return MouseButton.MIDDLE;
            default:
                return MouseButton.UNKNOWN;
        }
    }
}

Trong ví dụ nà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 nhấn 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 đối với hiệu ứng bóng đổ theo chiều dọc và AXIS_HSCROLL 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 lại dữ liệu nhập 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ư người thứ nhất hoặc thứ ba trong trò chơi hành động giúp ánh xạ chuyển động của chuột đến chuyển động của máy ảnh. Để sử dụng chế độ kiểm soát chuột độc quyền, hãy gọi View.requestPointerCapture().

requestPointerCapture() chỉ hoạt động khi hệ phân cấp chế độ xem có chứa thành phần hiển thị được đặt tiêu đ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 tương tác của người chơi để thu nạp con trỏ chuột, chẳng hạn như khi 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 OnCapturedPointerListener đã đăng ký. Ví dụ:

Kotlin

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

Java

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

Để phát hành tính năng chụp chuột độc quyền, chẳng hạn như cho phép người chơi tương tác với trình đơn tạm dừng, hãy gọi View.releasePointerCapture().