اگر از کنترلرهای بازی در بازی خود پشتیبانی می کنید، این مسئولیت شماست که مطمئن شوید که بازی شما به طور مداوم به کنترلرها در دستگاه هایی که روی نسخه های مختلف اندروید اجرا می شوند پاسخ می دهد. این به بازی شما اجازه میدهد تا مخاطبان بیشتری را جذب کند و بازیکنان شما میتوانند از یک تجربه گیمپلی یکپارچه با کنترلرهای خود لذت ببرند، حتی زمانی که دستگاههای اندرویدی خود را تعویض یا ارتقا میدهند.
این درس نحوه استفاده از APIهای موجود در Android نسخه 4.1 و بالاتر را به روشی سازگار با عقب نشان میدهد و بازی شما را قادر میسازد از ویژگیهای زیر در دستگاههای دارای Android نسخه 3.1 و بالاتر پشتیبانی کند:
- این بازی می تواند تشخیص دهد که آیا یک کنترلر بازی جدید اضافه، تغییر یا حذف شده است.
- بازی می تواند قابلیت های یک کنترلر بازی را جویا شود.
- بازی می تواند رویدادهای حرکتی ورودی را از یک کنترلر بازی تشخیص دهد.
مثالهای این درس بر اساس پیادهسازی مرجع ارائهشده توسط ControllerSample.zip
نمونه موجود برای دانلود در بالا است. این نمونه نحوه پیاده سازی رابط InputManagerCompat
برای پشتیبانی از نسخه های مختلف اندروید را نشان می دهد. برای کامپایل نمونه باید از اندروید 4.1 (سطح API 16) یا بالاتر استفاده کنید. پس از کامپایل، برنامه نمونه بر روی هر دستگاهی که اندروید 3.1 (سطح API 12) یا بالاتر به عنوان هدف ساخت دارد اجرا می شود.
برای پشتیبانی از کنترلرهای بازی، API های انتزاعی را آماده کنید
فرض کنید میخواهید بتوانید تعیین کنید که آیا وضعیت اتصال یک کنترلکننده بازی در دستگاههای دارای Android 3.1 (سطح API 12) تغییر کرده است یا خیر. با این حال، APIها فقط در اندروید 4.1 (سطح API 16) و بالاتر در دسترس هستند، بنابراین باید پیادهسازی را ارائه دهید که از اندروید 4.1 و بالاتر پشتیبانی میکند و در عین حال مکانیسم بازگشتی ارائه میدهد که از اندروید 3.1 تا اندروید 4.0 پشتیبانی میکند.
برای کمک به شما در تعیین اینکه کدام ویژگیها برای نسخههای قدیمیتر به چنین مکانیزم بازگشتی نیاز دارند، جدول 1 تفاوتهای پشتیبانی از کنترلر بازی را بین Android 3.1 (سطح API 12) و 4.1 (سطح API 16) فهرست میکند.
اطلاعات کنترلر | API کنترلر | API سطح 12 | API سطح 16 |
---|---|---|---|
شناسایی دستگاه | getInputDeviceIds() | • | |
getInputDevice() | • | ||
getVibrator() | • | ||
SOURCE_JOYSTICK | • | • | |
SOURCE_GAMEPAD | • | • | |
وضعیت اتصال | onInputDeviceAdded() | • | |
onInputDeviceChanged() | • | ||
onInputDeviceRemoved() | • | ||
شناسایی رویداد ورودی | دکمه D ( KEYCODE_DPAD_UP ، KEYCODE_DPAD_DOWN ، KEYCODE_DPAD_LEFT ، KEYCODE_DPAD_RIGHT ، KEYCODE_DPAD_CENTER ) | • | • |
فشار دادن دکمه گیم پد ( 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 ) | • | • |
میتوانید از انتزاع برای ایجاد پشتیبانی از کنترلر بازی آگاه از نسخه استفاده کنید که در همه پلتفرمها کار میکند. این رویکرد شامل مراحل زیر است:
- یک رابط جاوا واسط تعریف کنید که اجرای ویژگی های کنترلر بازی مورد نیاز بازی شما را خلاصه می کند.
- یک پیاده سازی پروکسی از رابط خود ایجاد کنید که از API در Android نسخه 4.1 و بالاتر استفاده می کند.
- یک پیاده سازی سفارشی از رابط خود ایجاد کنید که از API های موجود بین Android 3.1 تا Android 4.0 استفاده می کند.
- منطقی را برای جابجایی بین این پیاده سازی ها در زمان اجرا ایجاد کنید و شروع به استفاده از رابط در بازی خود کنید.
برای یک نمای کلی از نحوه استفاده از انتزاع برای اطمینان از اینکه برنامهها میتوانند به روشی سازگار با عقب در نسخههای مختلف Android کار کنند، به ایجاد رابطهای کاربری سازگار با عقب نگاه کنید.
یک رابط برای سازگاری با عقب اضافه کنید
برای ارائه سازگاری به عقب، می توانید یک رابط سفارشی ایجاد کنید و سپس پیاده سازی های خاص نسخه را اضافه کنید. یکی از مزایای این روش این است که به شما امکان می دهد رابط های عمومی را در اندروید 4.1 (سطح API 16) که از کنترلرهای بازی پشتیبانی می کنند، منعکس کنید.
کاتلین
// 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) } }
جاوا
// 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()
- Mirrors
unregisterInputDeviceListener()
. یک شنونده دستگاه ورودی را لغو ثبت می کند. -
onGenericMotionEvent()
- Mirrors
onGenericMotionEvent()
. به بازی شما اجازه میدهد اشیاء و مقادیر محورMotionEvent
را که نشاندهنده رویدادهایی مانند حرکات جوی استیک و فشارهای ماشه آنالوگ هستند، رهگیری کرده و مدیریت کند. -
onPause()
- هنگامی که فعالیت اصلی متوقف می شود یا زمانی که بازی دیگر فوکوس ندارد، نظرسنجی را برای رویدادهای کنترلر بازی متوقف می کند.
-
onResume()
- زمانی که فعالیت اصلی از سر گرفته می شود، یا زمانی که بازی شروع شده و در پیش زمینه اجرا می شود، نظرسنجی را برای رویدادهای کنترلر بازی شروع می کند.
-
InputDeviceListener
- رابط
InputManager.InputDeviceListener
را منعکس می کند. هنگامی که یک کنترلر بازی اضافه، تغییر یا حذف شده است، به بازی شما اطلاع می دهد.
سپس، پیادهسازیهایی را برای InputManagerCompat
ایجاد کنید که در نسخههای مختلف پلتفرم کار میکنند. اگر بازی شما روی اندروید 4.1 یا بالاتر اجرا میشود و یک روش InputManagerCompat
را فراخوانی میکند، اجرای پروکسی روش معادل را در InputManager
فراخوانی میکند. با این حال، اگر بازی شما روی اندروید 3.1 تا اندروید 4.0 اجرا میشود، پیادهسازی سفارشی با استفاده از APIهایی که حداکثر تا اندروید 3.1 معرفی شدهاند، روشهای InputManagerCompat
را فراخوانی میکند. صرف نظر از اینکه کدام نسخه خاص از پیاده سازی در زمان اجرا استفاده می شود، پیاده سازی نتایج تماس را به طور شفاف به بازی ارسال می کند.
رابط را در اندروید 4.1 و بالاتر پیاده سازی کنید
InputManagerCompatV16
پیاده سازی رابط InputManagerCompat
است که روش پراکسی را به یک InputManager
واقعی و InputManager.InputDeviceListener
فراخوانی می کند. InputManager
از Context
سیستم به دست می آید.
کاتلین
// 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 ... }
جاوا
// 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 } }
رابط را روی اندروید 3.1 تا اندروید 4.0 پیاده سازی کنید
برای ایجاد یک پیاده سازی از InputManagerCompat
که از اندروید 3.1 تا اندروید 4.0 پشتیبانی می کند، می توانید از اشیاء زیر استفاده کنید:
-
SparseArray
از شناسههای دستگاه برای ردیابی کنترلکنندههای بازی که به دستگاه متصل هستند. - یک
Handler
برای پردازش رویدادهای دستگاه. هنگامی که یک برنامه راه اندازی یا از سر گرفته می شود،Handler
پیامی برای شروع نظرسنجی برای قطع ارتباط کنترلر بازی دریافت می کند.Handler
حلقهای را شروع میکند تا هر کنترلکننده بازی متصل شناخته شده را بررسی کند و ببیند آیا شناسه دستگاه برگردانده شده است یا خیر. مقدار بازگشتیnull
نشان می دهد که کنترلر بازی قطع شده است. هنگامی که برنامه متوقف می شود،Handler
نظرسنجی را متوقف می کند. -
Map
ای از اشیاءInputManagerCompat.InputDeviceListener
. شما از شنوندگان برای به روز رسانی وضعیت اتصال کنترلرهای بازی ردیابی شده استفاده خواهید کرد.
کاتلین
// 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) … }
جاوا
// 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()
را لغو کنید. این روش بررسی می کند که آیا یک کنترلر بازی متصل شده قطع شده است یا خیر و به شنوندگان ثبت نام شده اطلاع می دهد.
کاتلین
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) } } } } }
جاوا
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; } } }
برای شروع و توقف نظرسنجی برای قطع ارتباط کنترلر بازی، این روش ها را نادیده بگیرید:
کاتلین
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) } ... }
جاوا
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()
را لغو کنید. وقتی سیستم یک رویداد حرکتی را گزارش میکند، بررسی کنید که آیا این رویداد از شناسه دستگاهی است که قبلاً ردیابی شده است یا از یک شناسه دستگاه جدید. اگر شناسه دستگاه جدید است، به شنوندگان ثبت نام شده اطلاع دهید.
کاتلین
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() }
جاوا
@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
اجرا می شود، روش پاسخ تماس مناسب شنونده فراخوانی می شود تا اگر کنترلر بازی اضافه، تغییر یا حذف شده است، علامت دهد.
کاتلین
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 } } } }
جاوا
@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 کار میکند.
از پیاده سازی مخصوص نسخه استفاده کنید
منطق سوئیچینگ نسخه خاص در کلاسی اجرا می شود که به عنوان یک کارخانه عمل می کند.
کاتلین
object Factory { fun getInputManager(context: Context): InputManagerCompat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { InputManagerV16(context) } else { InputManagerV9() } }
جاوا
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
اصلی خود ثبت کنید. به دلیل منطق تغییر نسخه ای که تنظیم کرده اید، بازی شما به طور خودکار از پیاده سازی مناسب برای نسخه اندرویدی که دستگاه در حال اجرا است استفاده می کند.
کاتلین
class GameView(context: Context) : View(context), InputManager.InputDeviceListener { private val inputManager: InputManagerCompat = Factory.getInputManager(context).apply { registerInputDeviceListener(this@GameView, null) ... } ... }
جاوا
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()
در نمای اصلی خود نادیده بگیرید، همانطور که در Handle a MotionEvent from a Game Controller توضیح داده شده است. بازی شما اکنون باید بتواند رویدادهای کنترلر بازی را به طور مداوم در دستگاههای دارای Android نسخه 3.1 (سطح API 12) و بالاتر پردازش کند.
کاتلین
override fun onGenericMotionEvent(event: MotionEvent): Boolean { inputManager.onGenericMotionEvent(event) // Handle analog input from the controller as normal ... return super.onGenericMotionEvent(event) }
جاوا
@Override public boolean onGenericMotionEvent(MotionEvent event) { inputManager.onGenericMotionEvent(event); // Handle analog input from the controller as normal ... return super.onGenericMotionEvent(event); }
میتوانید پیادهسازی کامل این کد سازگاری را در کلاس GameView
در نمونه ControllerSample.zip
موجود برای دانلود در بالا بیابید.