Input del mouse

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

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

Anche se questa modalità rende il gioco funzionale con poche modifiche, non offre ai giocatori PC un'esperienza nativa. Per questo, ti consigliamo di implementare quanto segue:

  • Stati di passaggio del mouse per i menu contestuali anziché azioni di pressione prolungata
  • Fai clic con il tasto destro del mouse per azioni alternative che si verificano con una pressione prolungata o in un menu contestuale
  • Mouselook per giochi d'azione in prima o terza persona anziché un evento di trascinamento con pressione

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

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

Disattiva modalità di traduzione di input

Nel file AndroidManifest.xml, dichiara la funzionalità android.hardware.type.pc. Questo indica che il gioco utilizza hardware del PC e disattiva la modalità di traduzione di input. Inoltre, l'aggiunta di required="false" contribuisce a garantire che il tuo gioco possa essere installato su smartphone e tablet anche senza mouse. Ad esempio:

<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 al momento del lancio di un gioco. Quando esegui l'emulatore per sviluppatori, devi fare clic con il tasto destro del mouse sull'icona della barra delle app, selezionare Opzioni sviluppatore e poi Modalità PC(KiwiMouse) per ricevere l'input del mouse non elaborato.

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 informazioni dettagliate sulla gestione dell'input del mouse, consulta la documentazione di ChromeOS.

Gestione del movimento del mouse

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

Questo evento è ideale per rilevare il passaggio del mouse dell'utente sopra i pulsanti o gli oggetti in un gioco, dandoti la possibilità di visualizzare una finestra di suggerimento o implementare uno stato mouseover per evidenziare ciò che un giocatore sta per selezionare. Ad esempio:

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 tasti del mouse

I PC dispongono da tempo dei pulsanti sinistro e destro del mouse, che offrono elementi interattivi con azioni sia principali che secondarie. In un gioco, le azioni di tocco, come toccare un pulsante, sono mappate meglio al clic con il tasto sinistro, mentre le azioni di tocco e pressione sono più naturali con il clic con il tasto destro. Nei giochi di strategia in tempo reale puoi anche fare clic con il tasto sinistro del mouse per selezionare e con il tasto destro per spostarti. Gli sparatutto in prima persona potrebbero assegnare fuoco primario e secondario ai clic sinistro e destro. Un corridore infinito potrebbe usare il clic con il tasto sinistro per saltare e il clic con il tasto destro del mouse per sfrecciare. Non abbiamo aggiunto il supporto per l'evento di clic centrale.

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

In questo esempio, viene utilizzato un enum 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 della rotellina del mouse

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

Per leggere i valori della rotellina di scorrimento, esamina l'evento ACTION_SCROLL. Il delta dall'ultimo frame può essere recuperato utilizzando getAxisValue con AXIS_VSCROLL per l'offset verticale e AXIS_HSCROLL per l'offset orizzontale. Ad esempio:

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 l'input del mouse

Alcuni giochi devono assumere il controllo completo del cursore del mouse, ad esempio i giochi di azione in prima o terza persona che mappano il movimento del mouse al movimento della fotocamera. Per assumere il controllo esclusivo del mouse, richiama View.requestPointerCapture().

requestPointerCapture() funziona solo quando la gerarchia delle visualizzazioni contenente la tua visualizzazione ha il focus. Per questo motivo, non puoi acquisire il rilevamento del cursore nel callbackonCreate. Devi attendere l'interazione del player per acquisire il cursore del mouse, ad esempio quando interagisci con il menu principale, oppure utilizzare il callback onWindowFocusChanged. Ad esempio:

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 vista attivabile che ha registrato OnCapturedPointerListener. Ad esempio:

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 la cattura esclusiva del mouse, ad esempio per consentire ai giocatori di interagire con un menu di pausa, richiama View.releasePointerCapture().