In diesem Thema wird beschrieben, wie Sie die Mauseingabe für Google Play Games auf dem PC für Spiele implementieren, bei denen der Eingabeübersetzungsmodus kein ideales Spielerlebnis bietet.
PC-Spieler verwenden in der Regel eine Tastatur und Maus anstelle eines Touchscreens. Daher ist es wichtig, dass Ihr Spiel auch Mauseingaben unterstützt. Standardmäßig werden bei Google Play Games auf dem PC alle Mausereignisse vom Typ „Linksklick“ in ein einzelnes virtuelles Tippereignis umgewandelt. Dies wird als „Eingabeübersetzungsmodus“ bezeichnet.
In diesem Modus ist Ihr Spiel mit nur wenigen Änderungen funktionsfähig, aber PC-Spieler haben nicht das Gefühl, dass es sich um ein natives PC-Spiel handelt. Dazu empfehlen wir Folgendes:
- Hover-Zustände für Kontextmenüs anstelle von Aktionen, die durch langes Drücken ausgelöst werden
- Mit der rechten Maustaste klicken, um alternative Aktionen aufzurufen, die bei langem Drücken oder in einem Kontextmenü ausgeführt werden
- Mouselook für Actionspiele aus der Ego- oder Third-Person-Perspektive anstelle von „Drücken und ziehen“
Um UI-Muster zu unterstützen, die auf PCs üblich sind, müssen Sie den Eingabeübersetzungsmodus deaktivieren.
Die Eingabebehandlung für Google Play Games auf dem PC ist identisch mit der von ChromeOS. Die Änderungen, die PCs unterstützen, verbessern Ihr Spiel auch für alle Android-Nutzer.
Eingabeübersetzungsmodus deaktivieren
Deklarieren Sie in der Datei AndroidManifest.xml das android.hardware.type.pc-Feature.
Das bedeutet, dass Ihr Spiel PC-Hardware verwendet und der Eingabeübersetzungsmodus deaktiviert ist. Wenn Sie required="false" hinzufügen, kann Ihr Spiel außerdem weiterhin auf Smartphones und Tablets ohne Maus installiert werden. Beispiel:
<manifest ...>
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
...
</manifest>
Die Produktionsversion von Google Play Games auf dem PC wechselt beim Start eines Spiels in den richtigen Modus. Wenn Sie die App im Entwickleremulator ausführen, müssen Sie mit der rechten Maustaste auf das Taskleistensymbol klicken, Entwickleroptionen und dann PC-Modus(KiwiMouse) auswählen, um rohe Mauseingaben zu erhalten.
Danach wird die Mausbewegung von View.onGenericMotionEvent mit der Quelle SOURCE_MOUSE gemeldet, was darauf hinweist, dass es sich um ein Mausereignis handelt.
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; });
Weitere Informationen zur Verarbeitung von Mauseingaben finden Sie in der ChromeOS-Dokumentation.
Mausbewegungen verarbeiten
Um Mausbewegungen zu erkennen, müssen Sie auf die Ereignisse ACTION_HOVER_ENTER, ACTION_HOVER_EXIT und ACTION_HOVER_MOVE warten.
Diese Funktion eignet sich am besten, um zu erkennen, wenn der Nutzer den Mauszeiger über Schaltflächen oder Objekte in einem Spiel bewegt. So können Sie z. B. eine Hinweisbox einblenden oder einen Mouseover-Status implementieren, um hervorzuheben, was ein Spieler gleich auswählen wird. Beispiel:
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; });
Umgang mit Maustasten
Auf PCs gibt es schon lange sowohl linke als auch rechte Maustasten, sodass interaktive Elemente sowohl primäre als auch sekundäre Aktionen haben. In einem Spiel sollten Aktionen wie das Tippen auf eine Schaltfläche am besten dem Linksklick zugewiesen werden, während Touch-and-Hold-Aktionen sich am natürlichsten mit dem Rechtsklick ausführen lassen. In Echtzeit-Strategiespielen können Sie auch mit der linken Maustaste auswählen und mit der rechten Maustaste verschieben. Bei Ego-Shootern wird das primäre und sekundäre Feuer möglicherweise dem Links- und Rechtsklick zugewiesen. Bei einem Infinite Runner wird möglicherweise mit der linken Maustaste gesprungen und mit der rechten Maustaste gesprintet. Wir haben keine Unterstützung für das Mittelklick-Ereignis hinzugefügt.
Verwenden Sie ACTION_DOWN und ACTION_UP, um Tastendrücke zu verarbeiten. Verwenden Sie dann getActionButton, um zu ermitteln, welche Taste die Aktion ausgelöst hat, oder getButtonState, um den Status aller Tasten abzurufen.
In diesem Beispiel wird ein Enum verwendet, um das Ergebnis von getActionButton darzustellen:
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; } } }
In diesem Beispiel wird die Aktion ähnlich wie bei den Hover-Ereignissen behandelt:
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; });
Scrollen mit dem Mausrad verarbeiten
Wir empfehlen, das Mausrad anstelle von Pinch-to-Zoom-Gesten oder Touch-and-Drag-Scrollbereichen in Ihrem Spiel zu verwenden.
Wenn Sie Werte des Scrollrads lesen möchten, müssen Sie auf das ACTION_SCROLL-Ereignis warten. Die Differenz seit dem letzten Frame kann mit getAxisValue abgerufen werden. Verwenden Sie dazu AXIS_VSCROLL für den vertikalen und AXIS_HSCROLL für den horizontalen Versatz. Beispiel:
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; });
Mauseingabe erfassen
Bei einigen Spielen muss der Mauszeiger vollständig gesteuert werden, z. B. bei Actionspielen in der ersten oder dritten Person, bei denen die Mausbewegung der Kamerabewegung zugeordnet wird. Rufen Sie View.requestPointerCapture() auf, um die Maus exklusiv zu steuern.
requestPointerCapture() funktioniert nur, wenn die Ansichtshierarchie, die Ihre Ansicht enthält, den Fokus hat. Aus diesem Grund können Sie die Zeigererfassung im onCreate-Callback nicht abrufen. Sie sollten entweder auf eine Spielerinteraktion warten, um den Mauszeiger zu erfassen, z. B. wenn der Spieler mit dem Hauptmenü interagiert, oder den onWindowFocusChanged-Callback verwenden. Beispiel:
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(); } }
Von requestPointerCapture() erfasste Ereignisse werden an die fokussierbare Ansicht gesendet, die OnCapturedPointerListener registriert hat. Beispiel:
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; });
Wenn Sie die exklusive Mauszeigererfassung aufheben möchten, z. B. damit Spieler mit einem Pausenmenü interagieren können, rufen Sie View.releasePointerCapture() auf.