בנושא הזה נסביר איך להטמיע קלט של עכבר ב-Google Play Games במחשב למשחקים שבהם מצב תרגום הקלט לא מספק חוויית משתמש אידיאלית.
בדרך כלל, שחקנים במחשב PC משתמשים במקלדת ובעכבר במקום במסך מגע, ולכן חשוב לבדוק אם המשחק שלכם תומך בקלט מהעכבר. כברירת מחדל, Google Play Games במחשב ממירה כל אירוע לחיצה שמאלית על העכבר לאירוע וירטואלי אחד של הקשה. המצב הזה נקרא 'מצב תרגום קלט'.
למרות שהמצב הזה הופך את המשחק לפונקציונלי עם מעט שינויים, הוא לא מספק לשחקני מחשב חוויה טבעית. לשם כך, מומלץ להטמיע את הפעולות הבאות:
- מצבי עכבר מרחף לתפריטי הקשר במקום פעולות של לחיצה ארוכה
- לחיצה ימנית כדי לבצע פעולות חלופיות שמתרחשות בלחיצה ארוכה או בתפריט ההקשר
- משחקי פעולה בגוף ראשון או בגוף שלישי עם תצוגת מצלמה שמאפשרת להסתכל על העולם דרך עיני הדמות באמצעות העכבר, במקום אירוע של לחיצה וגרירה
כדי לתמוך בדפוסי ממשק משתמש נפוצים במחשבים, צריך להשבית את מצב תרגום הקלט.
אופן הטיפול בקלט ב-Google Play Games במחשב זהה לאופן הטיפול ב-ChromeOS. השינויים שתומכים במחשבים גם משפרים את המשחק לכל נגני Android.
השבתת מצב תרגום הקלט
בקובץ AndroidManifest.xml
, מגדירים את התכונה android.hardware.type.pc
.
המשמעות היא שהמשחק שלכם משתמש בחומרה של מחשב ומשבית את מצב תרגום הקלט. בנוסף, הוספת required="false"
עוזרת לוודא שעדיין אפשר להתקין את המשחק בטלפונים ובטאבלטים בלי עכבר. לדוגמה:
<manifest ...>
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
...
</manifest>
גרסת הייצור של Google Play Games במחשב עוברת למצב הנכון כשמשחק מופעל. כשמריצים את האפליקציה במהנתח למפתחים, צריך ללחוץ לחיצה ימנית על הסמל של שורת המשימות, לבחור באפשרות Developer Options ואז באפשרות PC mode(KiwiMouse) כדי לקבל קלט גולמי מהעכבר.
אחרי שתעשו זאת, תנועת העכבר תדווח על ידי View.onGeneralMotionEvent עם המקור SOURCE_MOUSE
, שמציין שמדובר באירוע בעכבר.
Kotlin
gameView.setOnGenericMotionListener { _, motionEvent -> var handled = false if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // handle the mouse event here handled = true } handled }
Java
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
.
מומלץ להשתמש באירוע הזה כדי לזהות מתי המשתמש מעביר את העכבר מעל לחצנים או אובייקטים במשחק, וכך להציג תיבת רמז או להטמיע מצב של מעבר עכבר כדי להדגיש את מה שהשחקן עומד לבחור. לדוגמה:
Kotlin
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 }
Java
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
:
Kotlin
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 } } } }
Java
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; } } }
בדוגמה הזו, הפעולה מטופלת בדומה לאירועים של העברת העכבר:
Kotlin
// 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 }
Java
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
. אפשר לאחזר את ה-delta מאז המסגרת האחרונה באמצעות getAxisValue
עם AXIS_VSCROLL
להיסט אנכי ו-AXIS_HSCROLL
להיסט אופקי. לדוגמה:
Kotlin
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 }
Java
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()
פועל רק כשמתמקדים בהיררכיית התצוגות שכוללת את התצוגה. לכן אי אפשר לקבל תיעוד של מיקום הסמן בקריאה החוזרת onCreate
. צריך להמתין לאינטראקציה של השחקן כדי לתעד את סמן העכבר, למשל כשמתבצעת אינטראקציה עם התפריט הראשי, או להשתמש ב-callback onWindowFocusChanged
. לדוגמה:
Kotlin
override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { gameView.requestPointerCapture() } }
Java
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { View gameView = findViewById(R.id.game_view); gameView.requestPointerCapture(); } }
אירועים שתועדו על ידי requestPointerCapture()
מועברים לתצוגה שניתן להתמקד בה, שרשמה את OnCapturedPointerListener
. לדוגמה:
Kotlin
gameView.focusable = View.FOCUSABLE gameView.setOnCapturedPointerListener { _, motionEvent -> Log.d("MA", "${motionEvent.x}, ${motionEvent.y}, ${motionEvent.actionButton}") true }
Java
gameView.setFocusable(true); gameView.setOnCapturedPointerListener((view, motionEvent) -> { Log.d("MA", motionEvent.getX() + ", " + motionEvent.getY() + ", " + motionEvent.getActionButton()); return true; });
כדי לשחרר את הצילום הבלעדי של העכבר, למשל כדי לאפשר לשחקנים לבצע פעולות בתפריט ההשהיה, מפעילים את הפקודה View.releasePointerCapture()
.