Saisies à la souris

Cet article explique comment implémenter la saisie à la souris dans Google Play Jeux sur PC pour les jeux dans lesquels le mode de conversion des entrées n'offre pas une expérience satisfaisante.

Les joueurs sur PC disposent généralement d'un clavier et d'une souris plutôt que d'un écran tactile. Il est donc important de déterminer si votre jeu est compatible avec la saisie à la souris. Par défaut, Google Play Jeux sur PC convertit n'importe quel événement de clic gauche en événement tactile virtuel unique. C'est ce que nous appelons le "mode de conversion des entrées".

Bien que ce mode rende votre jeu fonctionnel avec peu de modifications, il n'offre pas une expérience intuitive aux joueurs sur PC. Nous vous recommandons donc d'implémenter les éléments suivants :

  • État de pointage avec la souris pour les menus contextuels plutôt que les actions d'appui de manière prolongée
  • Possibilité d'effectuer un clic droit pour afficher d'autres actions qui se produisent lorsqu'on appuie de manière prolongée ou dans un menu contextuel
  • Contrôle direct de la caméra à la souris dans les jeux d'action à la première ou à la troisième personne (plutôt que d'utiliser des événements appuyer-déplacer)

Pour prendre en charge les modèles d'interface utilisateur courants sur les PC, vous devez désactiver le mode de conversion des entrées.

La gestion des entrées pour Google Play Jeux sur PC est identique à celle de ChromeOS. Les modifications apportées pour les PC améliorent votre jeu pour tous les joueurs Android.

Désactiver le mode de conversion des entrées

Dans votre fichier AndroidManifest.xml, déclarez la fonctionnalité android.hardware.type.pc. Cela indique que votre jeu utilise du matériel PC et désactive le mode de conversion des entrées. De plus, l'ajout de required="false" permet de s'assurer que votre jeu peut toujours être installé sur des appareils sans souris, comme les téléphones et les tablettes. Par exemple :

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

La version de production de Google Play Jeux sur PC passe au mode approprié au lancement du jeu. Lorsque vous exécutez l'émulateur pour développeur, effectuez un clic droit sur l'icône de la barre des tâches, sélectionnez Developer Options (Options pour les développeurs), puis PC mode(KiwiMouse) (Mode PC (KiwiMouse)) pour recevoir les données brutes de la souris.

Capture d&#39;écran du mode PC (KiwiMouse) sélectionné dans le menu contextuel

Après cela, le mouvement de la souris est signalé par View.onGenericMotionEvent, la source SOURCE_MOUSE indiquant qu'il s'agit d'un événement de souris.

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

Pour en savoir plus sur la gestion des saisies à la souris, consultez la documentation Chrome OS.

Gérer les mouvements de la souris

Pour détecter les mouvements de souris, écoutez les événements ACTION_HOVER_ENTER, ACTION_HOVER_EXIT et ACTION_HOVER_MOVE.

Ces événements sont particulièrement utiles pour détecter si l'utilisateur pointe la souris sur des boutons ou des objets d'un jeu, ce qui vous permet d'afficher un indicateur ou d'implémenter un état de pointage avec la souris pour mettre en évidence les éléments qu'un joueur s'apprête à sélectionner. Par exemple :

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

Gérer les boutons de la souris

Les PC disposent depuis longtemps de souris à deux boutons, gauche et droit, qui permettent d'effectuer, respectivement, une action primaire et secondaire sur les éléments interactifs. Dans un jeu, il est plus naturel d'utiliser le bouton gauche pour les clics simples, tandis que le clic droit se prête mieux aux actions avec appui prolongé. Dans les jeux de stratégie en temps réel, vous pouvez associer le clic gauche à l'action d'effectuer une sélection et le clic droit aux déplacements. Les jeux de tir à la première personne peuvent attribuer des modes de tir principal et secondaire, respectivement, aux clics gauche et droit. Un jeu de course infini peut utiliser le clic gauche pour les sauts et le droit pour les accélérations. L'événement de clic central n'est pas pris en charge.

Pour gérer les boutons de souris, utilisez ACTION_DOWN et ACTION_UP. Utilisez ensuite getActionButton pour déterminer quel bouton a déclenché l'action ou getButtonState pour obtenir l'état de tous les boutons.

Dans cet exemple, une énumération permet d'afficher le résultat 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;
        }
    }
}

Dans cet exemple, l'action est gérée de la même manière que les événements de pointage :

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

Gérer le défilement à l'aide de la molette de la souris

Nous vous conseillons d'utiliser la molette de la souris pour les gestes de type "pincer pour zoomer" ou "appuyer et faire glisser" pour les zones de défilement dans votre jeu.

Pour lire les valeurs de la molette, écoutez l'événement ACTION_SCROLL. Le delta depuis la dernière image peut être obtenu à l'aide de getAxisValue avec AXIS_VSCROLL pour le déplacement vertical et AXIS_HSCROLL pour le déplacement horizontal. Par exemple :

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

Capturer la saisie à la souris

Certains jeux doivent entièrement contrôler le curseur de la souris. C'est le cas des jeux d'action à la première ou à la troisième personne, qui mappent le mouvement de la caméra sur le mouvement de la souris. Pour contrôler totalement la souris, appelez View.requestPointerCapture().

requestPointerCapture() ne fonctionne que lorsque la hiérarchie des vues qui contient votre vue est sélectionnée. Pour cette raison, vous ne pouvez pas acquérir la capture du pointeur dans le rappel onCreate. Attendez que l'interaction du joueur capture le pointeur de la souris, par exemple pour interagir avec le menu principal, ou utilisez le rappel onWindowFocusChanged. Exemple :

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

Les événements capturés par requestPointerCapture() sont envoyés à la vue sélectionnable qui a enregistré OnCapturedPointerListener. Par exemple :

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

Pour suspendre la capture exclusive par la souris, par exemple pour permettre aux joueurs d'interagir avec un menu de mise en pause, appelez View.releasePointerCapture().