Bạn có trách nhiệm hỗ trợ tay điều khiển trò chơi trong trò chơi của mình để đảm bảo trò chơi của bạn phản hồi tay điều khiển một cách nhất quán trên các thiết bị chạy trên các phiên bản Android khác nhau. Điều này cho phép trò chơi của bạn tiếp cận và người chơi có thể tận hưởng trải nghiệm chơi liền mạch với bộ điều khiển của họ ngay cả khi họ chuyển đổi hoặc nâng cấp thiết bị Android.
Bài học này trình bày cách sử dụng API có trong Android 4.1 trở lên theo cách tương thích ngược, cho phép trò chơi của bạn hỗ trợ trên các thiết bị chạy Android 3.1 trở lên:
- Trò chơi có thể phát hiện xem một tay điều khiển trò chơi mới được thêm, thay đổi hoặc xoá hay chưa.
- Trò chơi có thể truy vấn các chức năng của tay điều khiển trò chơi.
- Trò chơi có thể nhận dạng các sự kiện chuyển động đến qua tay điều khiển trò chơi.
Các ví dụ trong bài học này dựa trên cách triển khai tệp tham chiếu
được cung cấp bởi ControllerSample.zip
mẫu có sẵn để tải xuống
ở trên. Mẫu này trình bày cách triển khai InputManagerCompat
để hỗ trợ các phiên bản Android khác nhau. Để biên dịch mẫu, bạn
phải sử dụng Android 4.1 (API cấp 16) trở lên. Sau khi được biên dịch, ứng dụng mẫu
chạy trên mọi thiết bị chạy Android 3.1 (API cấp 12) trở lên dưới dạng bản dựng
.
Chuẩn bị các API trừu tượng để hỗ trợ tay điều khiển trò chơi
Giả sử bạn muốn có thể xác định xem kết nối của tay điều khiển trò chơi trạng thái đã thay đổi trên các thiết bị chạy trên Android 3.1 (API cấp 12). Tuy nhiên, API chỉ có trong Android 4.1 (API cấp 16) trở lên, vì vậy bạn cần cung cấp một phương thức triển khai hỗ trợ Android 4.1 trở lên trong khi cung cấp cơ chế dự phòng hỗ trợ từ Android 3.1 đến Android 4.0.
Để giúp bạn xác định tính năng nào yêu cầu cơ chế dự phòng như vậy cho các phiên bản cũ hơn, bảng 1 liệt kê những điểm khác biệt về khả năng hỗ trợ tay điều khiển trò chơi giữa Android 3.1 (API cấp 12) đến 4.1 (cấp độ API) 16).
Thông tin về tay điều khiển | API Trình điều khiển | API cấp 12 | API cấp 16 |
---|---|---|---|
Nhận dạng thiết bị | getInputDeviceIds() |
• | |
getInputDevice() |
• | ||
getVibrator() |
• | ||
SOURCE_JOYSTICK |
• | • | |
SOURCE_GAMEPAD |
• | • | |
Trạng thái kết nối mạng | onInputDeviceAdded() |
• | |
onInputDeviceChanged() |
• | ||
onInputDeviceRemoved() |
• | ||
Nhận dạng sự kiện đầu vào | Nhấn D-pad (
KEYCODE_DPAD_UP ,
KEYCODE_DPAD_DOWN ,
KEYCODE_DPAD_LEFT ,
KEYCODE_DPAD_RIGHT ,
KEYCODE_DPAD_CENTER ) |
• | • |
Nhấn nút trên tay điều khiển trò chơi (
BUTTON_A ,
BUTTON_B ,
BUTTON_THUMBL ,
BUTTON_THUMBR ,
BUTTON_SELECT ,
BUTTON_START ,
BUTTON_R1 ,
BUTTON_L1 ,
BUTTON_R2 ,
BUTTON_L2 ) |
• | • | |
Chuyển động của cần điều khiển và công tắc mũ (
AXIS_X ,
AXIS_Y ,
AXIS_Z ,
AXIS_RZ ,
AXIS_HAT_X ,
AXIS_HAT_Y ) |
• | • | |
Nhấn nút kích hoạt analog (
AXIS_LTRIGGER ,
AXIS_RTRIGGER ) |
• | • |
Bạn có thể sử dụng mô hình trừu tượng để xây dựng tính năng hỗ trợ tay điều khiển trò chơi có nhận biết phiên bản hoạt động trên nhiều nền tảng. Phương pháp này bao gồm các bước sau:
- Xác định giao diện Java trung gian tóm tắt việc triển khai các tính năng của tay điều khiển trò chơi mà trò chơi của bạn yêu cầu.
- Tạo hoạt động triển khai proxy cho giao diện sử dụng API trong Android 4.1 trở lên.
- Tạo phương thức triển khai tuỳ chỉnh giao diện sử dụng các API có sẵn giữa Android 3.1 và Android 4.0.
- Tạo logic để chuyển đổi giữa các cách triển khai này trong thời gian chạy, và bắt đầu sử dụng giao diện trong trò chơi của bạn.
Để biết thông tin tổng quan về cách sử dụng mô hình trừu tượng để đảm bảo rằng các ứng dụng có thể hoạt động theo cách tương thích ngược trên các phiên bản Android khác nhau, hãy xem Sáng tạo Giao diện người dùng tương thích ngược.
Thêm giao diện có khả năng tương thích ngược
Để cung cấp khả năng tương thích ngược, sau đó bạn có thể tạo giao diện tuỳ chỉnh thêm các phương pháp triển khai theo phiên bản cụ thể. Một ưu điểm của phương pháp này là cho phép bạn phản chiếu các giao diện công khai trên Android 4.1 (API cấp 16) hỗ trợ tay điều khiển trò chơi.
Kotlin
// The InputManagerCompat interface is a reference example. // The full code is provided in the ControllerSample.zip sample. interface InputManagerCompat { val inputDeviceIds: IntArray fun getInputDevice(id: Int): InputDevice fun registerInputDeviceListener( listener: InputManager.InputDeviceListener, handler: Handler? ) fun unregisterInputDeviceListener(listener:InputManager.InputDeviceListener) fun onGenericMotionEvent(event: MotionEvent) fun onPause() fun onResume() interface InputDeviceListener { fun onInputDeviceAdded(deviceId: Int) fun onInputDeviceChanged(deviceId: Int) fun onInputDeviceRemoved(deviceId: Int) } }
Java
// The InputManagerCompat interface is a reference example. // The full code is provided in the ControllerSample.zip sample. public interface InputManagerCompat { ... public InputDevice getInputDevice(int id); public int[] getInputDeviceIds(); public void registerInputDeviceListener( InputManagerCompat.InputDeviceListener listener, Handler handler); public void unregisterInputDeviceListener( InputManagerCompat.InputDeviceListener listener); public void onGenericMotionEvent(MotionEvent event); public void onPause(); public void onResume(); public interface InputDeviceListener { void onInputDeviceAdded(int deviceId); void onInputDeviceChanged(int deviceId); void onInputDeviceRemoved(int deviceId); } ... }
Giao diện InputManagerCompat
cung cấp các phương thức sau:
getInputDevice()
- Gương
getInputDevice()
. NhậnInputDevice
đối tượng đại diện cho các chức năng của tay điều khiển trò chơi. getInputDeviceIds()
- Gương
getInputDeviceIds()
. Trả về một mảng số nguyên, mỗi mảng trong số là mã nhận dạng cho một thiết bị đầu vào khác. Điều này sẽ hữu ích nếu bạn đang xây dựng một trò chơi hỗ trợ nhiều người chơi và bạn muốn biết có bao nhiêu người chơi tay điều khiển trò chơi đã được kết nối. registerInputDeviceListener()
- Gương
registerInputDeviceListener()
. Cho phép bạn đăng ký nhận thông báo khi có thiết bị được thêm vào, thay đổi hoặc bị xoá. unregisterInputDeviceListener()
- Gương
unregisterInputDeviceListener()
. Huỷ đăng ký trình nghe thiết bị đầu vào. onGenericMotionEvent()
- Gương
onGenericMotionEvent()
. Cho phép trò chơi chặn và xử lý Các đối tượngMotionEvent
và giá trị trục đại diện cho sự kiện chẳng hạn như chuyển động của cần điều khiển và thao tác nhấn nút kích hoạt tương tự. onPause()
- Dừng thăm dò sự kiện tay điều khiển trò chơi khi hoạt động chính bị tạm dừng hoặc khi trò chơi không còn tiêu điểm.
onResume()
- Bắt đầu thăm dò sự kiện tay điều khiển trò chơi khi hoạt động chính được tiếp tục hoặc khi trò chơi bắt đầu và chạy trong nền trước.
InputDeviceListener
- Phản ánh
InputManager.InputDeviceListener
. Cho trò chơi của bạn biết khi nào bạn đã thêm, thay đổi hoặc thêm tay điều khiển trò chơi đã bị xóa.
Tiếp theo, hãy tạo các phương pháp triển khai hiệu quả cho InputManagerCompat
trên các phiên bản nền tảng khác nhau. Nếu trò chơi của bạn đang chạy trên Android 4.1 hoặc
cao hơn và gọi phương thức InputManagerCompat
, phương thức triển khai proxy
gọi phương thức tương đương trong InputManager
.
Tuy nhiên, nếu trò chơi của bạn đang chạy trên Android 3.1 đến Android 4.0, việc triển khai tuỳ chỉnh
xử lý lệnh gọi đến phương thức InputManagerCompat
bằng cách sử dụng
chỉ các API được ra mắt sau Android 3.1. Bất kể
phương thức triển khai theo phiên bản cụ thể được dùng trong thời gian chạy, còn phương thức triển khai thành công
kết quả cuộc gọi trở lại một cách rõ ràng cho trò chơi.
Triển khai giao diện trên Android 4.1 trở lên
InputManagerCompatV16
là một cách triển khai của
Giao diện InputManagerCompat
proxy các lệnh gọi phương thức đến một
InputManager
và InputManager.InputDeviceListener
thực tế. Chiến lược phát hành đĩa đơn
InputManager
được lấy từ hệ thống
Context
Kotlin
// The InputManagerCompatV16 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. public class InputManagerV16( context: Context, private val inputManager: InputManager = context.getSystemService(Context.INPUT_SERVICE) as InputManager, private val listeners: MutableMap<InputManager.InputDeviceListener, V16InputDeviceListener> = mutableMapOf() ) : InputManagerCompat { override val inputDeviceIds: IntArray = inputManager.inputDeviceIds override fun getInputDevice(id: Int): InputDevice = inputManager.getInputDevice(id) override fun registerInputDeviceListener( listener: InputManager.InputDeviceListener, handler: Handler? ) { V16InputDeviceListener(listener).also { v16listener -> inputManager.registerInputDeviceListener(v16listener, handler) listeners += listener to v16listener } } // Do the same for unregistering an input device listener ... override fun onGenericMotionEvent(event: MotionEvent) { // unused in V16 } override fun onPause() { // unused in V16 } override fun onResume() { // unused in V16 } } class V16InputDeviceListener( private val idl: InputManager.InputDeviceListener ) : InputManager.InputDeviceListener { override fun onInputDeviceAdded(deviceId: Int) { idl.onInputDeviceAdded(deviceId) } // Do the same for device change and removal ... }
Java
// The InputManagerCompatV16 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. public class InputManagerV16 implements InputManagerCompat { private final InputManager inputManager; private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> listeners; public InputManagerV16(Context context) { inputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); listeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>(); } @Override public InputDevice getInputDevice(int id) { return inputManager.getInputDevice(id); } @Override public int[] getInputDeviceIds() { return inputManager.getInputDeviceIds(); } static class V16InputDeviceListener implements InputManager.InputDeviceListener { final InputManagerCompat.InputDeviceListener mIDL; public V16InputDeviceListener(InputDeviceListener idl) { mIDL = idl; } @Override public void onInputDeviceAdded(int deviceId) { mIDL.onInputDeviceAdded(deviceId); } // Do the same for device change and removal ... } @Override public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener); inputManager.registerInputDeviceListener(v16Listener, handler); listeners.put(listener, v16Listener); } // Do the same for unregistering an input device listener ... @Override public void onGenericMotionEvent(MotionEvent event) { // unused in V16 } @Override public void onPause() { // unused in V16 } @Override public void onResume() { // unused in V16 } }
Triển khai giao diện trên Android 3.1 đến Android 4.0
Để tạo một phương thức triển khai InputManagerCompat
hỗ trợ Android 3.1 cho đến Android 4.0, bạn có thể sử dụng
các đối tượng sau:
- Một
SparseArray
mã thiết bị để theo dõi tay điều khiển trò chơi được kết nối với thiết bị. Handler
để xử lý các sự kiện trên thiết bị. Khi khởi động ứng dụng hoặc được tiếp tục,Handler
sẽ nhận được thông báo để bắt đầu thăm dò ý kiến để ngắt kết nối tay điều khiển trò chơi.Handler
sẽ bắt đầu một để kiểm tra từng tay điều khiển trò chơi đã kết nối và xem mã thiết bị có phải là bị trả lại. Giá trị trả vềnull
cho biết tay điều khiển trò chơi đã ngắt kết nối.Handler
sẽ ngừng thăm dò ý kiến khi ứng dụng bị tạm dừng.- Một
Map
trong sốInputManagerCompat.InputDeviceListener
. Bạn sẽ dùng trình nghe để cập nhật trạng thái kết nối của các tay điều khiển trò chơi.
Kotlin
// The InputManagerCompatV9 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. class InputManagerV9( val devices: SparseArray<Array<Long>> = SparseArray(), private val listeners: MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf() ) : InputManagerCompat { private val defaultHandler: Handler = PollingMessageHandler(this) … }
Java
// The InputManagerCompatV9 class is a reference implementation. // The full code is provided in the ControllerSample.zip sample. public class InputManagerV9 implements InputManagerCompat { private final SparseArray<long[]> devices; private final Map<InputDeviceListener, Handler> listeners; private final Handler defaultHandler; … public InputManagerV9() { devices = new SparseArray<long[]>(); listeners = new HashMap<InputDeviceListener, Handler>(); defaultHandler = new PollingMessageHandler(this); } }
Triển khai đối tượng PollingMessageHandler
mở rộng
Handler
và ghi đè
handleMessage()
. Phương thức này sẽ kiểm tra xem tay điều khiển trò chơi đi kèm có bị
đã ngắt kết nối và thông báo cho các trình nghe đã đăng ký.
Kotlin
private class PollingMessageHandler( inputManager: InputManagerV9, private val mInputManager: WeakReference<InputManagerV9> = WeakReference(inputManager) ) : Handler() { override fun handleMessage(msg: Message) { super.handleMessage(msg) when (msg.what) { MESSAGE_TEST_FOR_DISCONNECT -> { mInputManager.get()?.also { imv -> val time = SystemClock.elapsedRealtime() val size = imv.devices.size() for (i in 0 until size) { imv.devices.valueAt(i)?.also { lastContact -> if (time - lastContact[0] > CHECK_ELAPSED_TIME) { // check to see if the device has been // disconnected val id = imv.devices.keyAt(i) if (null == InputDevice.getDevice(id)) { // Notify the registered listeners // that the game controller is disconnected imv.devices.remove(id) } else { lastContact[0] = time } } } } sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME) } } } } }
Java
private static class PollingMessageHandler extends Handler { private final WeakReference<InputManagerV9> inputManager; PollingMessageHandler(InputManagerV9 im) { inputManager = new WeakReference<InputManagerV9>(im); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MESSAGE_TEST_FOR_DISCONNECT: InputManagerV9 imv = inputManager.get(); if (null != imv) { long time = SystemClock.elapsedRealtime(); int size = imv.devices.size(); for (int i = 0; i < size; i++) { long[] lastContact = imv.devices.valueAt(i); if (null != lastContact) { if (time - lastContact[0] > CHECK_ELAPSED_TIME) { // check to see if the device has been // disconnected int id = imv.devices.keyAt(i); if (null == InputDevice.getDevice(id)) { // Notify the registered listeners // that the game controller is disconnected imv.devices.remove(id); } else { lastContact[0] = time; } } } } sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME); } break; } } }
Ghi đè để bắt đầu và dừng thăm dò ý kiến ngắt kết nối tay điều khiển trò chơi các phương thức sau:
Kotlin
private const val MESSAGE_TEST_FOR_DISCONNECT = 101 private const val CHECK_ELAPSED_TIME = 3000L class InputManagerV9( val devices: SparseArray<Array<Long>> = SparseArray(), private val listeners: MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf() ) : InputManagerCompat { ... override fun onPause() { defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT) } override fun onResume() { defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME) } ... }
Java
private static final int MESSAGE_TEST_FOR_DISCONNECT = 101; private static final long CHECK_ELAPSED_TIME = 3000L; @Override public void onPause() { defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT); } @Override public void onResume() { defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME); }
Để phát hiện xem một thiết bị đầu vào đã được thêm hay chưa, hãy ghi đè
onGenericMotionEvent()
. Khi hệ thống báo cáo một sự kiện chuyển động,
kiểm tra xem sự kiện này đến từ một mã thiết bị đã được theo dõi hay từ một
mã thiết bị mới. Nếu mã thiết bị là mới, hãy thông báo cho trình nghe đã đăng ký.
Kotlin
override fun onGenericMotionEvent(event: MotionEvent) { // detect new devices val id = event.deviceId val timeArray: Array<Long> = mDevices.get(id) ?: run { // Notify the registered listeners that a game controller is added ... arrayOf<Long>().also { mDevices.put(id, it) } } timeArray[0] = SystemClock.elapsedRealtime() }
Java
@Override public void onGenericMotionEvent(MotionEvent event) { // detect new devices int id = event.getDeviceId(); long[] timeArray = mDevices.get(id); if (null == timeArray) { // Notify the registered listeners that a game controller is added ... timeArray = new long[1]; mDevices.put(id, timeArray); } long time = SystemClock.elapsedRealtime(); timeArray[0] = time; }
Thông báo của trình nghe được triển khai bằng cách sử dụng
Đối tượng Handler
để gửi DeviceEvent
Runnable
vào hàng đợi tin nhắn. DeviceEvent
chứa tham chiếu đến InputManagerCompat.InputDeviceListener
. Thời gian
DeviceEvent
chạy, phương thức gọi lại thích hợp của trình nghe
được gọi để báo hiệu liệu tay điều khiển trò chơi đã được thêm, thay đổi hoặc bị xoá hay chưa.
Kotlin
class InputManagerV9( val devices: SparseArray<Array<Long>> = SparseArray(), private val listeners: MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf() ) : InputManagerCompat { ... override fun registerInputDeviceListener( listener: InputManager.InputDeviceListener, handler: Handler? ) { listeners[listener] = handler ?: defaultHandler } override fun unregisterInputDeviceListener(listener: InputManager.InputDeviceListener) { listeners.remove(listener) } private fun notifyListeners(why: Int, deviceId: Int) { // the state of some device has changed listeners.forEach { listener, handler -> DeviceEvent.getDeviceEvent(why, deviceId, listener).also { handler?.post(it) } } } ... } private val sObjectQueue: Queue<DeviceEvent> = ArrayDeque<DeviceEvent>() private class DeviceEvent( private var mMessageType: Int, private var mId: Int, private var mListener: InputManager.InputDeviceListener ) : Runnable { companion object { fun getDeviceEvent(messageType: Int, id: Int, listener: InputManager.InputDeviceListener) = sObjectQueue.poll()?.apply { mMessageType = messageType mId = id mListener = listener } ?: DeviceEvent(messageType, id, listener) } override fun run() { when(mMessageType) { ON_DEVICE_ADDED -> mListener.onInputDeviceAdded(mId) ON_DEVICE_CHANGED -> mListener.onInputDeviceChanged(mId) ON_DEVICE_REMOVED -> mListener.onInputDeviceChanged(mId) else -> { // Handle unknown message type } } } }
Java
@Override public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) { listeners.remove(listener); if (handler == null) { handler = defaultHandler; } listeners.put(listener, handler); } @Override public void unregisterInputDeviceListener(InputDeviceListener listener) { listeners.remove(listener); } private void notifyListeners(int why, int deviceId) { // the state of some device has changed if (!listeners.isEmpty()) { for (InputDeviceListener listener : listeners.keySet()) { Handler handler = listeners.get(listener); DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener); handler.post(odc); } } } private static class DeviceEvent implements Runnable { private int mMessageType; private int mId; private InputDeviceListener mListener; private static Queue<DeviceEvent> sObjectQueue = new ArrayDeque<DeviceEvent>(); ... static DeviceEvent getDeviceEvent(int messageType, int id, InputDeviceListener listener) { DeviceEvent curChanged = sObjectQueue.poll(); if (null == curChanged) { curChanged = new DeviceEvent(); } curChanged.mMessageType = messageType; curChanged.mId = id; curChanged.mListener = listener; return curChanged; } @Override public void run() { switch (mMessageType) { case ON_DEVICE_ADDED: mListener.onInputDeviceAdded(mId); break; case ON_DEVICE_CHANGED: mListener.onInputDeviceChanged(mId); break; case ON_DEVICE_REMOVED: mListener.onInputDeviceRemoved(mId); break; default: // Handle unknown message type ... break; } // Put this runnable back in the queue sObjectQueue.offer(this); } }
Bạn hiện có hai cách triển khai InputManagerCompat
: một cách triển khai
hoạt động trên các thiết bị chạy Android 4.1 trở lên và
hoạt động trên các thiết bị chạy Android 3.1 tới Android 4.0.
Sử dụng phương pháp triển khai theo phiên bản cụ thể
Logic chuyển đổi dành riêng cho phiên bản được triển khai trong một lớp đóng vai trò là nhà máy.
Kotlin
object Factory { fun getInputManager(context: Context): InputManagerCompat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { InputManagerV16(context) } else { InputManagerV9() } }
Java
public static class Factory { public static InputManagerCompat getInputManager(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { return new InputManagerV16(context); } else { return new InputManagerV9(); } } }
Bây giờ, bạn chỉ cần tạo thực thể cho đối tượng InputManagerCompat
và
hãy đăng ký một InputManagerCompat.InputDeviceListener
trong
View
. Do logic chuyển đổi phiên bản mà bạn đặt
thì trò chơi của bạn sẽ tự động sử dụng cách triển khai phù hợp với
phiên bản Android mà thiết bị đang chạy.
Kotlin
class GameView(context: Context) : View(context), InputManager.InputDeviceListener { private val inputManager: InputManagerCompat = Factory.getInputManager(context).apply { registerInputDeviceListener(this@GameView, null) ... } ... }
Java
public class GameView extends View implements InputDeviceListener { private InputManagerCompat inputManager; ... public GameView(Context context, AttributeSet attrs) { inputManager = InputManagerCompat.Factory.getInputManager(this.getContext()); inputManager.registerInputDeviceListener(this, null); ... } }
Tiếp theo, hãy ghi đè
Phương thức onGenericMotionEvent()
trong khung hiển thị chính, như mô tả trong
Xử lý MotionEvent từ một trò chơi
Bộ điều khiển. Giờ đây, trò chơi của bạn có thể xử lý các sự kiện trên tay điều khiển trò chơi
nhất quán trên các thiết bị chạy Android 3.1 (API cấp 12) trở lên.
Kotlin
override fun onGenericMotionEvent(event: MotionEvent): Boolean { inputManager.onGenericMotionEvent(event) // Handle analog input from the controller as normal ... return super.onGenericMotionEvent(event) }
Java
@Override public boolean onGenericMotionEvent(MotionEvent event) { inputManager.onGenericMotionEvent(event); // Handle analog input from the controller as normal ... return super.onGenericMotionEvent(event); }
Bạn có thể tìm thấy cách triển khai đầy đủ mã tương thích này trong
Lớp GameView
được cung cấp trong ControllerSample.zip
mẫu
có thể tải xuống ở trên.