אם אתם תומכים בבקרי משחקים במשחק שלכם, באחריותכם לוודא שהמשחק מגיב לבקרים באופן עקבי במכשירים שפועלים בגרסאות שונות של Android. כך המשחק שלכם יכול להגיע לקהל רחב יותר, והשחקנים יכולים ליהנות מחוויית משחק חלקה עם הבקרים שלהם גם כשהם מחליפים את מכשירי Android או משדרגים אותם.
בשיעור הזה נסביר איך להשתמש בממשקי API שזמינים ב-Android 4.1 ומעלה בצורה שתואמת לאחור, כדי שהמשחק שלכם יתמוך בתכונות הבאות במכשירים עם Android 3.1 ומעלה:
- המשחק יכול לזהות אם נוסף בקר משחק חדש, אם הוא השתנה או אם הוא הוסר.
- המשחק יכול לשלוח שאילתה לגבי היכולות של בקר משחקים.
- המשחק יכול לזהות אירועי תנועה נכנסים משלט משחק.
הכנה להפשטת ממשקי API לתמיכה בבקרי משחקים
נניח שאתם רוצים לקבוע אם סטטוס החיבור של בקר משחקים השתנה במכשירים שמריצים Android 3.1 (רמת API 12). עם זאת, ממשקי ה-API זמינים רק ב-Android מגרסה 4.1 (רמת API 16) ואילך, ולכן צריך לספק הטמעה שתומכת ב-Android מגרסה 4.1 ואילך, וגם מנגנון חלופי שתומך ב-Android מגרסה 3.1 עד Android 4.0.
כדי לעזור לכם להבין אילו תכונות דורשות מנגנון חלופי לגרסאות ישנות יותר, בטבלה 1 מפורטים ההבדלים בתמיכה בבקרי משחקים בין Android 3.1 (רמת API 12) לבין Android 4.1 (רמת API 16).
טבלה 1. ממשקי API לתמיכה בבקרי משחקים בגרסאות שונות של Android.
| פרטי בקר | Controller API | רמת API 12 | רמת API 16 |
|---|---|---|---|
| זיהוי מכשיר | getInputDeviceIds() |
• | |
getInputDevice() |
• | ||
getVibrator() |
• | ||
SOURCE_JOYSTICK |
• | • | |
SOURCE_GAMEPAD |
• | • | |
| סטטוס החיבור | onInputDeviceAdded() |
• | |
onInputDeviceChanged() |
• | ||
onInputDeviceRemoved() |
• | ||
| זיהוי אירוע קלט | לחיצה על לחצן הכיוונים (D-pad) (
KEYCODE_DPAD_UP,
KEYCODE_DPAD_DOWN,
KEYCODE_DPAD_LEFT,
KEYCODE_DPAD_RIGHT,
KEYCODE_DPAD_CENTER) |
• | • |
לחיצה על לחצן ב-Gamepad (
BUTTON_A,
BUTTON_B,
BUTTON_THUMBL,
BUTTON_THUMBR,
BUTTON_SELECT,
BUTTON_START,
BUTTON_R1,
BUTTON_L1,
BUTTON_R2,
BUTTON_L2) |
• | • | |
תנועה בג'ויסטיק ובמתג הכובע (AXIS_X,AXIS_Y,AXIS_Z,AXIS_RZ,AXIS_HAT_X,AXIS_HAT_Y) |
• | • | |
לחיצה על לחצן אנלוגי (
AXIS_LTRIGGER,
AXIS_RTRIGGER) |
• | • |
אתם יכולים להשתמש בהפשטה כדי ליצור תמיכה בבקרי משחקים שמודעת לגרסה ופועלת בפלטפורמות שונות. הגישה הזו כוללת את השלבים הבאים:
- הגדרת ממשק Java מתווך שמבצע הפשטה של ההטמעה של תכונות בקר המשחקים שנדרשות במשחק.
- יוצרים הטמעה של פרוקסי לממשק שמשתמש בממשקי API ב-Android מגרסה 4.1 ומעלה.
- יוצרים הטמעה מותאמת אישית של הממשק באמצעות ממשקי API שזמינים בגרסאות Android 3.1 עד Android 4.0.
- יוצרים את הלוגיקה למעבר בין ההטמעות האלה בזמן ריצה, ומתחילים להשתמש בממשק במשחק.
במאמר יצירת ממשקי משתמש שתואמים לאחור מוסבר איך אפשר להשתמש באבסטרקציה כדי לוודא שאפליקציות יכולות לפעול בצורה שתואמת לאחור בגרסאות שונות של Android.
הוספת ממשק לתאימות לאחור
כדי לספק תאימות לאחור, אפשר ליצור ממשק בהתאמה אישית ואז להוסיף הטמעות ספציפיות לגרסה. אחד היתרונות של הגישה הזו הוא שהיא מאפשרת לשקף את הממשקים הציבוריים ב-Android 4.1 (רמת API 16) שתומכים בבקרי משחקים.
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);
}
...
}
ממשק InputManagerCompat מספק את השיטות הבאות:
getInputDevice()- שיקוף מסך
getInputDevice(). מקבל את אובייקטInputDeviceשמייצג את היכולות של בקר משחקים. getInputDeviceIds()- שיקוף מסך
getInputDeviceIds(). הפונקציה מחזירה מערך של מספרים שלמים, שכל אחד מהם הוא מזהה של מכשיר קלט שונה. האפשרות הזו שימושית אם אתם מפתחים משחק עם תמיכה בכמה שחקנים ורוצים לזהות כמה בקרים מחוברים. registerInputDeviceListener()- שיקוף מסך
registerInputDeviceListener(). מאפשר להירשם לקבלת הודעה כשמכשיר חדש מתווסף, משתנה או מוסר. unregisterInputDeviceListener()- שיקוף מסך
unregisterInputDeviceListener(). ביטול הרישום של מעבד אירוע של מכשיר קלט. onGenericMotionEvent()- שיקוף מסך
onGenericMotionEvent(). מאפשר למשחק ליירט ולטפל באובייקטים ובערכי ציר שמייצגים אירועים כמו תנועות של ג'ויסטיק ולחיצות על הדק אנלוגי. onPause()- ההגדרה מפסיקה את הסקר לגבי אירועים של בקר משחקים כשהפעילות הראשית מושהית או כשהמשחק כבר לא נמצא במוקד.
onResume()- התחלת שליחת בקשות (polling) לאירועים של בקר משחקים כשהפעילות הראשית ממשיכה, או כשהמשחק מתחיל ופועל בחזית.
InputDeviceListener- משקף את הממשק.
InputManager.InputDeviceListenerמאפשרת למשחק לדעת מתי נוסף בקר משחק, מתי הוא השתנה או מתי הוא הוסר.
MotionEvent
לאחר מכן, יוצרים הטמעות של InputManagerCompat שפועלות בגרסאות שונות של הפלטפורמה. אם המשחק שלכם פועל ב-Android 4.1 או בגרסה מתקדמת יותר ומפעיל method של InputManagerCompat, הטמעת ה-proxy מפעילה את ה-method המקביל ב-InputManager.
עם זאת, אם המשחק שלכם פועל ב-Android מגרסה 3.1 עד גרסה 4.0, ההטמעה המותאמת אישית מעבדת קריאות לשיטות InputManagerCompat באמצעות ממשקי API שהוצגו לכל המאוחר ב-Android 3.1. לא משנה באיזו הטמעה ספציפית לגרסה נעשה שימוש בזמן הריצה, ההטמעה מעבירה את תוצאות הקריאה בחזרה למשחק באופן שקוף.
הטמעה של הממשק ב-Android מגרסה 4.1 ואילך
InputManagerCompatV16 הוא הטמעה של הממשק InputManagerCompat שמעביר קריאות של מתודות ל-InputManager ו-InputManager.InputDeviceListener בפועל.
ה-InputManager מתקבל מ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
}
}
הטמעה של הממשק ב-Android מגרסה 3.1 עד גרסה 4.0
כדי ליצור הטמעה של InputManagerCompat שתומכת ב-Android מגרסה 3.1 עד גרסה 4.0, אפשר להשתמש באובייקטים הבאים:
SparseArrayשל מזהי מכשירים למעקב אחרי השלטים לגיימינג שמחוברים למכשיר.Handlerלעיבוד אירועים במכשיר. כשמפעילים או מפעילים מחדש אפליקציה,Handlerמקבל הודעה להתחיל לבצע סקר כדי לבדוק אם בקר המשחקים מנותק. הסקריפטHandlerיתחיל לולאה כדי לבדוק כל שלט גיימינג מחובר מוכר ולראות אם מוחזר מזהה מכשיר. ערך ההחזרהnullמציין שהשלט של משחק המחשב מנותק. האפליקציהHandlerמפסיקה את הסקר כשהיא מושהית.Mapשל אובייקטים מסוגInputManagerCompat.InputDeviceListener. תשתמשו ב-listeners כדי לעדכן את סטטוס החיבור של בקרי המשחקים שעוקבים אחריהם.
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);
}
}
מטמיעים אובייקט PollingMessageHandler שמרחיב את Handler ומבטלים את השיטה handleMessage(). השיטה הזו בודקת אם שלט משחק שמחובר למכשיר התנתק, ומודיעה על כך ל-listeners רשומים.
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;
}
}
}
כדי להתחיל ולהפסיק את הבדיקה אם בקר המשחק התנתק, צריך לבטל את השיטות האלה:
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);
}
כדי לזהות שנוסף מיקרופון, צריך לבטל את השיטה onGenericMotionEvent(). כשהמערכת מדווחת על אירוע תנועה, צריך לבדוק אם האירוע הזה הגיע ממזהה מכשיר שכבר מתבצע אחריו מעקב, או ממזהה מכשיר חדש. אם מזהה המכשיר חדש, נשלחת הודעה למאזינים הרשומים.
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;
}
ההודעה על המאזינים מיושמת באמצעות האובייקט Handler כדי לשלוח אובייקט DeviceEvent
Runnable לתור ההודעות.
התג DeviceEvent מכיל הפניה ל-InputManagerCompat.InputDeviceListener. כש-DeviceEvent פועל, מתבצעת קריאה לשיטת הקריאה החוזרת המתאימה של המאזין כדי לציין אם בקר המשחקים נוסף, השתנה או הוסר.
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);
}
}
עכשיו יש לכם שתי הטמעות של InputManagerCompat: אחת שפועלת במכשירים עם Android מגרסה 4.1 ואילך, ואחת שפועלת במכשירים עם Android מגרסה 3.1 עד Android 4.0.
שימוש בהטמעה ספציפית לגרסה
הלוגיקה של המעבר בין גרסאות מוטמעת במחלקה שפועלת כ מפעל.
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();
}
}
}
עכשיו אפשר ליצור מופע של אובייקט InputManagerCompat ולרשום InputManagerCompat.InputDeviceListener ב-View הראשי. בגלל הלוגיקה של מעבר הגרסה שהגדרתם, המשחק משתמש באופן אוטומטי בהטמעה שמתאימה לגרסת Android שפועלת במכשיר.
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);
...
}
}
לאחר מכן, מבטלים את השיטה onGenericMotionEvent() בתצוגה הראשית, כמו שמתואר במאמר טיפול ב-MotionEvent מבקר משחקים (גרסה 3.0 ואילך). המשחק שלך אמור להיות מסוגל לעבד עכשיו אירועים של בקר משחקים באופן עקבי במכשירים עם Android 3.1 (רמת API).
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);
}
אפשר למצוא הטמעה מלאה של קוד התאימות הזה במחלקה GameView שמופיעה בדוגמה ControllerSample.zip שזמינה להורדה.