Ở cấp hệ thống, Android báo cáo mã sự kiện đầu vào từ tay điều khiển trò chơi làm mã khoá Android và giá trị trục. Trong trò chơi, bạn có thể nhận được những mã này và giá trị cũng như chuyển đổi chúng thành các hành động cụ thể trong trò chơi.
Khi người chơi kết nối thực tế hoặc ghép nối không dây tay điều khiển trò chơi với
thiết bị chạy Android của họ, hệ thống sẽ tự động phát hiện bộ điều khiển
làm thiết bị đầu vào và bắt đầu báo cáo các sự kiện đầu vào của thiết bị đó. Trò chơi của bạn có thể nhận
các sự kiện đầu vào này bằng cách triển khai các phương thức gọi lại sau đây trong
Activity
hoặc View
được lấy tiêu điểm (bạn nên
triển khai các lệnh gọi lại cho Activity
hoặc
View
, nhưng không phải cả hai):
- Từ
Activity
:dispatchGenericMotionEvent(android.view. MotionEvent)
Được gọi để xử lý các sự kiện chuyển động chung, chẳng hạn như chuyển động của cần điều khiển.
dispatchKeyEvent(android.view.KeyEvent)
Được gọi để xử lý các sự kiện chính, chẳng hạn như nhấn hoặc thả tay điều khiển trò chơi hoặc nút D-pad.
- Từ
View
:onGenericMotionEvent(android.view.MotionEvent)
Được gọi để xử lý các sự kiện chuyển động chung, chẳng hạn như chuyển động của cần điều khiển.
onKeyDown(int, android.view.KeyEvent)
Được gọi để xử lý thao tác nhấn một phím vật lý, chẳng hạn như tay điều khiển trò chơi hoặc Nút D-pad.
onKeyUp(int, android.view.KeyEvent)
Được gọi để xử lý thao tác nhả phím vật lý, chẳng hạn như tay điều khiển trò chơi hoặc Nút D-pad.
Bạn nên nắm bắt các sự kiện từ
đối tượng View
cụ thể mà người dùng tương tác.
Kiểm tra các đối tượng do lệnh gọi lại cung cấp sau đây để lấy thông tin
về loại sự kiện đầu vào nhận được:
KeyEvent
- Đối tượng mô tả phương hướng
pad (D-pad) và sự kiện nút trên tay điều khiển trò chơi. Sự kiện chính đi kèm với
mã phím cho biết nút cụ thể được kích hoạt, chẳng hạn như
DPAD_DOWN
hoặcBUTTON_A
. Bạn có thể lấy mã phím bằng cách gọigetKeyCode()
hoặc từ khoá các lệnh gọi lại sự kiện nhưonKeyDown()
MotionEvent
- Đối tượng mô tả thao tác đầu vào bằng cần điều khiển và nút kích hoạt bằng vai
chuyển động. Sự kiện chuyển động có một mã hành động và một tập hợp
giá trị trục. Mã hành động chỉ định thay đổi trạng thái đã xảy ra
chẳng hạn như cần điều khiển đang di chuyển. Các giá trị trục mô tả vị trí và các giá trị khác
thuộc tính chuyển động cho một thiết bị điều khiển vật lý cụ thể, chẳng hạn như
AXIS_X
hoặcAXIS_RTRIGGER
Bạn có thể lấy mã hành động bằng cách gọigetAction()
và giá trị trục bằng cách đang gọigetAxisValue()
.
Bài học này tập trung vào cách bạn có thể xử lý thông tin đầu vào từ các loại phổ biến nhất
các nút điều khiển vật lý (nút trên tay điều khiển trò chơi, bàn phím di chuyển và
cần điều khiển) trong màn hình trò chơi bằng cách triển khai các thao tác nêu trên
Đang xử lý và phương thức gọi lại View
Các đối tượng KeyEvent
và MotionEvent
.
Xác minh rằng bạn đã kết nối tay điều khiển trò chơi
Khi báo cáo sự kiện đầu vào, Android không phân biệt
giữa sự kiện đến từ một thiết bị không phải tay điều khiển trò chơi và sự kiện xảy ra
trên tay điều khiển trò chơi. Ví dụ: thao tác trên màn hình cảm ứng sẽ tạo ra
Sự kiện AXIS_X
đại diện cho X
nhưng cần điều khiển sẽ tạo ra
Sự kiện AXIS_X
đại diện cho vị trí X của cần điều khiển. Nếu
trò chơi của bạn quan tâm đến việc xử lý đầu vào bằng tay điều khiển trò chơi, trước tiên, bạn nên kiểm tra
rằng sự kiện đầu vào đến từ một loại nguồn có liên quan.
Để xác minh thiết bị đầu vào đã kết nối là tay điều khiển trò chơi, hãy gọi
getSources()
để lấy trường bit kết hợp của
loại nguồn đầu vào được hỗ trợ trên thiết bị đó. Sau đó, bạn có thể kiểm tra xem
các trường sau đây được đặt:
- Loại nguồn của
SOURCE_GAMEPAD
cho biết thiết bị đầu vào có các nút trên tay điều khiển trò chơi (ví dụ:BUTTON_A
). Lưu ý rằng nguồn này không chỉ rõ rằng bộ điều khiển trò chơi có các nút trên D-pad, mặc dù hầu hết các tay điều khiển trò chơi thường có tính năng điều khiển hướng. - Loại nguồn
SOURCE_DPAD
cho biết rằng thiết bị đầu vào có các nút D-pad (ví dụ:DPAD_UP
). - Loại nguồn của
SOURCE_JOYSTICK
cho biết thiết bị đầu vào có cần điều khiển analog (ví dụ: cần điều khiển ghi lại các chuyển động dọc theoAXIS_X
vàAXIS_Y
).
Đoạn mã sau đây cho thấy một phương thức trợ giúp cho phép bạn kiểm tra xem thiết bị đầu vào được kết nối là tay điều khiển trò chơi. Nếu có, phương thức này sẽ truy xuất mã thiết bị cho tay điều khiển trò chơi. Sau đó, bạn có thể liên kết từng thiết bị Mã nhận dạng với người chơi trong trò chơi của bạn và xử lý hành động trong trò chơi cho mỗi người chơi được kết nối trình phát riêng biệt. Để tìm hiểu thêm về cách hỗ trợ nhiều tay điều khiển trò chơi được kết nối đồng thời trên cùng một thiết bị Android, hãy xem Hỗ trợ nhiều tay điều khiển trò chơi.
Kotlin
fun getGameControllerIds(): List<Int> { val gameControllerDeviceIds = mutableListOf<Int>() val deviceIds = InputDevice.getDeviceIds() deviceIds.forEach { deviceId -> InputDevice.getDevice(deviceId).apply { // Verify that the device has gamepad buttons, control sticks, or both. if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD || sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK) { // This device is a game controller. Store its device ID. gameControllerDeviceIds .takeIf { !it.contains(deviceId) } ?.add(deviceId) } } } return gameControllerDeviceIds }
Java
public ArrayList<Integer> getGameControllerIds() { ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>(); int[] deviceIds = InputDevice.getDeviceIds(); for (int deviceId : deviceIds) { InputDevice dev = InputDevice.getDevice(deviceId); int sources = dev.getSources(); // Verify that the device has gamepad buttons, control sticks, or both. if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { // This device is a game controller. Store its device ID. if (!gameControllerDeviceIds.contains(deviceId)) { gameControllerDeviceIds.add(deviceId); } } } return gameControllerDeviceIds; }
Ngoài ra, bạn nên kiểm tra khả năng nhập dữ liệu riêng lẻ được hỗ trợ bởi tay điều khiển trò chơi đã kết nối. Điều này có thể hữu ích, chẳng hạn như nếu bạn muốn trò chơi của mình chỉ sử dụng dữ liệu đầu vào từ một tập hợp các nút điều khiển vật lý hiểu.
Để phát hiện xem một mã phím hoặc mã trục cụ thể có được hỗ trợ bởi tay điều khiển trò chơi, hãy sử dụng các kỹ thuật sau:
- Trong Android 4.4 (API cấp 19) trở lên, bạn có thể xác định xem mã khoá có
được hỗ trợ trên tay điều khiển trò chơi đã kết nối bằng cách gọi
hasKeys(int...)
. - Trong Android 3.1 (API cấp 12) trở lên, bạn có thể tìm thấy tất cả các trục hiện có
được hỗ trợ trên tay điều khiển trò chơi đã kết nối bằng cách gọi trước
getMotionRanges()
. Sau đó, trên mỗi Đã trả về đối tượngInputDevice.MotionRange
, hãy gọigetAxis()
để nhận mã trục.
Xử lý thao tác nhấn nút trên tay điều khiển trò chơi
Hình 1 thể hiện cách Android ánh xạ các mã khoá và giá trị trục đến dữ liệu thực trên hầu hết các tay điều khiển trò chơi.
![](https://developer.android.google.cn/static/images/training/game-controller-profiles.png?authuser=9&hl=vi)
Hình 1. Hồ sơ cho tay điều khiển trò chơi thông thường.
Các chú thích trong hình này đề cập đến:
Các mã phím phổ biến do các thao tác nhấn nút trên tay điều khiển trò chơi tạo ra bao gồm
BUTTON_A
,
BUTTON_B
,
BUTTON_SELECT
,
và BUTTON_START
. Trận đấu nào đó
các tay điều khiển cũng kích hoạt mã phím DPAD_CENTER
khi nhấn vào giữa thanh ngang của D-pad. Thông tin
trò chơi có thể kiểm tra mã phím bằng cách gọi getKeyCode()
hoặc qua các lệnh gọi lại sự kiện chính như
onKeyDown()
,
và nếu sự kiện đó đại diện cho một sự kiện có liên quan đến trò chơi, hãy xử lý sự kiện đó dưới dạng
hành động trong trò chơi. Bảng 1 liệt kê các hành động phổ biến nhất trong trò chơi, được đề xuất
nút trên tay điều khiển trò chơi.
Bảng 1. Các thao tác được đề xuất trong trò chơi cho tay điều khiển trò chơi các nút.
Hành động trong trò chơi | Mã phím nút |
---|---|
Bắt đầu trò chơi trong trình đơn chính hoặc tạm dừng/bỏ tạm dừng trong khi chơi | BUTTON_START * |
Hiện trình đơn | BUTTON_SELECT *
và KEYCODE_MENU * |
Giống như hành vi điều hướng Quay lại của Android được mô tả trong Thiết kế điều hướng của chúng tôi. | KEYCODE_BACK |
Quay lại mục trước trong một trình đơn | BUTTON_B |
Xác nhận lựa chọn hoặc thực hiện hành động chính trong trò chơi | BUTTON_A và
DPAD_CENTER |
* Trò chơi của bạn không nên phụ thuộc vào sự hiện diện của nút Bắt đầu, Chọn hoặc Trình đơn .
Mẹo: Cân nhắc việc cung cấp màn hình cấu hình trong trò chơi của mình để cho phép người dùng cá nhân hoá việc ánh xạ tay điều khiển trò chơi của riêng họ cho hành động trong trò chơi.
Đoạn mã sau đây hướng dẫn cách bạn có thể ghi đè
onKeyDown()
thành
liên kết BUTTON_A
và
DPAD_CENTER
lần nhấn nút
hành động trong trò chơi.
Kotlin
class GameView(...) : View(...) { ... override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { var handled = false if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) { if (event.repeatCount == 0) { when (keyCode) { // Handle gamepad and D-pad button presses to navigate the ship ... else -> { keyCode.takeIf { isFireKey(it) }?.run { // Update the ship object to fire lasers ... handled = true } } } } if (handled) { return true } } return super.onKeyDown(keyCode, event) } // Here we treat Button_A and DPAD_CENTER as the primary action // keys for the game. private fun isFireKey(keyCode: Int): Boolean = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A }
Java
public class GameView extends View { ... @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { if (event.getRepeatCount() == 0) { switch (keyCode) { // Handle gamepad and D-pad button presses to // navigate the ship ... default: if (isFireKey(keyCode)) { // Update the ship object to fire lasers ... handled = true; } break; } } if (handled) { return true; } } return super.onKeyDown(keyCode, event); } private static boolean isFireKey(int keyCode) { // Here we treat Button_A and DPAD_CENTER as the primary action // keys for the game. return keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A; } }
Lưu ý: Trên Android 4.2 (API
cấp 17) trở xuống, thì hệ thống sẽ xử lý
BUTTON_A
làm Android
Phím Quay lại theo mặc định. Nếu ứng dụng của bạn hỗ trợ các tính năng Android này
phiên bản, hãy nhớ áp dụng
BUTTON_A
là trận đấu chính
hành động. Để xác định SDK Android hiện tại
phiên bản của thiết bị, hãy tham khảo
Giá trị Build.VERSION.SDK_INT
.
Xử lý phương thức nhập bằng bàn phím di chuyển
Bàn phím di chuyển 4 chiều (D-pad) là một chức năng điều khiển vật lý phổ biến trong nhiều trò chơi
bộ điều khiển trò chơi. Android báo cáo số lần nhấn LÊN và XUỐNG D-pad là
AXIS_HAT_Y
sự kiện có phạm vi
từ -1 (lên) đến 1 (xuống) và D-pad nhấn TRÁI hoặc PHẢI là
AXIS_HAT_X
sự kiện có phạm vi từ -1
(trái) đến 1,0 (phải).
Một số bộ điều khiển báo cáo các lần nhấn D-pad bằng một mã phím. Nếu trò chơi của bạn quan tâm đến thao tác nhấn D-pad, bạn nên xử lý các sự kiện trục mũ và D-pad các mã chính với các sự kiện đầu vào tương tự, như được đề xuất trong bảng 2.
Bảng 2. Các thao tác mặc định được đề xuất trong trò chơi cho phím trên D-pad mã và giá trị trục mũ.
Hành động trong trò chơi | Mã phím trên D-pad | Mã trục mũ |
---|---|---|
Di chuyển lên | KEYCODE_DPAD_UP |
AXIS_HAT_Y (cho các giá trị từ 0 đến -1) |
Di chuyển xuống | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (cho các giá trị từ 0 đến 1.0) |
Di chuyển sang trái | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (cho các giá trị từ 0 đến -1) |
Di chuyển sang phải | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (cho các giá trị từ 0 đến 1.0) |
Đoạn mã sau đây cho thấy một lớp trợ giúp cho phép bạn kiểm tra mũ các giá trị mã trục và mã phím từ một sự kiện đầu vào để xác định hướng D-pad.
Kotlin
class Dpad { private var directionPressed = -1 // initialized to -1 fun getDirectionPressed(event: InputEvent): Int { if (!isDpadDevice(event)) { return -1 } // If the input event is a MotionEvent, check its hat axis values. (event as? MotionEvent)?.apply { // Use the hat axis value to find the D-pad direction val xaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_X) val yaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_Y) directionPressed = when { // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad // LEFT and RIGHT direction accordingly. xaxis.compareTo(-1.0f) == 0 -> Dpad.LEFT xaxis.compareTo(1.0f) == 0 -> Dpad.RIGHT // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad // UP and DOWN direction accordingly. yaxis.compareTo(-1.0f) == 0 -> Dpad.UP yaxis.compareTo(1.0f) == 0 -> Dpad.DOWN else -> directionPressed } } // If the input event is a KeyEvent, check its key code. (event as? KeyEvent)?.apply { // Use the key code to find the D-pad direction. directionPressed = when(event.keyCode) { KeyEvent.KEYCODE_DPAD_LEFT -> Dpad.LEFT KeyEvent.KEYCODE_DPAD_RIGHT -> Dpad.RIGHT KeyEvent.KEYCODE_DPAD_UP -> Dpad.UP KeyEvent.KEYCODE_DPAD_DOWN -> Dpad.DOWN KeyEvent.KEYCODE_DPAD_CENTER -> Dpad.CENTER else -> directionPressed } } return directionPressed } companion object { internal const val UP = 0 internal const val LEFT = 1 internal const val RIGHT = 2 internal const val DOWN = 3 internal const val CENTER = 4 fun isDpadDevice(event: InputEvent): Boolean = // Check that input comes from a device with directional pads. event.source and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD } }
Java
public class Dpad { final static int UP = 0; final static int LEFT = 1; final static int RIGHT = 2; final static int DOWN = 3; final static int CENTER = 4; int directionPressed = -1; // initialized to -1 public int getDirectionPressed(InputEvent event) { if (!isDpadDevice(event)) { return -1; } // If the input event is a MotionEvent, check its hat axis values. if (event instanceof MotionEvent) { // Use the hat axis value to find the D-pad direction MotionEvent motionEvent = (MotionEvent) event; float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X); float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y); // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad // LEFT and RIGHT direction accordingly. if (Float.compare(xaxis, -1.0f) == 0) { directionPressed = Dpad.LEFT; } else if (Float.compare(xaxis, 1.0f) == 0) { directionPressed = Dpad.RIGHT; } // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad // UP and DOWN direction accordingly. else if (Float.compare(yaxis, -1.0f) == 0) { directionPressed = Dpad.UP; } else if (Float.compare(yaxis, 1.0f) == 0) { directionPressed = Dpad.DOWN; } } // If the input event is a KeyEvent, check its key code. else if (event instanceof KeyEvent) { // Use the key code to find the D-pad direction. KeyEvent keyEvent = (KeyEvent) event; if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { directionPressed = Dpad.LEFT; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) { directionPressed = Dpad.RIGHT; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) { directionPressed = Dpad.UP; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) { directionPressed = Dpad.DOWN; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) { directionPressed = Dpad.CENTER; } } return directionPressed; } public static boolean isDpadDevice(InputEvent event) { // Check that input comes from a device with directional pads. if ((event.getSource() & InputDevice.SOURCE_DPAD) != InputDevice.SOURCE_DPAD) { return true; } else { return false; } } }
Bạn có thể sử dụng lớp trợ giúp này trong trò chơi ở bất cứ nơi nào bạn muốn xử lý
Phương thức nhập bằng D-pad (ví dụ: trong
onGenericMotionEvent()
hoặc
onKeyDown()
lệnh gọi lại).
Ví dụ:
Kotlin
private val dpad = Dpad() ... override fun onGenericMotionEvent(event: MotionEvent): Boolean { if (Dpad.isDpadDevice(event)) { when (dpad.getDirectionPressed(event)) { Dpad.LEFT -> { // Do something for LEFT direction press ... return true } Dpad.RIGHT -> { // Do something for RIGHT direction press ... return true } Dpad.UP -> { // Do something for UP direction press ... return true } ... } } // Check if this event is from a joystick movement and process accordingly. ... }
Java
Dpad dpad = new Dpad(); ... @Override public boolean onGenericMotionEvent(MotionEvent event) { // Check if this event if from a D-pad and process accordingly. if (Dpad.isDpadDevice(event)) { int press = dpad.getDirectionPressed(event); switch (press) { case LEFT: // Do something for LEFT direction press ... return true; case RIGHT: // Do something for RIGHT direction press ... return true; case UP: // Do something for UP direction press ... return true; ... } } // Check if this event is from a joystick movement and process accordingly. ... }
Xử lý chuyển động của cần điều khiển
Khi người chơi di chuyển cần điều khiển trên tay điều khiển trò chơi, Android sẽ báo cáo
MotionEvent
chứa phần tử
Mã hành động ACTION_MOVE
và mã hành động được cập nhật
vị trí các trục của cần điều khiển. Trò chơi của bạn có thể sử dụng dữ liệu do
MotionEvent
để xác định xem cần điều khiển có di chuyển nó hay không
quan tâm đã xảy ra.
Lưu ý rằng các sự kiện chuyển động của cần điều khiển có thể nhóm nhiều mẫu chuyển động lại với nhau
trong một đối tượng duy nhất. Đối tượng MotionEvent
chứa
vị trí hiện tại của từng trục cần điều khiển cũng như nhiều trục
vị trí cho mỗi trục. Khi báo cáo sự kiện chuyển động bằng mã thao tác ACTION_MOVE
(chẳng hạn như di chuyển cần điều khiển), Android sẽ gộp nhóm
giá trị trục cho hiệu quả. Giá trị lịch sử cho một trục bao gồm các biến
một tập hợp các giá trị riêng biệt cũ hơn giá trị trục hiện tại và gần đây hơn
các giá trị được báo cáo trong mọi sự kiện chuyển động trước đó. Xem
Tham khảo MotionEvent
để biết thông tin chi tiết.
Bạn có thể sử dụng thông tin trong quá khứ để kết xuất trò chơi một cách chính xác hơn
chuyển động của đối tượng dựa trên đầu vào của cần điều khiển. Người nhận
truy xuất giá trị hiện tại và giá trị trước đây, hãy gọi
getAxisValue()
hoặc getHistoricalAxisValue()
. Bạn cũng có thể tìm thấy số lượng
điểm trong sự kiện cần điều khiển bằng cách gọi
getHistorySize()
.
Đoạn mã sau đây cho biết cách bạn có thể ghi đè
Lệnh gọi lại onGenericMotionEvent()
để xử lý thao tác đầu vào của cần điều khiển. Trước tiên, bạn nên
xử lý các giá trị trước đây cho một trục, sau đó xử lý vị trí hiện tại của trục đó.
Kotlin
class GameView(...) : View(...) { override fun onGenericMotionEvent(event: MotionEvent): Boolean { // Check that the event came from a game controller return if (event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK && event.action == MotionEvent.ACTION_MOVE) { // Process the movements starting from the // earliest historical position in the batch (0 until event.historySize).forEach { i -> // Process the event at historical position i processJoystickInput(event, i) } // Process the current movement sample in the batch (position -1) processJoystickInput(event, -1) true } else { super.onGenericMotionEvent(event) } } }
Java
public class GameView extends View { @Override public boolean onGenericMotionEvent(MotionEvent event) { // Check that the event came from a game controller if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { // Process all historical movement samples in the batch final int historySize = event.getHistorySize(); // Process the movements starting from the // earliest historical position in the batch for (int i = 0; i < historySize; i++) { // Process the event at historical position i processJoystickInput(event, i); } // Process the current movement sample in the batch (position -1) processJoystickInput(event, -1); return true; } return super.onGenericMotionEvent(event); } }
Trước khi sử dụng phương thức nhập bằng cần điều khiển, bạn cần xác định xem cần điều khiển có đang căn giữa, sau đó tính chuyển động trục của nó sao cho phù hợp. Cần điều khiển thông thường có vùng phẳng, tức là một phạm vi các giá trị gần toạ độ (0,0) tại đó trục được coi là trọng tâm. Nếu giá trị trục được báo cáo bởi Android nằm trong khu vực phẳng, bạn nên coi bộ điều khiển là ở nghỉ (tức là không chuyển động dọc theo cả hai trục).
Đoạn mã dưới đây cho thấy một phương thức trợ giúp để tính toán chuyển động dọc
từng trục. Bạn gọi trình trợ giúp này trong phương thức processJoystickInput()
được mô tả kỹ hơn bên dưới.
Kotlin
private fun getCenteredAxis( event: MotionEvent, device: InputDevice, axis: Int, historyPos: Int ): Float { val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source) // A joystick at rest does not always report an absolute position of // (0,0). Use the getFlat() method to determine the range of values // bounding the joystick axis center. range?.apply { val value: Float = if (historyPos < 0) { event.getAxisValue(axis) } else { event.getHistoricalAxisValue(axis, historyPos) } // Ignore axis values that are within the 'flat' region of the // joystick axis center. if (Math.abs(value) > flat) { return value } } return 0f }
Java
private static float getCenteredAxis(MotionEvent event, InputDevice device, int axis, int historyPos) { final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource()); // A joystick at rest does not always report an absolute position of // (0,0). Use the getFlat() method to determine the range of values // bounding the joystick axis center. if (range != null) { final float flat = range.getFlat(); final float value = historyPos < 0 ? event.getAxisValue(axis): event.getHistoricalAxisValue(axis, historyPos); // Ignore axis values that are within the 'flat' region of the // joystick axis center. if (Math.abs(value) > flat) { return value; } } return 0; }
Kết hợp kiến thức đã học, sau đây là cách xử lý các chuyển động của cần điều khiển trò chơi của bạn:
Kotlin
private fun processJoystickInput(event: MotionEvent, historyPos: Int) { val inputDevice = event.device // Calculate the horizontal distance to move by // using the input value from one of these physical controls: // the left control stick, hat axis, or the right control stick. var x: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos) if (x == 0f) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos) } if (x == 0f) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos) } // Calculate the vertical distance to move by // using the input value from one of these physical controls: // the left control stick, hat switch, or the right control stick. var y: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos) if (y == 0f) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos) } if (y == 0f) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos) } // Update the ship object based on the new x and y values }
Java
private void processJoystickInput(MotionEvent event, int historyPos) { InputDevice inputDevice = event.getDevice(); // Calculate the horizontal distance to move by // using the input value from one of these physical controls: // the left control stick, hat axis, or the right control stick. float x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos); if (x == 0) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos); } if (x == 0) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos); } // Calculate the vertical distance to move by // using the input value from one of these physical controls: // the left control stick, hat switch, or the right control stick. float y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos); if (y == 0) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos); } if (y == 0) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos); } // Update the ship object based on the new x and y values }
Để hỗ trợ tay điều khiển trò chơi tinh vi hơn ngoài một cần điều khiển, hãy làm theo các phương pháp hay nhất sau đây:
- Xử lý các thanh điều khiển kép. Nhiều tay điều khiển trò chơi có
cả cần điều khiển bên trái và bên phải. Đối với thanh bên trái, Android
báo cáo chuyển động ngang dưới dạng sự kiện
AXIS_X
và chuyển động theo chiều dọc dưới dạng sự kiệnAXIS_Y
. Đối với thanh bên phải, Android báo cáo chuyển động ngang làAXIS_Z
sự kiện và chuyển động theo chiều dọc dưới dạngAXIS_RZ
sự kiện. Hãy nhớ xử lý cả hai thẻ điều khiển trong mã của bạn. - Xử lý thao tác nhấn nút kích hoạt vai (nhưng cung cấp phương thức nhập thay thế
). Một số bộ điều khiển có vai trái và vai phải
điều kiện kích hoạt. Nếu có các điều kiện kích hoạt này, Android sẽ báo cáo một lượt nhấn điều kiện kích hoạt bên trái
dưới dạng sự kiện
AXIS_LTRIGGER
và nhấn nút kích hoạt bên phải Sự kiệnAXIS_RTRIGGER
. Trên Android 4.3 (API cấp 18), bộ điều khiển tạo raAXIS_LTRIGGER
cũng báo cáo một giá trị giống hệt cho trụcAXIS_BRAKE
. Chiến lược phát hành đĩa đơn điều tương tự cũng đúng vớiAXIS_RTRIGGER
vàAXIS_GAS
Android báo cáo tất cả điều kiện kích hoạt analog có giá trị chuẩn hóa từ 0,0 (nhả) đến 1,0 (nhấn hoàn toàn). Không phải tất cả tay điều khiển đều có trình kích hoạt, vì vậy, hãy cân nhắc cho phép người chơi thực hiện các thao tác đó hành động trong trò chơi bằng các nút khác.