این مبحث نحوه پیادهسازی ورودی ماوس برای بازیهای Google Play در رایانه شخصی را برای بازیهایی که حالت ترجمه ورودی تجربه بازیکنی ایدهآل ارائه نمیدهد، پوشش میدهد.
پخشکنندههای رایانههای شخصی معمولاً به جای صفحهنمایش لمسی، صفحهکلید و ماوس دارند، و این مهم است که در نظر بگیرید آیا بازی شما ورودی ماوس را دارد یا خیر. بهطور پیشفرض، بازیهای Google Play در رایانه شخصی هر رویداد کلیک چپ ماوس را به یک رویداد ضربه مجازی تبدیل میکند. این به عنوان "حالت ترجمه ورودی" شناخته می شود.
اگرچه این حالت با تغییرات اندکی بازی شما را کاربردی می کند، اما تجربه ای با احساس بومی برای بازیکنان رایانه شخصی فراهم نمی کند. برای این منظور توصیه می کنیم موارد زیر را پیاده سازی کنید:
- به جای فشار دادن و نگه داشتن عملکردها، حالت ها را برای منوهای زمینه نگه دارید
- برای اقدامات جایگزینی که با فشار طولانی یا در منوی زمینه اتفاق میافتند، کلیک راست کنید
- ماوس را برای بازی های اکشن اول یا سوم شخص به جای یک رویداد مطبوعاتی و کشیدنی جستجو کنید
به منظور پشتیبانی از الگوهای رابط کاربری رایج در رایانه های شخصی، باید حالت ترجمه ورودی را غیرفعال کنید.
مدیریت ورودی بازیهای Google Play در رایانه شخصی مشابه ChromeOS است. تغییراتی که از رایانه های شخصی پشتیبانی می کند همچنین بازی شما را برای همه بازیکنان اندروید بهبود می بخشد.
در فایل AndroidManifest.xml
، ویژگی android.hardware.type.pc
را اعلام کنید. این نشان می دهد که بازی شما از سخت افزار رایانه شخصی استفاده می کند و حالت ترجمه ورودی را غیرفعال می کند. علاوه بر این، افزودن required="false"
به شما کمک می کند تا مطمئن شوید که بازی شما همچنان می تواند بدون ماوس روی تلفن ها و تبلت ها نصب شود. به عنوان مثال:
<manifest ...>
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
...
</manifest>
نسخه تولیدی بازیهای Google Play در رایانه شخصی هنگام راهاندازی بازی به حالت صحیح تغییر میکند. هنگام اجرا در شبیه ساز توسعه دهنده، باید روی نماد نوار وظیفه کلیک راست کنید، گزینه های توسعه دهنده و سپس حالت PC (KiwiMouse) را برای دریافت ورودی خام ماوس انتخاب کنید.
پس از انجام این کار، حرکت ماوس توسط View.onGenericMotionEvent با منبع SOURCE_MOUSE
گزارش می شود که نشان می دهد این یک رویداد ماوس است.
gameView.setOnGenericMotionListener { _, motionEvent -> var handled = false if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // handle the mouse event here handled = true } handled }
gameView.setOnGenericMotionListener((view, motionEvent) -> { if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // handle the mouse event here return true; } return false; });
برای جزئیات در مورد مدیریت ورودی ماوس، به مستندات ChromeOS مراجعه کنید.
برای تشخیص حرکت ماوس، به رویدادهای ACTION_HOVER_ENTER
، ACTION_HOVER_EXIT
و ACTION_HOVER_MOVE
گوش دهید.
این به بهترین وجه برای تشخیص معلق بودن کاربر روی دکمهها یا اشیاء در بازی استفاده میشود و به شما فرصتی میدهد تا یک جعبه اشاره نمایش دهید یا یک حالت ماوس را برای برجسته کردن چیزی که بازیکن میخواهد انتخاب کند، اجرا کنید. به عنوان مثال:
gameView.setOnGenericMotionListener { _, motionEvent -> var handled = false if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { when(motionEvent.action) { MotionEvent.ACTION_HOVER_ENTER -> Log.d("MA", "Mouse entered at ${motionEvent.x}, ${motionEvent.y}") MotionEvent.ACTION_HOVER_EXIT -> Log.d("MA", "Mouse exited at ${motionEvent.x}, ${motionEvent.y}") MotionEvent.ACTION_HOVER_MOVE -> Log.d("MA", "Mouse hovered at ${motionEvent.x}, ${motionEvent.y}") } handled = true } handled }
gameView.setOnGenericMotionListener((view, motionEvent) -> { if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_HOVER_ENTER: Log.d("MA", "Mouse entered at " + motionEvent.getX() + ", " + motionEvent.getY()); break; case MotionEvent.ACTION_HOVER_EXIT: Log.d("MA", "Mouse exited at " + motionEvent.getX() + ", " + motionEvent.getY()); break; case MotionEvent.ACTION_HOVER_MOVE: Log.d("MA", "Mouse hovered at " + motionEvent.getX() + ", " + motionEvent.getY()); break; } return true; } return false; });
رایانههای شخصی مدتهاست که دارای دکمههای چپ و راست ماوس بوده و عناصر تعاملی را هم عملکردهای اولیه و هم ثانویه ارائه میدهند. در یک بازی، اعمال ضربه مانند ضربه زدن روی یک دکمه به بهترین وجه برای کلیک چپ نشان داده میشوند، جایی که اعمال لمس و نگه داشتن با کلیک راست طبیعیترین حالت را دارند. در بازی های استراتژی بلادرنگ می توانید از کلیک چپ برای انتخاب و کلیک راست برای حرکت استفاده کنید. تیراندازهای اول شخص ممکن است تیراندازی اولیه و ثانویه را به سمت چپ و راست کلیک کنند. یک دونده بی نهایت ممکن است از کلیک چپ برای پرش و کلیک راست برای خط تیره استفاده کند. ما برای رویداد کلیک میانی پشتیبانی اضافه نکرده ایم.
برای کنترل فشار دکمه، از ACTION_DOWN
و ACTION_UP
استفاده کنید. سپس getActionButton
برای تعیین اینکه کدام دکمه اکشن را راه اندازی کرده است یا getButtonState
برای دریافت وضعیت همه دکمه ها استفاده کنید.
در این مثال، از یک enum برای کمک به نمایش نتیجه getActionButton
استفاده شده است:
enum class MouseButton { LEFT, RIGHT, UNKNOWN; companion object { fun fromMotionEvent(motionEvent: MotionEvent): MouseButton { return when (motionEvent.actionButton) { MotionEvent.BUTTON_PRIMARY -> LEFT MotionEvent.BUTTON_SECONDARY -> RIGHT else -> UNKNOWN } } } }
enum MouseButton { LEFT, RIGHT, MIDDLE, UNKNOWN; static MouseButton fromMotionEvent(MotionEvent motionEvent) { switch (motionEvent.getActionButton()) { case MotionEvent.BUTTON_PRIMARY: return MouseButton.LEFT; case MotionEvent.BUTTON_SECONDARY: return MouseButton.RIGHT; default: return MouseButton.UNKNOWN; } } }
در این مثال، عمل مشابه با رویدادهای شناور انجام می شود:
// Handle the generic motion event gameView.setOnGenericMotionListener { _, motionEvent -> var handled = false if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { when (motionEvent.action) { MotionEvent.ACTION_BUTTON_PRESS -> Log.d( "MA", "${MouseButton.fromMotionEvent(motionEvent)} pressed at ${motionEvent.x}, ${motionEvent.y}" ) MotionEvent.ACTION_BUTTON_RELEASE -> Log.d( "MA", "${MouseButton.fromMotionEvent(motionEvent)} released at ${motionEvent.x}, ${motionEvent.y}" ) } handled = true } handled }
gameView.setOnGenericMotionListener((view, motionEvent) -> { if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_BUTTON_PRESS: Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " pressed at " + motionEvent.getX() + ", " + motionEvent.getY()); break; case MotionEvent.ACTION_BUTTON_RELEASE: Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " released at " + motionEvent.getX() + ", " + motionEvent.getY()); break; } return true; } return false; });
توصیه میکنیم برای بزرگنمایی حرکات یا لمس و کشیدن نواحی اسکرول در بازیتان، از چرخ اسکرول ماوس به جای نیشگون گرفتن استفاده کنید.
برای خواندن مقادیر چرخ پیمایش، به رویداد ACTION_SCROLL
گوش دهید. دلتا از آخرین فریم را می توان با استفاده از getAxisValue
با AXIS_VSCROLL
برای افست عمودی و AXIS_HSCROLL
برای افست افقی بازیابی کرد. به عنوان مثال:
gameView.setOnGenericMotionListener { _, motionEvent -> var handled = false if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { when (motionEvent.action) { MotionEvent.ACTION_SCROLL -> { val scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL) val scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL) Log.d("MA", "Mouse scrolled $scrollX, $scrollY") } } handled = true } handled }
gameView.setOnGenericMotionListener((view, motionEvent) -> { if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { switch (motionEvent.getAction()) { case MotionEvent.ACTION_SCROLL: float scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL); float scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL); Log.d("MA", "Mouse scrolled " + scrollX + ", " + scrollY); break; } return true; } return false; });
برخی از بازیها باید کنترل کامل نشانگر ماوس را در دست بگیرند، مانند بازیهای اکشن اول یا سوم شخص که حرکت ماوس را به حرکت دوربین ترسیم میکنند. برای در دست گرفتن کنترل انحصاری ماوس، View.requestPointerCapture()
را فراخوانی کنید.
requestPointerCapture()
فقط زمانی کار می کند که سلسله مراتب view حاوی view شما فوکوس داشته باشد. به همین دلیل، نمیتوانید در پاسخ به تماس onCreate
نشانگر را به دست آورید. یا باید منتظر بمانید تا تعامل بازیکن برای گرفتن نشانگر ماوس، مانند هنگام تعامل با منوی اصلی، یا از پاسخ تماس onWindowFocusChanged
استفاده کنید. به عنوان مثال:
override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { gameView.requestPointerCapture() } }
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { View gameView = findViewById(R.id.game_view); gameView.requestPointerCapture(); } }
رویدادهای ثبت شده توسط requestPointerCapture()
به نمای قابل تمرکزی که OnCapturedPointerListener
ثبت کرده فرستاده می شود. به عنوان مثال:
gameView.focusable = View.FOCUSABLE gameView.setOnCapturedPointerListener { _, motionEvent -> Log.d("MA", "${motionEvent.x}, ${motionEvent.y}, ${motionEvent.actionButton}") true }
gameView.setFocusable(true); gameView.setOnCapturedPointerListener((view, motionEvent) -> { Log.d("MA", motionEvent.getX() + ", " + motionEvent.getY() + ", " + motionEvent.getActionButton()); return true; });
به منظور آزاد کردن ضبط انحصاری ماوس، مانند اجازه دادن به بازیکنان برای تعامل با منوی مکث، View.releasePointerCapture()
را فراخوانی کنید.