Mauseingabe

In diesem Thema wird beschrieben, wie Sie die Mauseingabe für Google Play Games auf dem PC für Spiele implementieren, in 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 die Mauseingabe 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 zwar mit wenigen Änderungen funktionsfähig, aber PC-Spieler haben nicht das Gefühl, dass es sich um ein natives PC-Spiel handelt. Wir empfehlen daher, Folgendes zu implementieren:

  • Hover-Zustände für Kontextmenüs anstelle von Aktionen bei langem Drücken
  • Mit der rechten Maustaste können Sie alternative Aktionen aufrufen, die bei langem Drücken oder in einem Kontextmenü ausgeführt werden.
  • Mouselook für Actionspiele aus der ersten oder dritten Person 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 dein Spiel PC-Hardware verwendet und der Eingabeübersetzungsmodus deaktiviert ist. Wenn Sie required="false" hinzufügen, kann Ihr Spiel auch 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 den Entwickleremulator verwenden, müssen Sie mit der rechten Maustaste auf das Taskleistensymbol klicken, Entwickleroptionen und dann PC-Modus(KiwiMouse) auswählen, um rohe Mauseingaben zu erhalten.

Screenshot des im Kontextmenü ausgewählten „PC-Modus(KiwiMouse)“

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 auswählen möchte. 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 Aktionen, bei denen man den Finger auf dem Display hält, 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 ein Sprint ausgeführt. Wir haben keine Unterstützung für das Mittelklick-Ereignis hinzugefügt.

Verwende 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. Dabei steht 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 Ego- oder Third-Person-Actionspielen, bei denen die Mausbewegung der Kamerabewegung entspricht. Um die exklusive Steuerung der Maus zu übernehmen, rufen Sie View.requestPointerCapture() auf.

requestPointerCapture() funktioniert nur, wenn die Ansichtshierarchie, die Ihre Ansicht enthält, den Fokus hat. Aus diesem Grund können Sie in der onCreate-Rückruffunktion keine Zeigererfassung durchführen. 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();
    }
}

Ereignisse, die von requestPointerCapture() erfasst werden, 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.