ในระดับระบบ Android จะรายงานการป้อนโค้ดเหตุการณ์จากตัวควบคุมเกม เป็นโค้ดคีย์ Android และค่าแกน คุณรับรหัสเหล่านี้ในเกมได้ มูลค่า และแปลงเป็นการดำเนินการที่เจาะจงในเกม
เมื่อผู้เล่นเชื่อมต่อตัวเกมหรือจับคู่อุปกรณ์ควบคุมเกมแบบไร้สาย
อุปกรณ์ที่ใช้ Android ของตน ระบบจะตรวจพบตัวควบคุมโดยอัตโนมัติ
เป็นอุปกรณ์อินพุตและเริ่มรายงานเหตุการณ์การป้อนข้อมูลของอุปกรณ์นั้น เกมของคุณสามารถรับได้
เหตุการณ์อินพุตเหล่านี้โดยใช้เมธอด Callback ต่อไปนี้ใน
Activity
หรือ View
ที่โฟกัส (คุณควร
ใช้ Callback สำหรับ Activity
หรือ
View
แต่ไม่ใช่ทั้ง 2 อย่าง):
- จาก
Activity
dispatchGenericMotionEvent(android.view. MotionEvent)
เรียกใช้เพื่อประมวลผลเหตุการณ์การเคลื่อนไหวทั่วไป เช่น การเคลื่อนที่ของจอยสติ๊ก
dispatchKeyEvent(android.view.KeyEvent)
เรียกใช้เพื่อประมวลผลเหตุการณ์สำคัญ เช่น การแถลงข่าวหรือข่าวประชาสัมพันธ์ ปุ่มเกมแพดหรือ D-pad
- จาก
View
onGenericMotionEvent(android.view.MotionEvent)
เรียกใช้เพื่อประมวลผลเหตุการณ์การเคลื่อนไหวทั่วไป เช่น การเคลื่อนที่ของจอยสติ๊ก
onKeyDown(int, android.view.KeyEvent)
เรียกใช้ให้ประมวลผลการกดปุ่มจริง เช่น เกมแพด หรือ ปุ่ม D-pad
onKeyUp(int, android.view.KeyEvent)
เรียกใช้เพื่อประมวลผลการเปิดตัวคีย์จริง เช่น เกมแพด หรือ ปุ่ม D-pad
วิธีที่แนะนำคือบันทึกเหตุการณ์จาก
ออบเจ็กต์ View
เฉพาะที่ผู้ใช้โต้ตอบกับ
ตรวจสอบออบเจ็กต์ต่อไปนี้ที่ได้จาก Callback เพื่อรับข้อมูล
เกี่ยวกับประเภทของเหตุการณ์อินพุตที่ได้รับ
KeyEvent
- วัตถุที่อธิบายทิศทาง
เหตุการณ์เกี่ยวกับแพด (D-pad) และปุ่มเกมแพด เหตุการณ์สำคัญมาพร้อมกับ
โค้ดหลักที่ระบุถึงปุ่มเฉพาะที่เรียกใช้ เช่น
DPAD_DOWN
หรือBUTTON_A
คุณสามารถรับ โดยโทรหาgetKeyCode()
หรือจากกุญแจ Callback ของเหตุการณ์ เช่นonKeyDown()
MotionEvent
- วัตถุที่อธิบายอินพุตจากจอยสติ๊กและทริกเกอร์ตามไหล่
การเคลื่อนไหว เหตุการณ์การเคลื่อนไหวมาพร้อมกับรหัสการดำเนินการและชุดของ
ค่าแกน รหัสการกระทำจะระบุการเปลี่ยนแปลงสถานะที่เกิดขึ้น
เช่น จอยสติ๊กที่กำลังขยับ ค่าแกนจะอธิบายตำแหน่งและ
คุณสมบัติการเคลื่อนไหวสำหรับการควบคุมการเคลื่อนไหวบางอย่าง เช่น
AXIS_X
หรือAXIS_RTRIGGER
คุณสามารถรับรหัสการดำเนินการ โดยเรียกgetAction()
และค่าแกนตาม กำลังโทรหาgetAxisValue()
บทเรียนนี้จะเน้นถึงวิธีการจัดการกับการป้อนข้อมูลจากประเภทที่พบบ่อยที่สุด
การควบคุมทางกายภาพ (ปุ่มเกมแพด แผ่นควบคุมทิศทาง และ
จอยสติ๊ก) ในหน้าจอเกมโดยใช้สิ่งที่กล่าวไว้ข้างต้น
วิธีการและการประมวลผลของ Callback View
รายการ
KeyEvent
และ MotionEvent
ออบเจ็กต์
ตรวจสอบว่าได้เชื่อมต่อเกมคอนโทรลเลอร์แล้ว
เมื่อรายงานเหตุการณ์อินพุต Android จะไม่แยก
ระหว่างเหตุการณ์ที่มาจากอุปกรณ์ที่ไม่ใช่ตัวควบคุมเกมกับเหตุการณ์ที่เกิดขึ้น
จากเกมคอนโทรลเลอร์ ตัวอย่างเช่น การทำงานบนหน้าจอสัมผัสจะสร้าง
AXIS_X
เหตุการณ์ที่แสดง X
พิกัดของพื้นผิวสัมผัส แต่จอยสติ๊กจะสร้าง
AXIS_X
เหตุการณ์ที่แสดงตำแหน่ง X ของจอยสติ๊ก ถ้า
เกมของคุณจะให้ความสำคัญกับการจัดการ
อินพุตตัวควบคุมเกม ก่อนอื่นคุณควรตรวจสอบ
ว่าเหตุการณ์อินพุตมาจากประเภทแหล่งที่มาที่เกี่ยวข้อง
ในการยืนยันว่าอุปกรณ์อินพุตที่เชื่อมต่อเป็นตัวควบคุมเกม โปรดโทร
getSources()
เพื่อรับฟิลด์บิตรวมของ
ประเภทแหล่งที่มาของอินพุตที่อุปกรณ์นั้นรองรับ จากนั้นคุณสามารถทดสอบเพื่อดูว่า
มีการตั้งค่าฟิลด์ต่อไปนี้:
- ประเภทแหล่งที่มา
SOURCE_GAMEPAD
บ่งชี้ อุปกรณ์อินพุตมีปุ่มเกมแพด (เช่นBUTTON_A
) โปรดทราบว่าแหล่งข้อมูลนี้ ประเภทไม่ได้ระบุไว้ชัดเจนว่าตัวควบคุมเกมมีปุ่ม D-pad หรือไม่ แม้ว่าเกมแพดส่วนใหญ่ จะมีการควบคุมทิศทาง - ประเภทแหล่งที่มา
SOURCE_DPAD
บ่งชี้ว่า อุปกรณ์อินพุตมีปุ่ม D-pad (ตัวอย่างเช่นDPAD_UP
) - ประเภทแหล่งที่มา
SOURCE_JOYSTICK
บ่งบอกว่าอุปกรณ์อินพุตมีแท่งควบคุมแบบแอนะล็อก (ตัวอย่างเช่น จอยสติ๊กที่บันทึกการเคลื่อนที่ตลอดAXIS_X
และAXIS_Y
)
ข้อมูลโค้ดต่อไปนี้แสดงวิธีตัวช่วยที่ให้คุณตรวจสอบว่า อุปกรณ์อินพุตที่เชื่อมต่อคือตัวควบคุมเกม ถ้าใช่ เมธอดจะเรียกคืน รหัสอุปกรณ์ของตัวควบคุมเกม จากนั้นคุณจะสามารถเชื่อมโยงอุปกรณ์แต่ละเครื่อง ใส่รหัสด้วยผู้เล่นในเกม และประมวลผลการดำเนินการในเกมสำหรับแต่ละเกมที่เชื่อมต่อ โปรแกรมเล่นวิดีโอแยกกัน หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการรองรับตัวควบคุมเกมหลายเครื่อง ที่เชื่อมต่อบนอุปกรณ์ Android เครื่องเดียวกันพร้อมๆ กัน โปรดดู รองรับตัวควบคุมเกมได้หลายรายการ
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; }
นอกจากนี้ คุณอาจต้องตรวจสอบความสามารถในการป้อนข้อมูลแต่ละรายการ รองรับโดยตัวควบคุมเกมที่เชื่อมต่อ ซึ่งอาจเป็นประโยชน์ เช่น หาก คุณต้องการให้เกมใช้เฉพาะอินพุตจากชุดการควบคุมทางกายภาพ เข้าใจ
หากต้องการตรวจสอบว่าเครื่องมือที่เชื่อมต่อรองรับรหัสคีย์หรือรหัสแกนที่เฉพาะเจาะจงหรือไม่ เกมคอนโทรลเลอร์ ใช้เทคนิคเหล่านี้
- ใน Android 4.4 (API ระดับ 19) ขึ้นไป คุณระบุได้ว่ารหัสคีย์คือ
รองรับบนอุปกรณ์ควบคุมเกมที่เชื่อมต่ออยู่โดยการเรียกใช้
hasKeys(int...)
- ใน Android 3.1 (API ระดับ 12) ขึ้นไป คุณสามารถค้นหาแกนทั้งหมดที่มีอยู่ได้
รองรับอุปกรณ์ควบคุมเกมที่เชื่อมต่ออยู่โดยการเรียกใช้ครั้งแรก
getMotionRanges()
จากนั้น ในแต่ละ ส่งคืนออบเจ็กต์InputDevice.MotionRange
รายการ เรียกgetAxis()
เพื่อรับรหัสแกน
ประมวลผลการกดปุ่มเกมแพด
รูปที่ 1 แสดงวิธีที่ Android แมปโค้ดคีย์และค่าแกนกับฟิวเจอร์ส ในตัวควบคุมเกมส่วนใหญ่
![](https://developer.android.com/static/images/training/game-controller-profiles.png?hl=th)
รูปที่ 1 โปรไฟล์สำหรับตัวควบคุมเกมทั่วไป
ไฮไลต์ในรูปอ้างอิงถึงข้อมูลต่อไปนี้
โค้ดคีย์ทั่วไปที่สร้างขึ้นจากการกดปุ่มเกมแพดมีดังนี้
BUTTON_A
,
BUTTON_B
,
BUTTON_SELECT
,
และ BUTTON_START
บางเกม
ตัวควบคุมยังจะทริกเกอร์โค้ดคีย์ DPAD_CENTER
ด้วยเมื่อกดตรงกลางของข้ามแถบ D-pad บัญชี
เกมจะตรวจสอบรหัสคีย์ได้โดยการโทรหา getKeyCode()
หรือจาก Callback ของเหตุการณ์สําคัญ เช่น
onKeyDown()
,
และถ้าเหตุการณ์นั้นแสดงถึงเหตุการณ์ที่เกี่ยวข้องกับเกมของคุณ ให้ประมวลผลเป็น
กับแอ็กชันในเกม ตารางที่ 1 แสดงรายการการดำเนินการที่แนะนำสำหรับเกมที่พบบ่อยที่สุด
ปุ่มเกมแพด
ตาราง 1 การดำเนินการที่แนะนำสำหรับเกมแพด
แอ็กชันในเกม | รหัสคีย์ของปุ่ม |
---|---|
เริ่มเกมในเมนูหลัก หรือหยุดเล่นชั่วคราว/ยกเลิกการหยุดชั่วคราวระหว่างเกม | BUTTON_START * |
แสดงเมนู | BUTTON_SELECT *
และ KEYCODE_MENU * |
เช่นเดียวกับลักษณะการไปยังส่วนต่างๆ แบบกลับของ Android ที่อธิบายไว้ใน การออกแบบการนำทาง | KEYCODE_BACK |
กลับไปยังรายการก่อนหน้าในเมนู | BUTTON_B |
ยืนยันการเลือก หรือดำเนินการกับเกมหลัก | BUTTON_A และ
วันที่ DPAD_CENTER |
* เกมของคุณไม่ควรพึ่งพาการแสดงข้อมูล "เริ่ม", "เลือก" หรือ "เมนู"
เคล็ดลับ: ลองใส่หน้าจอการกำหนดค่า ในเกมของคุณ เพื่ออนุญาตให้ผู้ใช้สามารถปรับเปลี่ยนการแมปเกมคอนโทรลเลอร์ของตนเอง การดำเนินการในเกม
ข้อมูลโค้ดต่อไปนี้แสดงวิธีลบล้าง
onKeyDown()
ถึง
เชื่อมโยง BUTTON_A
กับ
การกดปุ่ม DPAD_CENTER
กับแอ็กชันในเกม
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; } }
หมายเหตุ: ใน Android 4.2 (API
ระดับ 17) และต่ำกว่า ระบบจะพิจารณา
BUTTON_A
ในฐานะ Android
ปุ่ม ย้อนกลับ โดยค่าเริ่มต้น ถ้าแอปของคุณสนับสนุน Android เหล่านี้
เวอร์ชันต่างๆ อย่าลืมพิจารณา
BUTTON_A
เป็นเกมหลัก
การดำเนินการ เพื่อดู Android SDK ปัจจุบัน
เวอร์ชันในอุปกรณ์ โปรดไปที่
Build.VERSION.SDK_INT
ประมวลผลการป้อนข้อมูลแป้นทิศทาง
ปุ่มบังคับทิศทาง 4 ทิศทาง (D-pad) เป็นการควบคุมทางกายภาพที่ใช้กันโดยทั่วไปในหลายๆ เกม
Android รายงานการกด D-pad ขึ้นและลงเป็น
AXIS_HAT_Y
เหตุการณ์ที่มีช่วง
จาก -1.0 (ขึ้น) ถึง 1.0 (ลง) และกด D-pad ซ้ายหรือขวาเป็น
AXIS_HAT_X
เหตุการณ์ที่มีช่วงตั้งแต่ -1.0
(ซ้าย) เป็น 1.0 (ขวา)
ตัวควบคุมบางรายจะรายงานการกด D-pad โดยใช้รหัสคีย์แทน หากเกมของคุณ ให้ความสำคัญกับการกด D-pad คุณควรดูเหตุการณ์ของแกนหมวกและ D-pad รหัสคีย์เป็นเหตุการณ์อินพุตเดียวกับที่แนะนำในตาราง 2
ตาราง 2 การดำเนินการที่แนะนำสำหรับเกมเริ่มต้นสำหรับปุ่ม D-pad รหัสและค่าแกนหมวก
แอ็กชันในเกม | รหัสปุ่ม D-pad | รหัสแกนหมวก |
---|---|---|
ย้ายขึ้น | KEYCODE_DPAD_UP |
AXIS_HAT_Y (สำหรับค่า 0 ถึง -1.0) |
ย้ายลง | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (สำหรับค่า 0 ถึง 1.0) |
ย้ายไปทางซ้าย | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (สำหรับค่า 0 ถึง -1.0) |
ย้ายไปทางขวา | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (สำหรับค่า 0 ถึง 1.0) |
ข้อมูลโค้ดต่อไปนี้แสดงคลาสตัวช่วยที่ให้คุณตรวจหมวก ค่าแกนและคีย์โค้ดจากเหตุการณ์อินพุตเพื่อกำหนดทิศทาง 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; } } }
คุณจะใช้คลาสผู้ช่วยนี้ในเกมได้ทุกที่ที่ต้องการประมวลผล
อินพุต D-pad (ตัวอย่างเช่น ใน
onGenericMotionEvent()
หรือ
วันที่ onKeyDown()
Callback)
เช่น
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. ... }
ประมวลผลการเคลื่อนที่ของจอยสติ๊ก
เมื่อผู้เล่นเคลื่อนจอยสติ๊กบนตัวควบคุมเกม Android จะรายงาน
MotionEvent
ที่มีฟังก์ชัน
โค้ดดำเนินการ ACTION_MOVE
และอัปเดตแล้ว
ที่ตำแหน่งแกนของจอยสติ๊ก เกมของคุณสามารถใช้ข้อมูลที่ให้ไว้โดย
MotionEvent
เพื่อดูว่าจอยสติ๊กเคลื่อนที่หรือไม่
สิ่งที่เกิดขึ้น
โปรดทราบว่าเหตุการณ์การเคลื่อนไหวของจอยสติ๊กอาจรวมกลุ่มตัวอย่างการเคลื่อนไหวหลายรายการเข้าด้วยกัน
ภายในออบเจ็กต์เดียว ออบเจ็กต์ MotionEvent
ประกอบด้วย
ตำแหน่งปัจจุบันของแกนจอยสติ๊กแต่ละแกน รวมถึงประวัติหลายครั้ง
สำหรับแต่ละแกน เมื่อรายงานเหตุการณ์การเคลื่อนไหวที่มีรหัสการกระทำ ACTION_MOVE
(เช่น การเคลื่อนที่ของจอยสติ๊ก) Android จะจัดกลุ่ม
สำหรับประสิทธิภาพ ค่าประวัติสำหรับแกนประกอบด้วย
ชุดของค่าที่ไม่ซ้ำกันซึ่งเก่ากว่าค่าแกนปัจจุบัน และใหม่กว่า
มูลค่าที่รายงานในเหตุการณ์การเคลื่อนไหวก่อนหน้า โปรดดู
ข้อมูลอ้างอิงของ MotionEvent
สำหรับรายละเอียด
คุณสามารถใช้ข้อมูลประวัติเพื่อให้แสดงผลเกมได้แม่นยำยิ่งขึ้น
การเคลื่อนที่ของวัตถุตามอินพุตจอยสติ๊ก ถึง
ดึงค่าปัจจุบันและที่ผ่านมา
getAxisValue()
หรือ getHistoricalAxisValue()
คุณสามารถดูจำนวนพร็อพเพอร์ตี้
ในเหตุการณ์จอยสติ๊กด้วยการเรียก
getHistorySize()
ข้อมูลโค้ดต่อไปนี้แสดงวิธีลบล้าง
onGenericMotionEvent()
Callback เพื่อประมวลผลอินพุตจอยสติ๊ก ก่อนอื่น
ประมวลผลค่าในอดีตสำหรับแกน จากนั้นประมวลผลตำแหน่งปัจจุบันของแกน
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); } }
ก่อนใช้อินพุตจอยสติ๊ก คุณต้องตรวจสอบว่าจอยสติ๊ก ให้อยู่กึ่งกลาง แล้วคำนวณการเคลื่อนที่ตามแกนของแกนนั้นๆ โดยทั่วไปจอยสติ๊ก มีพื้นที่ราบ ซึ่งก็คือช่วงของค่าที่อยู่ใกล้กับพิกัด (0,0) ที่ถือว่าแกนอยู่กึ่งกลาง หากค่าแกนที่รายงานโดย Android อยู่ในพื้นที่ราบ คุณควรถือว่าตัวควบคุมอยู่ที่ ไม่เคลื่อนไหว (กล่าวคือ ไม่เคลื่อนไหวไปตามแกนทั้ง 2 แกน)
ข้อมูลโค้ดด้านล่างแสดงวิธีตัวช่วยที่คํานวณการเคลื่อนไหว
แต่ละแกน คุณเรียกใช้ตัวช่วยนี้ในเมธอด processJoystickInput()
ดังที่อธิบายไว้ด้านล่าง
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; }
นำทุกอย่างมารวมเข้าด้วยกัน คุณจะใช้การเคลื่อนที่ของจอยสติ๊กได้โดยทำดังนี้ เกมของคุณ
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 }
เพื่อรองรับเกมคอนโทรลเลอร์ที่ซับซ้อนยิ่งขึ้น คุณลักษณะที่นอกเหนือจากจอยสติ๊กเดียว ให้ทำตามแนวทางปฏิบัติที่ดีที่สุดต่อไปนี้:
- ใช้ด้ามจับไม้คอนโทรลเลอร์แบบคู่ เกมคอนโทรลเลอร์จำนวนมาก
ทั้งจอยสติ๊กซ้ายและขวา สำหรับคันโยกซ้าย Android
รายงานการเคลื่อนไหวในแนวนอนเป็น
AXIS_X
เหตุการณ์ และการเคลื่อนไหวแนวตั้งเป็นAXIS_Y
เหตุการณ์ สำหรับแท่งด้านขวา Android จะรายงานการเคลื่อนที่ในแนวนอนเป็นAXIS_Z
เหตุการณ์และการเคลื่อนไหวแนวตั้งเป็นAXIS_RZ
กิจกรรม อย่าลืมจัดการ ตัวควบคุมทั้ง 2 ตัวจะติดอยู่ในโค้ด - จัดการการกดทริกเกอร์ไหล่ (แต่มีอินพุตสำรอง)
วิธีการ) ตัวควบคุมบางอย่างมีไหล่ซ้ายและขวา
ทริกเกอร์ หากมีตัวทริกเกอร์เหล่านี้ Android จะรายงานการกดทริกเกอร์ด้านซ้าย
เป็นเหตุการณ์
AXIS_LTRIGGER
และ การกดทริกเกอร์ด้านขวาเป็นAXIS_RTRIGGER
เหตุการณ์ บน Android 4.3 (API ระดับ 18) ซึ่งเป็นตัวควบคุมที่สร้างAXIS_LTRIGGER
ยังรายงาน ค่าที่เหมือนกันสำหรับแกนAXIS_BRAKE
สำหรับAXIS_RTRIGGER
และAXIS_GAS
Android รายงานทริกเกอร์แบบแอนะล็อกทั้งหมด การกดด้วยค่ามาตรฐานจาก 0.0 (ปล่อยแล้ว) เป็น 1.0 (กดทั้งหมด) ไม่ใช่ ตัวควบคุมทั้งหมดมีทริกเกอร์ คุณจึงควรอนุญาตให้ผู้เล่นใช้ทริกเกอร์ การทำงานในเกมด้วยปุ่มอื่นๆ