Input del mouse

Questo argomento spiega come implementare l'input del mouse in Google Play Giochi su PC per i giochi in cui la modalità di immissione non offre un'esperienza ideale per i giocatori.

I giocatori su PC di solito hanno una tastiera e un mouse anziché un touchscreen, pertanto è importante valutare se il gioco supporta l'input del mouse. Per impostazione predefinita, Google Play Giochi su PC converte qualsiasi evento di clic con il tasto sinistro del mouse in un singolo evento di tocco virtuale. Questa modalità è nota come "modalità di traduzione dell'input".

Sebbene questa modalità renda il gioco funzionante con poche modifiche, non offre ai giocatori su PC un'esperienza nativa. A questo scopo, ti consigliamo di implementare quanto segue:

  • Stati del passaggio del mouse per i menu contestuali anziché le azioni di pressione e pressione
  • Fai clic con il tasto destro del mouse per azioni alternative eseguite in caso di pressione prolungata o in un menu contestuale
  • Cerca giochi d'azione in prima o terza persona invece di un evento di stampa e trascinamento

Per supportare i pattern UI comuni sui PC, devi disattivare la modalità di traduzione dell'input.

La gestione dell'immissione per Google Play Giochi su PC è identica a quella di ChromeOS. Le modifiche che supportano i PC migliorano anche il gioco per tutti i giocatori Android.

Disattiva la modalità di traduzione dell'input

Nel file AndroidManifest.xml, dichiara la funzionalità android.hardware.type.pc. Questo indica che il gioco utilizza l'hardware del PC e disabilita la modalità di traduzione input. Inoltre, l'aggiunta di required="false" consente di continuare a installare il gioco su telefoni e tablet senza mouse. Ecco alcuni esempi:

<manifest ...>
  <uses-feature
      android:name="android.hardware.type.pc"
      android:required="false" />
  ...
</manifest>

La versione di produzione di Google Play Giochi su PC passa alla modalità corretta all'avvio di un gioco. Quando utilizzi l'emulatore sviluppatore, devi fare clic con il tasto destro del mouse sull'icona della barra delle applicazioni, selezionare Opzioni sviluppatore e quindi Modalità PC(KiwiMouse) per ricevere input non elaborati del mouse.

Screenshot della &quot;modalità PC(KiwiMouse)&quot; selezionata nel menu contestuale

Dopo aver eseguito questa operazione, il movimento del mouse viene riportato da View.onGenericMotionEvent con l'origine SOURCE_MOUSE che indica che si tratta di un evento del 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;
});

Per maggiori dettagli sulla gestione dell'input del mouse, consulta la documentazione di ChromeOS.

Gestione dei movimenti del mouse

Per rilevare il movimento del mouse, ascolta gli eventi ACTION_HOVER_ENTER, ACTION_HOVER_EXIT e ACTION_HOVER_MOVE.

Questa funzionalità è utile per rilevare l'utente che passa il mouse sopra pulsanti o oggetti in un gioco, offrendoti la possibilità di visualizzare una finestra di suggerimenti o implementare uno stato mouseover per evidenziare ciò che un giocatore sta per selezionare. Ecco alcuni esempi:

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;
});

Gestione dei pulsanti del mouse

I PC utilizzano da tempo sia i pulsanti sinistro che destro del mouse, assegnando agli elementi interattivi azioni primarie e secondarie. In un gioco, le azioni di tocco come toccare un pulsante sono più adatte al clic con il tasto sinistro del mouse, dove le azioni di tocco e pressione risultano più naturali con il clic destro. Nei giochi di strategia in tempo reale potresti anche usare il clic con il tasto sinistro per selezionare e il clic con il tasto destro del mouse per spostarti. I tiratori in prima persona possono assegnare il fuoco principale e secondario a sinistra e al clic destro. Un runner infinito potrebbe usare il clic con il tasto sinistro per saltare e il clic con il tasto destro del mouse per passare al trattino. Non abbiamo aggiunto il supporto per l'evento del clic centrale.

Per gestire la pressione dei pulsanti, usa ACTION_DOWN e ACTION_UP. Quindi utilizza getActionButton per determinare quale pulsante ha attivato l'azione o getButtonState per visualizzare lo stato di tutti i pulsanti.

In questo esempio, viene utilizzata un'enumerazione per visualizzare il risultato di 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;
        }
    }
}

In questo esempio, l'azione viene gestita in modo simile agli eventi di passaggio del mouse:

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;
});

Gestire lo scorrimento con la rotellina del mouse

Ti consigliamo di utilizzare la rotellina di scorrimento del mouse anziché pizzicare per eseguire lo zoom dei gesti o toccare e trascinare aree di scorrimento nel gioco.

Per leggere i valori della rotellina di scorrimento, esamina l'evento ACTION_SCROLL. Il parametro delta poiché l'ultimo frame può essere recuperato utilizzando getAxisValue con AXIS_VSCROLL per l'offset verticale e AXIS_HSCROLL per l'offset orizzontale. Ecco alcuni esempi:

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;
});

Acquisisci input del mouse

Alcuni giochi devono avere il pieno controllo del cursore del mouse, come i giochi d'azione in prima o terza persona che mappano il movimento del mouse a quello della videocamera. Per assumere il controllo esclusivo del mouse, richiama View.requestPointerCapture().

requestPointerCapture() funziona solo quando lo stato attivo è impostato sulla gerarchia delle viste che contiene la vista. Per questo motivo, non puoi acquisire l'acquisizione del puntatore nel callback onCreate. Devi attendere che l'interazione del player acquisisca il puntatore del mouse, ad esempio durante l'interazione con il menu principale, oppure utilizzare il callback onWindowFocusChanged. Ecco alcuni esempi:

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();
    }
}

Gli eventi acquisiti da requestPointerCapture() vengono inviati alla visualizzazione attivabile che ha registrato OnCapturedPointerListener. Ecco alcuni esempi:

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;
});

Per rilasciare l'acquisizione esclusiva del mouse, ad esempio per consentire ai giocatori di interagire con un menu di pausa, richiama View.releasePointerCapture().