Este tópico aborda como implementar a entrada do mouse no Google Play Games no PC para jogos em que o modo de conversão de entrada não oferece aos uma experiência ideal aos jogadores.
No PC, normalmente há um teclado e um mouse em vez de uma tela touchscreen, o que faz com que seja importante considerar se o jogo acomoda a entrada do mouse. Por padrão, o Google Play Games no PC converte qualquer evento de clique com o botão esquerdo do mouse em um único evento de toque virtual. Isso é conhecido como "modo de conversão de entrada".
Embora esse modo deixe seu jogo funcional com poucas mudanças, ele não oferece aos jogadores de PC uma experiência nativa. Para isso, recomendamos que você implemente o seguinte:
- Estados de passar o cursor sobre menus de contexto em vez de ações de tocar e pressionar
- O ato de clicar com o botão direito do mouse para ações alternativas que ocorrem ao tocar e manter pressionado ou em um menu de contexto
- Controle de visão do mouse para jogos de ação em primeira ou terceira pessoa, em vez de um evento de pressionar e arrastar
Para oferecer suporte a padrões de interface comuns em PCs, desative o modo de conversão de entrada.
O processamento de entrada do Google Play Games no PC é idêntico ao do ChromeOS. As mudanças que podem ser feitas em PCs também melhoram o jogo para o Android.
Desativar o modo de conversão de entrada
No arquivo AndroidManifest.xml
,
declare o
recurso android.hardware.type.pc
.
Isso indica que o jogo usa o hardware de PC e desativa o modo de conversão
de entrada. Além disso, a adição de required="false"
ajuda a garantir que o jogo ainda
possa ser instalado em smartphones e tablets sem um mouse. Exemplos:
<manifest ...>
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
...
</manifest>
A versão de produção do Google Play Games no PC alterna para o modo correto quando um jogo é iniciado. Ao executar no emulador do desenvolvedor, você precisa clicar com o botão direito do mouse no ícone da barra de tarefas, selecionar Developer Options e PC mode(KiwiMouse) para receber entrada bruta do mouse.
Depois disso, o movimento do mouse será informado por View.onGenericMotionEvent com a origem SOURCE_MOUSE
,
indicando que esse é um evento de 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; });
Para ver detalhes sobre como lidar com a entrada do mouse, consulte a documentação do ChromeOS.
Como processar o movimento do mouse
Para identificar o movimento do mouse, é necessário detectar os eventos ACTION_HOVER_ENTER
, ACTION_HOVER_EXIT
e
ACTION_HOVER_MOVE
.
Isso ajuda a identificar quando o usuário passa o cursor sobre botões ou objetos em um jogo, dando a você a chance de mostrar uma caixa de dicas ou implementar um estado de mouseover para destacar o que o jogador está prestes a selecionar. Exemplos:
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; });
Como processar os botões do mouse
Os PCs têm botões os esquerdo e direito no mouse há muito tempo, oferecendo elementos interativos para ações primárias e secundárias. Em um jogo, ações de toque (como tocar em um botão) são associadas ao clique com o botão esquerdo do mouse, enquanto as ações de tocar e manter pressionado ficam mais naturais com o botão direito. Em jogos de estratégia em tempo real, você também pode usar o clique com o botão esquerdo para selecionar e com o botão direito para mover. Os jogos de tiro em primeira pessoa podem atribuir as ações de tiro principal e secundária ao clique com o botão esquerdo e direito, respectivamente. Um jogo de corrida interminável pode usar o clique com o botão esquerdo para pular e com o botão direito para correr mais rápido. Não adicionamos suporte ao evento de clique com a roda do mouse.
Para processar os pressionamentos de botão, use ACTION_DOWN
e ACTION_UP
. Depois, use
getActionButton
para determinar qual botão acionou a ação ou
getButtonState
para saber o estado de todos os botões.
Neste exemplo, uma enumeração é usada para ajudar a mostrar o resultado de
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; } } }
Neste exemplo, a ação é processada de forma semelhante aos eventos de passar o cursor:
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; });
Processar a rolagem da roda do mouse
Recomendamos que você use a roda de rolagem do mouse em vez do gesto de pinça para aplicar zoom ou tocar e arrastar áreas de rolagem no jogo.
Para ler os valores da roda de rolagem, detecte o evento ACTION_SCROLL
. O delta
desde o último frame pode ser extraído usando getAxisValue
com AXIS_VSCROLL
para deslocamento vertical e AXIS_HSCROLL
para deslocamento horizontal. Exemplos:
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; });
Capturar a entrada do mouse
Alguns jogos precisam ter controle total do cursor do mouse, como jogos de ação em primeira ou terceira
pessoa que associam o movimento do mouse ao da câmera. Para ter
o controle exclusivo do mouse, invoque View.requestPointerCapture()
.
A função requestPointerCapture()
só funciona quando a hierarquia de visualização que contém sua
visualização está em foco. Por esse motivo, não é possível conseguir a captura do ponteiro no
callback onCreate
. Você precisa esperar a interação do jogador para capturar
o ponteiro do mouse, como ao interagir com o menu principal, ou usar o
callback
onWindowFocusChanged
. Exemplos:
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(); } }
Os eventos capturados por requestPointerCapture()
são enviados para a visualização focalizável que registrou
OnCapturedPointerListener
. Exemplos:
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; });
Para liberar a captura exclusiva do mouse, por exemplo, para permitir que os jogadores
interajam com um menu de pausa, invoque View.releasePointerCapture()
.