קלט העכבר

בנושא הזה מוסבר איך להטמיע קלט עכבר עבור Google Play Games במחשב עבור משחקים שבהם מצב תרגום הקלט לא מספק חוויית שחקן אידיאלית.

לשחקני מחשב בדרך כלל יש מקלדת ועכבר במקום מסך מגע, ולכן חשוב לבדוק אם המשחק כולל קלט עכבר. כברירת מחדל, ב-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 במחשב עוברת לגרסה הנכונה במצב מופעל כשמשחק מופעל. כשמריצים באמולטור המפתח, צריך: לוחצים לחיצה ימנית על הסמל של סרגל האפליקציות, בוחרים באפשרות אפשרויות למפתחים, ואז PC mode(KiwiMouse) כדי לקבל קלט גולמי מהעכבר.

צילום מסך של &quot;PC mode(KiwiMouse)&quot; נבחרו בתפריט ההקשר

אחרי שתעשו זאת, תנועת העכבר תדווח על ידי 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. דלתא מכיוון שניתן לאחזר את הפריים האחרון באמצעות 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. עליך להמתין לאינטראקציה של הנגן בלחיצה על סמן העכבר, למשל במהלך אינטראקציה עם התפריט הראשי, או 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().