Premiers pas avec le SDK Input

Ce document décrit comment configurer et afficher le SDK Input dans les jeux compatibles avec Google Play Jeux sur PC. Les tâches, telles que l'ajout du SDK à votre jeu et la génération d'un mappage des entrées, qui contient les différentes actions du jeu correspondant aux entrées utilisateur définies.

Avant de commencer

Avant d'ajouter le SDK Input à votre jeu, vous devez prendre en charge l'entrée au clavier et à la souris à l'aide du système d'entrée de votre moteur de jeu.

Le SDK Input fournit des informations à Google Play Jeux sur PC concernant les commandes que votre jeu utilise, afin qu'elles soient affichées à l'utilisateur. Il peut aussi, si vous le souhaitez, autoriser les utilisateurs à remapper leur clavier.

Chaque commande est une InputAction (par exemple "S" pour "Sauter") et vous organisez vos InputActions en InputGroups. Un InputGroup peut représenter un mode différent dans votre jeu, par exemple "Conduite", "Marche" ou "Menu principal". Vous pouvez aussi utiliser des InputContexts pour indiquer quels groupes sont actifs à différents stades du jeu.

Vous pouvez activer la gestion automatique du remappage du clavier, mais si vous préférez fournir votre propre interface de remappage des commandes, vous pouvez désactiver le remappage du SDK Input.

Le diagramme séquentiel suivant décrit le fonctionnement de l'API du SDK Input.

Diagramme séquentiel montrant l'implémentation d'un jeu qui appelle l'API du SDK Input, ainsi que ses interactions avec l'appareil Android.

Lorsque votre jeu implémente le SDK Input, vos commandes s'affichent dans la superposition Google Play Jeux sur PC.

La superposition Google Play Jeux sur PC

La superposition Google Play Jeux sur PC (la "superposition") affiche les commandes définies par votre jeu. Les utilisateurs peuvent accéder à la superposition à tout moment en appuyant sur Maj + Tab.

La superposition Google Play Jeux sur PC.

Bonnes pratiques pour la conception d'associations de touches

Lors de la conception d'associations de touches, tenez compte des bonnes pratiques suivantes :

  • Regroupez vos InputActions en InputGroups reliés de façon logique afin d'améliorer la navigation et la visibilité des commandes lors du jeu.
  • Attribuez chaque InputGroup à un seul InputContext au maximum. Une InputMap affinée offre une meilleure expérience pour naviguer dans les commandes dans la superposition.
  • Créez un InputContext pour chaque type de scène différent de votre jeu. Généralement, vous pouvez utiliser un seul InputContext pour toutes vos scènes de menu. Utilisez des InputContexts différents pour tout mini-jeu présent dans votre jeu ou pour des commandes alternatives au sein d'une même scène.
  • Si deux actions sont conçues pour utiliser la même touche avec le même InputContext, servez-vous de la chaîne de libellé pour le préciser, par exemple "Interagir/Tirer".
  • Si deux touches sont conçues pour être associées à la même InputAction, utilisez deux InputActions différentes qui effectuent la même action dans votre jeu. Vous pouvez utiliser la même chaîne de libellé pour les deux InputActions, mais leur identifiant doit être différent.
  • Si une touche de modification est appliquée à un ensemble de touches, envisagez de disposer d'une seule InputAction avec la touche de modification au lieu de plusieurs InputActions associées à une même touche de modification (par exemple : utilisez Maj et W, A, S, D au lieu de Maj + W, Maj + A, Maj + S, MAj + D).
  • Le remappage des entrées est automatiquement désactivé lorsque l'utilisateur écrit dans des champs de texte. Suivez les bonnes pratiques d'implémentation des champs de texte Android pour vous assurer qu'Android est capable de détecter les champs de texte dans votre jeu et éviter que les touches remappées interfèrent avec ces champs. Si votre jeu utilise des champs de texte non conventionnels, vous pouvez désactiver manuellement le remappage en utilisant setInputContext() avec un InputContext contenant une liste d'InputGroups vide.
  • Si votre jeu prend en charge le remappage, tenez compte du fait que la modification de vos associations de touches est une opération délicate qui peut entrer en conflit avec les associations de touches enregistrées par l'utilisateur. Dans la mesure du possible, évitez de modifier l'identifiant de commandes existantes.

La fonctionnalité de remappage

Google Play Jeux sur PC permet de remapper les commandes du clavier en fonction des associations de touches fournies par votre jeu à l'aide du SDK Input. Cette fonctionnalité est optionnelle et peut être totalement désactivée. Par exemple, vous pouvez fournir votre propre interface de remappage de clavier. Pour désactiver le remappage pour votre jeu, il vous suffit de désactiver l'option de remappage pour votre InputMap (consultez Concevoir une InputMap pour en savoir plus).

Pour accéder à cette fonctionnalité, les utilisateurs doivent ouvrir la superposition, puis cliquer sur l'action qu'ils souhaitent remapper. Après chaque événement de remappage, Google Play Jeux sur PC mappe chaque commande remappée par l'utilisateur aux commandes par défaut que votre jeu s'attend à recevoir, sans signalement à votre jeu du remappage effectué par le joueur. Si vous le souhaitez, vous pouvez modifier les éléments permettant d'afficher les commandes du clavier dans votre jeu en ajoutant un rappel pour les événements de remappage.

Tentative de remappage de la touche

Google Play Jeux sur PC stocke localement les commandes remappées pour chaque utilisateur, ce qui permet de les conserver d'une session de jeu à une autre. Ces informations sont stockées sur le disque uniquement sur PC et n'ont aucun effet sur l'expérience mobile. Les données de commande sont supprimées lorsque l'utilisateur désinstalle ou réinstalle Google Play Jeux sur PC. Ces données ne sont pas conservées d'un PC à l'autre.

Pour prendre en charge la fonctionnalité de remappage dans votre jeu, évitez les restrictions suivantes :

Restrictions de remappage

Les fonctionnalités de remappage peuvent être désactivées dans votre jeu si l'un des cas suivants s'applique pour les associations de touches :

  • Des InputActions qui utilisent plusieurs touches ne sont pas composées d'une touche de modification et d'une touche de non-modification. Par exemple, Maj + A est valide, mais A + B, Ctrl + Alt ou Maj + A + Tab ne l'est pas.
  • L'InputMap contient des InputActions, des InputGroups ou des InputContexts avec des identifiants uniques répétés.

Limitations du remappage

Lors de la conception d'associations de touches pour le remappage, tenez compte des limitations suivantes :

  • Le remappage à des combinaisons de touches n'est pas pris en charge. Par exemple, les utilisateurs ne peuvent pas remapper Maj + A à Ctrl + B ni A à Maj + A.
  • Le remappage n'est pas pris en charge pour les InputActions avec les boutons de la souris. Par exemple, la combinaison Maj + Clic droit ne peut pas être remappée.

Tester le remappage des touches sur l'émulateur Google Play Jeux sur PC

Vous pouvez activer la fonctionnalité de remappage à tout moment dans l'émulateur Google Play Jeux sur PC en émettant la commande adb suivante :

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

La superposition est modifiée comme dans l'exemple suivant :

Superposition avec remappage des touches activé.

Ajouter le SDK

Installez le SDK Input conformément à votre plate-forme de développement.

Java et Kotlin

Obtenez le SDK Input pour Java ou Kotlin en ajoutant une dépendance à votre fichier build.gradle au niveau du module :

dependencies {
  implementation 'com.google.android.libraries.play.games:inputmapping:1.1.1-beta'
  ...
}

Unity

Le SDK Input est un package Unity standard avec plusieurs dépendances.

L'installation du package avec toutes les dépendances est requise. Il existe plusieurs façons d'installer les packages.

Installer le fichier .unitypackage

Téléchargez le fichier unitypackage du SDK Input avec toutes ses dépendances. Vous pouvez installer le fichier .unitypackage en sélectionnant Assets > Import package > Custom Package (Éléments > Importer un package > Package personnalisé) et en trouvant le fichier que vous avez téléchargé.

Installer à l'aide d'UPM

Vous pouvez aussi installer le package à l'aide du gestionnaire de paquets Unity en téléchargeant le fichier .tgz et en installant ses dépendances:

Installer à l'aide d'OpenUPM

Vous pouvez installer le package à l'aide d'OpenUPM.

$ openupm add com.google.android.libraries.play.games.inputmapping

Exemples de jeux

Pour obtenir des exemples d'intégration avec le SDK Input, consultez la page Tunnel AGDK pour les jeux Kotlin ou Java et Trivial Kart pour les jeux Unity.

Générer vos associations de clés

Enregistrez vos associations de touches en créant une InputMap et en la retournant avec un InputMappingProvider. L'exemple suivant illustre un InputMappingProvider :

Kotlin

class InputSDKProvider : InputMappingProvider {
  override fun onProvideInputMap(): InputMap {
    TODO("Not yet implemented")
  }
}

Java

public class InputSDKProvider implements InputMappingProvider {
    private static final String INPUTMAP_VERSION = "1.0.0";

    @Override
    @NonNull
    public InputMap onProvideInputMap() {
        // TODO: return an InputMap
    }
}

C#

#if PLAY_GAMES_PC
using Java.Lang;
using Java.Util;
using Google.Android.Libraries.Play.Games.Inputmapping;
using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel;

public class InputSDKProvider : InputMappingProviderCallbackHelper
{
    public static readonly string INPUT_MAP_VERSION = "1.0.0";

    public override InputMap OnProvideInputMap()
    {
        // TODO: return an InputMap
    }
}
#endif

Définir vos actions d'entrée

La classe InputAction permet de mapper une touche ou une combinaison de touches pour l'associer à une action de jeu. Les InputActions doivent avoir un identifiant unique entre les différents InputActions.

Si vous prenez en charge le remappage, vous pouvez définir quelles InputActions peuvent être remappées. Si votre jeu ne prend pas en charge le remappage, nous vous invitons à désactiver cette option pour toutes vos InputActions, mais le SDK Input est suffisamment intelligent pour désactiver le remappage si vous ne le prenez pas en charge dans votre InputMap.

L'exemple suivant mappe la touche Espace à l'action Drive (Conduite) :

Kotlin

companion object {
  private val driveInputAction = InputAction.create(
    "Drive",
    InputActionsIds.DRIVE.ordinal.toLong(),
    InputControls.create(listOf(KeyEvent.KEYCODE_SPACE), emptyList()),
    InputEnums.REMAP_OPTION_ENABLED)
}

Java

private static final InputAction driveInputAction = InputAction.create(
    "Drive",
    InputEventIds.DRIVE.ordinal(),
    InputControls.create(
            Collections.singletonList(KeyEvent.KEYCODE_SPACE),
            Collections.emptyList()),
    InputEnums.REMAP_OPTION_ENABLED
);

C#

private static readonly InputAction driveInputAction = InputAction.Create(
    "Drive",
    (long)InputEventIds.DRIVE,
    InputControls.Create(
        new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(),
        new ArrayList<Integer>()),
    InputEnums.REMAP_OPTION_ENABLED
);

Une InputAction à une seule touche s&#39;affiche dans la superposition.

Les actions peuvent également être déclenchées par des entrées de la souris. L'exemple suivant associe le clic gauche à l'action Move (Déplacement) :

Kotlin

companion object {
  private val mouseInputAction = InputAction.create(
    "Move",
    InputActionsIds.MOUSE_MOVEMENT.ordinal.toLong(),
    InputControls.create(emptyList(), listOf(InputControls.MOUSE_LEFT_CLICK)),
    InputEnums.REMAP_OPTION_DISABLED)
}

Java

private static final InputAction mouseInputAction = InputAction.create(
    "Move",
    InputActionsIds.MOUSE_MOVEMENT.ordinal(),
    InputControls.create(
            Collections.emptyList(),
            Collections.singletonList(InputControls.MOUSE_LEFT_CLICK)
    ),
    InputEnums.REMAP_OPTION_DISABLED
);

C#

private static readonly InputAction mouseInputAction = InputAction.Create(
    "Move",
    (long)InputEventIds.MOUSE_MOVEMENT,
    InputControls.Create(
        new ArrayList<Integer>(),
        new[] { new Integer((int)PlayMouseAction.MouseLeftClick) }.ToJavaList()
    ),
    InputEnums.REMAP_OPTION_DISABLED
);

Un InputAction à la souris s&#39;affiche dans la superposition.

Des combinaisons de touches peuvent être spécifiées par l'envoi de plusieurs codes de touche à l'élément InputAction. Dans cet exemple, la combinaison Espace + Maj est mappée à l'action Turbo, qui fonctionne même lorsque la touche Espace est mappée à l'action Drive (Conduite).

Kotlin

companion object {
  private val turboInputAction = InputAction.create(
    "Turbo",
    InputActionsIds.TURBO.ordinal.toLong(),
    InputControls.create(
      listOf(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SPACE),
      emptyList()),
    InputEnums.REMAP_OPTION_ENABLED)
}

Java

private static final InputAction turboInputAction = InputAction.create(
    "Turbo",
    InputActionsIds.TURBO.ordinal(),
    InputControls.create(
            Arrays.asList(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SPACE),
            Collections.emptyList()
    ),
    InputEnums.REMAP_OPTION_ENABLED
);

C#

private static readonly InputAction turboInputAction = InputAction.Create(
    "Turbo",
    (long)InputEventIds.TURBO,
    InputControls.Create(
        new[]
        {
            new Integer(AndroidKeyCode.KEYCODE_SHIFT_LEFT),
            new Integer(AndroidKeyCode.KEYCODE_SPACE)
        }.ToJavaList(),
        new ArrayList<Integer>()),
    InputEnums.REMAP_OPTION_ENABLED
);

Une InputAction à plusieurs touches s&#39;affiche dans la superposition.

Le SDK Input vous permet de combiner les boutons de la souris et les touches pour une même action. Dans l'exemple ci-dessous, les touches Maj et Clic droit permettent d'ajouter une étape dans cet exemple de jeu :

Kotlin

companion object {
  private val addWaypointInputAction = InputAction.create(
    "Add waypoint",
    InputActionsIds.ADD_WAYPOINT.ordinal.toLong(),
    InputControls.create(
      listOf(KeyEvent.KeyEvent.KEYCODE_TAB),
      listOf(InputControls.MOUSE_RIGHT_CLICK)),
    InputEnums.REMAP_OPTION_DISABLED)
}

Java

private static final InputAction addWaypointInputAction = InputAction.create(
    "Add waypoint",
    InputActionsIds.ADD_WAYPOINT.ordinal(),
    InputControls.create(
            Collections.singletonList(KeyEvent.KEYCODE_TAB),
            Collections.singletonList(InputControls.MOUSE_RIGHT_CLICK)
    ),
    InputEnums.REMAP_OPTION_DISABLED
);

C#

private static readonly InputAction addWaypointInputAction = InputAction.Create(
    "Add waypoint",
    (long)InputEventIds.ADD_WAYPOINT,
    InputControls.Create(
        new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(),
        new[] { new Integer((int)PlayMouseAction.MouseRightClick) }.ToJavaList()
    ),
    InputEnums.REMAP_OPTION_DISABLED
);

L&#39;InputAction associant une touche et une entrée à la souris s&#39;affiche dans la superposition.

L'élément InputAction possède les champs suivants :

  • ActionLabel : la chaîne affichée dans l'interface utilisateur pour représenter cette action. La localisation n'est pas effectuée de façon automatique, donc effectuez toute localisation à l'avance.
  • InputControls : définit les commandes d'entrée utilisées par cette action. Des symboles correspondants s'affichent dans la superposition.
  • InputActionId : objet InputIdentifier qui stocke le numéro d'identifiant et la version de l'élément InputAction (consultez la section Suivi des identifiants de touches pour en savoir plus).
  • InputRemappingOption : InputEnums.REMAP_OPTION_ENABLED ou InputEnums.REMAP_OPTION_DISABLED. Définit si l'action peut être remappée. Si votre jeu ne prend pas en charge le remappage, vous pouvez ignorer ce champ ou le définir simplement sur désactivé.
  • RemappedInputControls : objet InputControls en lecture seule permettant de lire la touche remappée définie par l'utilisateur lors des événements de remappage (utilisé pour être averti lors des événements de remappage).

InputControls représente les entrées associées à une action et contient les champs suivants :

  • AndroidKeycodes : liste d'entiers représentant les entrées au clavier associées à une action. Ces éléments sont définis dans la classe KeyEvent ou dans la classe AndroidKeycode pour Unity.
  • MouseActions : liste de valeurs MouseAction représentant les saisies à la souris associées à cette action.

Définir vos groupes d'entrées

Les éléments InputActions dont les actions sont liées de façon logique sont regroupés à l'aide d'InputGroups afin d'améliorer la navigation et la visibilité des commandes dans la superposition. Chaque ID d'InputGroup doit être unique parmi tous les InputGroups de votre jeu.

En organisant vos actions d'entrées en groupes, vous aidez le joueur à identifier plus facilement l'association de touche qui correspond à son contexte actuel.

Si vous prenez en charge le remappage, vous pouvez définir quels InputGroups peuvent être remappés. Si votre jeu ne prend pas en charge le remappage, nous vous invitons à désactiver cette option pour toutes vos InputGroups, mais le SDK Input est suffisamment intelligent pour désactiver le remappage si vous ne le prenez pas en charge dans votre InputMap.

Kotlin

companion object {
  private val menuInputGroup = InputGroup.create(
    "Menu keys",
    listOf(
      navigateUpInputAction,
      navigateLeftInputAction,
      navigateDownInputAction,
      navigateRightInputAction,
      openMenuInputAction,
      returnMenuInputAction),
    InputGroupsIds.MENU_ACTION_KEYS.ordinal.toLong(),
    InputEnums.REMAP_OPTION_ENABLED
  )
}

Java

private static final InputGroup menuInputGroup = InputGroup.create(
    "Menu keys",
    Arrays.asList(
           navigateUpInputAction,
           navigateLeftInputAction,
           navigateDownInputAction,
           navigateRightInputAction,
           openMenuInputAction,
           returnMenuInputAction),
    InputGroupsIds.MENU_ACTION_KEYS.ordinal(),
    REMAP_OPTION_ENABLED
);

C#

private static readonly InputGroup menuInputGroup = InputGroup.Create(
    "Menu keys",
    new[]
    {
        navigateUpInputAction,
        navigateLeftInputAction,
        navigateDownInputAction,
        navigateRightInputAction,
        openMenuInputAction,
        returnMenuInputAction,
    }.ToJavaList(),
    (long)InputGroupsIds.MENU_ACTION_KEYS,
    InputEnums.REMAP_OPTION_ENABLED
);

L'exemple suivant affiche les groupes d'entrée Road controls (Commandes de conduite) et Menu controls (Commandes de menu) dans la superposition :

La superposition affiche une InputMap qui contient les groupes d&#39;entrée &quot;Road controls&quot; (Commandes de conduite) et &quot;Menu controls&quot; (Commandes de menu).

InputGroup comporte les champs suivants :

  • GroupLabel : chaîne à afficher dans la superposition et qui permet de regrouper un ensemble d'actions de façon logique. Cette chaîne n'est pas localisée automatiquement.
  • InputActions : liste des objets InputAction que vous avez définis dans l'étape précédente. Toutes ces actions s'affichent de façon visuelle sous l'en-tête de groupe.
  • InputGroupId : objet InputIdentifier qui stocke le numéro d'identifiant et la version de l'InputGroup. Pour en savoir plus, consultez la section Suivi des identifiants de touches.
  • InputRemappingOption : InputEnums.REMAP_OPTION_ENABLED ou InputEnums.REMAP_OPTION_DISABLED. Si cette option est désactivée, tous les objets InputAction appartenant à ce groupe verront leur remappage désactivé, même si leur option individuelle de remappage est activée. Si cette option est activée, toutes les actions appartenant à ce groupe peuvent être remappées, sauf si leur option individuelle de remappage est désactivée.

Définir vos contextes d'entrée

InputContexts permet à votre jeu d'utiliser un ensemble de commandes au clavier distinct pour différentes scènes de votre jeu. Par exemple :

  • Vous pouvez spécifier des ensembles d'entrées distincts pour naviguer dans le menu et pour vous déplacer dans le jeu.
  • Vous pouvez spécifier différents ensembles d'entrées en fonction du mode de locomotion dans votre jeu (conduite ou marche, par exemple).
  • Vous pouvez spécifier des ensembles d'entrées distincts en fonction de l'état actuel de votre jeu à un moment donné, par exemple lorsque vous naviguez sur une carte ou lorsque vous jouez à un niveau en particulier.

Lors de l'utilisation d'InputContexts, la superposition affiche le groupe correspondant au contexte en cours en premier. Pour activer ce comportement, appelez setInputContext() pour définir le contexte chaque fois que votre jeu entre dans une scène différente. L'image suivante illustre ce comportement dans la scène de conduite. Le groupe Road controls (Commandes de conduite) s'affiche en haut de la superposition. Lorsque vous ouvrez le menu de boutique, les actions "Menu controls" (Commandes de menu) s'affichent en haut de la superposition.

Groupes de tri InputContexts dans la superposition.

Ces modifications de la superposition sont obtenues en définissant un InputContext à différents endroits de votre jeu. Pour ce faire, procédez comme suit :

  1. Regroupez vos InputActions dont les actions sont liées de façon logique à l'aide d'InputGroups.
  2. Affectez ces InputGroups à un InputContext correspondant aux différentes parties de votre jeu.

Les InputGroups qui font partie du même InputContext ne peuvent pas avoir d'InputActions en conflit pour lesquelles la même touche est utilisée. Il est recommandé d'attribuer chaque InputGroup à un InputContext unique.

L'exemple de code suivant illustre la logique de l'élément InputContext :

Kotlin

companion object {
  val menuSceneInputContext = InputContext.create(
    "Menu",
    InputIdentifier.create(
      INPUTMAP_VERSION,
      InputContextIds.MENU_SCENE.ordinal.toLong()),
    listOf(basicMenuNavigationInputGroup, menuActionsInputGroup))

  val gameSceneInputContext = InputContext.create(
    "Game",
    InputIdentifier.create(
      INPUTMAP_VERSION,
      InputContextIds.GAME_SCENE.ordinal.toLong()),
    listOf(
      movementInputGroup,
      mouseActionsInputGroup,
      emojisInputGroup,
      gameActionsInputGroup))
}

Java

public static final InputContext menuSceneInputContext = InputContext.create(
        "Menu",
        InputIdentifier.create(
                INPUTMAP_VERSION,
                InputContextIds.MENU_SCENE.ordinal()),
        Arrays.asList(
                basicMenuNavigationInputGroup,
                menuActionsInputGroup
        )
);

public static final InputContext gameSceneInputContext = InputContext.create(
        "Game",
        InputIdentifier.create(
                INPUTMAP_VERSION,
                InputContextIds.GAME_SCENE.ordinal()),
        Arrays.asList(
                movementInputGroup,
                mouseActionsInputGroup,
                emojisInputGroup,
                gameActionsInputGroup
        )
);

C#

public static readonly InputContext menuSceneInputContext = InputContext.Create(
    "Menu",
    InputIdentifier.Create(
        INPUT_MAP_VERSION,
        (long)InputContextsIds.MENU_SCENE),
    new[]
    {
        basicMenuNavigationInputGroup,
        menuActionsInputGroup
    }.ToJavaList()
);

public static readonly InputContext gameSceneInputContext = InputContext.Create(
    "Game",
    InputIdentifier.Create(
        INPUT_MAP_VERSION,
        (long)InputContextsIds.GAME_SCENE),
    new[]
    {
        movementInputGroup,
        mouseActionsInputGroup,
        emojisInputGroup,
        gameActionsInputGroup
    }.ToJavaList()
);

InputContext comporte les champs suivants :

  • LocalizedContextLabel : chaîne décrivant les groupes qui font partie du contexte.
  • InputContextId : objet InputIdentifier qui stocke le numéro d'identifiant et la version de l'élément InputContext (consultez la section Suivi des identifiants de touches pour en savoir plus).
  • ActiveGroups : liste des InputGroups à utiliser et qui s'affichent en haut de la superposition lorsque ce contexte est actif.

Créer un mappage d'entrées

Un élément InputMap est une collection de tous les objets InputGroup disponibles dans un jeu, c'est-à-dire de tous les objets InputAction qu'un joueur peut s'attendre à exécuter.

Lorsque vous signalez vos associations de touches, vous créez une InputMap contenant tous les InputGroups utilisés dans votre jeu.

Si votre jeu ne prend pas en charge le remappage, désactivez l'option de remappage et définissez les touches réservées comme vides.

L'exemple suivant crée une InputMap permettant de signaler un ensemble d'InputGroups.

Kotlin

companion object {
  val gameInputMap = InputMap.create(
    listOf(
      basicMenuNavigationInputGroup,
      menuActionKeysInputGroup,
      movementInputGroup,
      mouseMovementInputGroup,
      pauseMenuInputGroup),
    MouseSettings.create(true, false),
    InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID.toLong()),
    InputEnums.REMAP_OPTION_ENABLED,
    // Use ESCAPE as reserved remapping key
    listof(InputControls.create(listOf(KeyEvent.KEYCODE_ESCAPE), emptyList()))
  )
}

Java

public static final InputMap gameInputMap = InputMap.create(
        Arrays.asList(
                basicMenuNavigationInputGroup,
                menuActionKeysInputGroup,
                movementInputGroup,
                mouseMovementInputGroup,
                pauseMenuInputGroup),
        MouseSettings.create(true, false),
        InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID),
        REMAP_OPTION_ENABLED,
        // Use ESCAPE as reserved remapping key
        Arrays.asList(
                InputControls.create(
                        Collections.singletonList(KeyEvent.KEYCODE_ESCAPE),
                        Collections.emptyList()
                )
        )
);

C#

public static readonly InputMap gameInputMap = InputMap.Create(
    new[]
    {
        basicMenuNavigationInputGroup,
        menuActionKeysInputGroup,
        movementInputGroup,
        mouseMovementInputGroup,
        pauseMenuInputGroup,
    }.ToJavaList(),
    MouseSettings.Create(true, false),
    InputIdentifier.Create(INPUT_MAP_VERSION, INPUT_MAP_ID),
    InputEnums.REMAP_OPTION_ENABLED,
    // Use ESCAPE as reserved remapping key
    new[]
    {
        InputControls.Create(
            New[] {
            new Integer(AndroidKeyCode.KEYCODE_ESCAPE)
        }.ToJavaList(),
        new ArrayList<Integer>())
    }.ToJavaList()
);

InputMap comporte les champs suivants :

  • InputGroups : les InputGroups signalés par votre jeu. Les groupes s'affichent dans l'ordre dans la superposition, sauf si vous spécifiez les groupes actuellement utilisés en appelant setInputContext().
  • MouseSettings : l'objet MouseSettings indique que la sensibilité de la souris peut être ajustée et que les mouvements de souris sont inversés sur l'axe y.
  • InputMapId : objet InputIdentifier qui stocke le numéro d'identifiant et la version de l'élément InputMap (consultez la section Suivi des identifiants de touches pour en savoir plus).
  • InputRemappingOption : InputEnums.REMAP_OPTION_ENABLED ou InputEnums.REMAP_OPTION_DISABLED. Définit si la fonctionnalité de remappage est activée.
  • ReservedControls : une liste d'InputControls que les utilisateurs n'auront pas le droit de remapper.

Suivi des identifiants de touches

Les objets InputAction, InputGroup, InputContext et InputMap contiennent un objet InputIdentifier qui stocke un numéro d'identifiant unique et un identifiant de version de chaîne. Le suivi de la version de chaîne de vos objets est facultative, mais recommandée pour suivre les versions de votre InputMap. Si la version de chaîne n'est pas fournie, la chaîne est vide. Une version de chaîne est requise pour les objets InputMap.

L'exemple suivant attribue une version de chaîne à des InputActions ou à des InputGroups :

Kotlin

class InputSDKProviderKotlin : InputMappingProvider {
  companion object {
    const val INPUTMAP_VERSION = "1.0.0"
    private val enterMenuInputAction = InputAction.create(
      "Enter menu",
      InputControls.create(listOf(KeyEvent.KEYCODE_ENTER), emptyList()),
      InputIdentifier.create(
        INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal.toLong()),
      InputEnums.REMAP_OPTION_ENABLED
    )

    private val movementInputGroup  = InputGroup.create(
      "Basic movement",
      listOf(
        moveUpInputAction,
        moveLeftInputAction,
        moveDownInputAction,
        mouseGameInputAction),
      InputIdentifier.create(
        INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal.toLong()),
      InputEnums.REMAP_OPTION_ENABLED)
  }
}

Java

public class InputSDKProvider implements InputMappingProvider {
    public static final String INPUTMAP_VERSION = "1.0.0";

    private static final InputAction enterMenuInputAction = InputAction.create(
            "Enter menu",
            InputControls.create(
                    Collections.singletonList(KeyEvent.KEYCODE_ENTER),
                    Collections.emptyList()),
            InputIdentifier.create(
                    INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal()),
            InputEnums.REMAP_OPTION_ENABLED
    );

    private static final InputGroup movementInputGroup = InputGroup.create(
            "Basic movement",
            Arrays.asList(
                    moveUpInputAction,
                    moveLeftInputAction,
                    moveDownInputAction,
                    moveRightInputAction,
                    mouseGameInputAction
            ),
            InputIdentifier.create(
                    INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal()),
            InputEnums.REMAP_OPTION_ENABLED
    );
}

C#

#if PLAY_GAMES_PC

using Java.Lang;
using Java.Util;
using Google.Android.Libraries.Play.Games.Inputmapping;
using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel;

public class InputSDKMappingProvider : InputMappingProviderCallbackHelper
{
    public static readonly string INPUT_MAP_VERSION = "1.0.0";

    private static readonly InputAction enterMenuInputAction =
        InputAction.Create(
            "Enter menu",
            InputControls.Create(
                new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE)}.ToJavaList(),
                new ArrayList<Integer>()),
            InputIdentifier.Create(
                INPUT_MAP_VERSION,
                (long)InputEventIds.ENTER_MENU),
            InputEnums.REMAP_OPTION_ENABLED
        );

    private static readonly InputGroup movementInputGroup = InputGroup.Create(
        "Basic movement",
        new[]
        {
            moveUpInputAction,
            moveLeftInputAction,
            moveDownInputAction,
            moveRightInputAction,
            mouseGameInputAction
        }.ToJavaList(),
        InputIdentifier.Create(
            INPUT_MAP_VERSION,
            (long)InputGroupsIds.BASIC_MOVEMENT),
        InputEnums.REMAP_OPTION_ENABLED
    );
}
#endif

Les numéros d'identifiant des objets InputAction doivent être uniques parmi tous les InputActions de votre InputMap. De même, les identifiants des objets InputGroup doivent être uniques parmi tous les InputGroups de votre InputMap. L'exemple suivant illustre comment suivre les identifiants uniques de vos objets à l'aide d'un enum :

Kotlin

enum class InputActionsIds {
    NAVIGATE_UP,
    NAVIGATE_DOWN,
    ENTER_MENU,
    EXIT_MENU,
    // ...
    JUMP,
    RUN,
    EMOJI_1,
    EMOJI_2,
    // ...
}

enum class InputGroupsIds {
    // Main menu scene
    BASIC_NAVIGATION, // WASD, Enter, Backspace
    MENU_ACTIONS, // C: chat, Space: quick game, S: store
    // Gameplay scene
    BASIC_MOVEMENT, // WASD, space: jump, Shift: run
    MOUSE_ACTIONS, // Left click: shoot, Right click: aim
    EMOJIS, // Emojis with keys 1,2,3,4 and 5
    GAME_ACTIONS, // M: map, P: pause, R: reload
}

enum class InputContextIds {
    MENU_SCENE, // Basic menu navigation, menu actions
    GAME_SCENE, // Basic movement, mouse actions, emojis, game actions
}

const val INPUT_MAP_ID = 0

Java

public enum InputActionsIds {
    NAVIGATE_UP,
    NAVIGATE_DOWN,
    ENTER_MENU,
    EXIT_MENU,
    // ...
    JUMP,
    RUN,
    EMOJI_1,
    EMOJI_2,
    // ...
}

public enum InputGroupsIds {
    // Main menu scene
    BASIC_NAVIGATION, // WASD, Enter, Backspace
    MENU_ACTIONS, // C: chat, Space: quick game, S: store
    // Gameplay scene
    BASIC_MOVEMENT, // WASD, space: jump, Shift: run
    MOUSE_ACTIONS, // Left click: shoot, Right click: aim
    EMOJIS, // Emojis with keys 1,2,3,4 and 5
    GAME_ACTIONS, // M: map, P: pause, R: reload
}

public enum InputContextIds {
    MENU_SCENE, // Basic navigation, menu actions
    GAME_SCENE, // Basic movement, mouse actions, emojis, game actions
}

public static final long INPUT_MAP_ID = 0;

C#

public enum InputActionsIds
{
    NAVIGATE_UP,
    NAVIGATE_DOWN,
    ENTER_MENU,
    EXIT_MENU,
    // ...
    JUMP,
    RUN,
    EMOJI_1,
    EMOJI_2,
    // ...
}

public enum InputGroupsIds
{
    // Main menu scene
    BASIC_NAVIGATION, // WASD, Enter, Backspace
    MENU_ACTIONS, // C: chat, Space: quick game, S: store
    // Gameplay scene
    BASIC_MOVEMENT, // WASD, space: jump, Shift: run
    MOUSE_ACTIONS, // Left click: shoot, Right click: aim
    EMOJIS, // Emojis with keys 1,2,3,4 and 5
    GAME_ACTIONS, // M: map, P: pause, R: reload
}

public enum InputContextIds
{
    MENU_SCENE, // Basic navigation, menu actions
    GAME_SCENE, // Basic movement, mouse actions, emojis, game actions
}

public static readonly long INPUT_MAP_ID = 0;

InputIdentifier comporte les champs suivants :

  • UniqueId : un numéro d'identifiant unique est défini pour identifier clairement et sans équivoque un ensemble de données d'entrée.
  • VersionString : une chaîne de version lisible par l'humain et définie pour identifier une version de données d'entrée parmi deux versions de modifications de données d'entrée.

Recevoir une notification lors d'événements de remappage (facultatif)

Recevez des notifications lors d'événements de remappage afin d'être informé des touches en cours d'utilisation dans votre jeu. Cela permet à votre jeu de mettre à jour les éléments présents à l'écran du jeu et qui permettent d'afficher les commandes des actions.

L'image suivante illustre un exemple de ce comportement où, après le remappage des touches G, P et S en J, X et T, les éléments de l'interface utilisateur du jeu sont mis à jour pour afficher les touches définies par l'utilisateur.

Interface utilisateur réagissant aux événements de remappage à l&#39;aide du rappel InputRemappingListener.

Cette fonctionnalité est obtenue en enregistrant un rappel InputRemappingListener. Pour implémenter cette fonctionnalité, commencez par enregistrer une instance InputRemappingListener :

Kotlin

class InputSDKRemappingListener : InputRemappingListener {
  override fun onInputMapChanged(inputMap: InputMap) {
    Log.i(TAG, "Received update on input map changed.")
    if (inputMap.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) {
      return
    }
    for (inputGroup in inputMap.inputGroups()) {
      if (inputGroup.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) {
        continue
      }
      for (inputAction in inputGroup.inputActions()) {
        if (inputAction.inputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) {
          // Found InputAction remapped by user
          processRemappedAction(inputAction)
        }
      }
    }
  }

  private fun processRemappedAction(remappedInputAction: InputAction) {
    // Get remapped action info
    val remappedControls = remappedInputAction.remappedInputControls()
    val remappedKeyCodes = remappedControls.keycodes()
    val mouseActions = remappedControls.mouseActions()
    val version = remappedInputAction.inputActionId().versionString()
    val remappedActionId = remappedInputAction.inputActionId().uniqueId()
    val currentInputAction: Optional<InputAction>
    currentInputAction = if (version == null || version.isEmpty()
      || version == InputSDKProvider.INPUTMAP_VERSION
    ) {
      getCurrentVersionInputAction(remappedActionId)
    } else {
      Log.i(TAG,
            "Detected version of user-saved input action defers from current version")
      getCurrentVersionInputActionFromPreviousVersion(
        remappedActionId, version)
    }
    if (!currentInputAction.isPresent) {
      Log.e(TAG, String.format(
        "can't find remapped input action with id %d and version %s",
        remappedActionId, if (version == null || version.isEmpty()) "UNKNOWN" else version))
      return
    }
    val originalControls = currentInputAction.get().inputControls()
    val originalKeyCodes = originalControls.keycodes()
    Log.i(TAG, String.format(
      "Found input action with id %d remapped from key %s to key %s",
      remappedActionId,
      keyCodesToString(originalKeyCodes),
      keyCodesToString(remappedKeyCodes)))

    // TODO: make display changes to match controls used by the user
  }

  private fun getCurrentVersionInputAction(inputActionId: Long): Optional<InputAction> {
    for (inputGroup in InputSDKProvider.gameInputMap.inputGroups()) {
      for (inputAction in inputGroup.inputActions()) {
        if (inputAction.inputActionId().uniqueId() == inputActionId) {
          return Optional.of(inputAction)
        }
      }
    }
    return Optional.empty()
  }

  private fun getCurrentVersionInputActionFromPreviousVersion(
    inputActionId: Long, previousVersion: String
  ): Optional<InputAction7gt; {
    // TODO: add logic to this method considering the diff between the current and previous
    //  InputMap.
    return Optional.empty()
  }

  private fun keyCodesToString(keyCodes: List<Int>): String {
    val builder = StringBuilder()
    for (keyCode in keyCodes) {
      if (!builder.toString().isEmpty()) {
        builder.append(" + ")
      }
      builder.append(keyCode)
    }
    return String.format("(%s)", builder)
  }

  companion object {
    private const val TAG = "InputSDKRemappingListener"
  }
}

Java

public class InputSDKRemappingListener implements InputRemappingListener {

    private static final String TAG = "InputSDKRemappingListener";

    @Override
    public void onInputMapChanged(InputMap inputMap) {
        Log.i(TAG, "Received update on input map changed.");
        if (inputMap.inputRemappingOption() ==
                InputEnums.REMAP_OPTION_DISABLED) {
            return;
        }
        for (InputGroup inputGroup : inputMap.inputGroups()) {
            if (inputGroup.inputRemappingOption() ==
                    InputEnums.REMAP_OPTION_DISABLED) {
                continue;
            }
            for (InputAction inputAction : inputGroup.inputActions()) {
                if (inputAction.inputRemappingOption() !=
                        InputEnums.REMAP_OPTION_DISABLED) {
                    // Found InputAction remapped by user
                    processRemappedAction(inputAction);
                }
            }
        }
    }

    private void processRemappedAction(InputAction remappedInputAction) {
        // Get remapped action info
        InputControls remappedControls =
            remappedInputAction.remappedInputControls();
        List<Integer> remappedKeyCodes = remappedControls.keycodes();
        List<Integer> mouseActions = remappedControls.mouseActions();
        String version = remappedInputAction.inputActionId().versionString();
        long remappedActionId = remappedInputAction.inputActionId().uniqueId();
        Optional<InputAction> currentInputAction;
        if (version == null || version.isEmpty()
                    || version.equals(InputSDKProvider.INPUTMAP_VERSION)) {
            currentInputAction = getCurrentVersionInputAction(remappedActionId);
        } else {
            Log.i(TAG, "Detected version of user-saved input action defers " +
                    "from current version");
            currentInputAction =
                    getCurrentVersionInputActionFromPreviousVersion(
                            remappedActionId, version);
        }
        if (!currentInputAction.isPresent()) {
            Log.e(TAG, String.format(
                    "input action with id %d and version %s not found",
                    remappedActionId, version == null || version.isEmpty() ?
                            "UNKNOWN" : version));
            return;
        }
        InputControls originalControls =
                currentInputAction.get().inputControls();
        List<Integer> originalKeyCodes = originalControls.keycodes();

        Log.i(TAG, String.format(
                "Found input action with id %d remapped from key %s to key %s",
                remappedActionId,
                keyCodesToString(originalKeyCodes),
                keyCodesToString(remappedKeyCodes)));

        // TODO: make display changes to match controls used by the user
    }

    private Optional<InputAction> getCurrentVersionInputAction(
            long inputActionId) {
        for (InputGroup inputGroup :
                    InputSDKProvider.gameInputMap.inputGroups()) {
            for (InputAction inputAction : inputGroup.inputActions()) {
                if (inputAction.inputActionId().uniqueId() == inputActionId) {
                    return Optional.of(inputAction);
                }
            }
        }
        return Optional.empty();
    }

    private Optional<InputAction>
            getCurrentVersionInputActionFromPreviousVersion(
                    long inputActionId, String previousVersion) {
        // TODO: add logic to this method considering the diff between your
        // current and previous InputMap.
        return Optional.empty();
    }

    private String keyCodesToString(List<Integer> keyCodes) {
        StringBuilder builder = new StringBuilder();
        for (Integer keyCode : keyCodes) {
            if (!builder.toString().isEmpty()) {
                builder.append(" + ");
            }
            builder.append(keyCode);
        }
        return String.format("(%s)", builder);
    }
}

C#

#if PLAY_GAMES_PC

using System.Text;
using Java.Lang;
using Java.Util;
using Google.Android.Libraries.Play.Games.Inputmapping;
using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel;
using UnityEngine;

public class InputSDKRemappingListener : InputRemappingListenerCallbackHelper
{
    public override void OnInputMapChanged(InputMap inputMap)
    {
        Debug.Log("Received update on remapped controls.");
        if (inputMap.InputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED)
        {
            return;
        }
        List<InputGroup> inputGroups = inputMap.InputGroups();
        for (int i = 0; i < inputGroups.Size(); i ++)
        {
            InputGroup inputGroup = inputGroups.Get(i);
            if (inputGroup.InputRemappingOption()
                    == InputEnums.REMAP_OPTION_DISABLED)
            {
                continue;
            }
            List<InputAction> inputActions = inputGroup.InputActions();
            for (int j = 0; j < inputActions.Size(); j ++)
            {
                InputAction inputAction = inputActions.Get(j);
                if (inputAction.InputRemappingOption()
                        != InputEnums.REMAP_OPTION_DISABLED)
                {
                    // Found action remapped by user
                    ProcessRemappedAction(inputAction);
                }
            }
        }
    }

    private void ProcessRemappedAction(InputAction remappedInputAction)
    {
        InputControls remappedInputControls =
                remappedInputAction.RemappedInputControls();
        List<Integer> remappedKeycodes = remappedInputControls.Keycodes();
        List<Integer> mouseActions = remappedInputControls.MouseActions();
        string version = remappedInputAction.InputActionId().VersionString();
        long remappedActionId = remappedInputAction.InputActionId().UniqueId();
        InputAction currentInputAction;
        if (string.IsNullOrEmpty(version)
                || string.Equals(
                version, InputSDKMappingProvider.INPUT_MAP_VERSION))
        {
            currentInputAction = GetCurrentVersionInputAction(remappedActionId);
        }
        else
        {
            Debug.Log("Detected version of used-saved input action defers" +
                " from current version");
            currentInputAction =
                GetCurrentVersionInputActionFromPreviousVersion(
                    remappedActionId, version);
        }
        if (currentInputAction == null)
        {
            Debug.LogError(string.Format(
                "Input Action with id {0} and version {1} not found",
                remappedActionId,
                string.IsNullOrEmpty(version) ? "UNKNOWN" : version));
            return;
        }
        InputControls originalControls = currentInputAction.InputControls();
        List<Integer> originalKeycodes = originalControls.Keycodes();

        Debug.Log(string.Format(
            "Found Input Action with id {0} remapped from key {1} to key {2}",
            remappedActionId,
            KeyCodesToString(originalKeycodes),
            KeyCodesToString(remappedKeycodes)));
        // TODO: update HUD according to the controls of the user
    }

    private InputAction GetCurrentVersionInputAction(
            long inputActionId)
    {
        List<InputGroup> inputGroups =
            InputSDKMappingProvider.gameInputMap.InputGroups();
        for (int i = 0; i < inputGroups.Size(); i++)
        {
            InputGroup inputGroup = inputGroups.Get(i);
            List<InputAction> inputActions = inputGroup.InputActions();
            for (int j = 0; j < inputActions.Size(); j++)
            {
                InputAction inputAction = inputActions.Get(j);
                if (inputAction.InputActionId().UniqueId() == inputActionId)
                {
                    return inputAction;
                }
            }
        }
        return null;
    }

    private InputAction GetCurrentVersionInputActionFromPreviousVersion(
            long inputActionId, string version)
    {
        // TODO: add logic to this method considering the diff between your
        // current and previous InputMap.
        return null;
    }

    private string KeyCodesToString(List<Integer> keycodes)
    {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < keycodes.Size(); i ++)
        {
            Integer keycode = keycodes.Get(i);
            if (builder.Length > 0)
            {
                builder.Append(" + ");
            }
            builder.Append(keycode.IntValue());
        }
        return string.Format("({0})", builder.ToString());
    }
}
#endif

Le InputRemappingListener est averti lors du lancement après le chargement des commandes remappées enregistrées par l'utilisateur, et chaque fois que l'utilisateur remappe ses touches.

Initialisation

Si vous utilisez des InputContexts, définissez le contexte lors de chaque transition vers une nouvelle scène, y compris le premier contexte utilisé pour votre scène initiale. Vous devez définir l'InputContext après avoir enregistré votre InputMap.

Si vous utilisez des InputRemappingListeners pour être averti lors d'événements de remappage, enregistrez votre InputRemappingListener avant d'enregistrer votre InputMappingProvider. Dans le cas contraire, votre jeu peut manquer des événements importants au moment du lancement.

L'exemple suivant montre comment initialiser l'API :

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    if (isGooglePlayGamesOnPC()) {
        val inputMappingClient = Input.getInputMappingClient(this)
        // Register listener before registering the provider
        inputMappingClient.registerRemappingListener(InputSDKRemappingListener())
        inputMappingClient.setInputMappingProvider(
                InputSDKProvider())
        // Set the context after you have registered the provider.
        inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext)
    }
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (isGooglePlayGamesOnPC()) {
        InputMappingClient inputMappingClient =
                Input.getInputMappingClient(this);
        // Register listener before registering the provider
        inputMappingClient.registerRemappingListener(
                new InputSDKRemappingListener());
        inputMappingClient.setInputMappingProvider(
                new InputSDKProvider());
        // Set the context after you have registered the provider
        inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext);
    }
}

C#

#if PLAY_GAMES_PC
using Google.Android.Libraries.Play.Games.Inputmapping;
using Google.Android.Libraries.Play.Games.InputMapping.ExternalType.Android.Content;
using Google.LibraryWrapper.Java;
#endif

public class GameManager : MonoBehaviour
{
#if PLAY_GAMES_PC
    private InputSDKMappingProvider _inputMapProvider =
        new InputSDKMappingProvider();
    private InputMappingClient _inputMappingClient;
#endif

    public void Awake()
    {
#if PLAY_GAMES_PC
        Context context = (Context)Utils.GetUnityActivity().GetRawObject();
        _inputMappingClient = Google.Android.Libraries.Play.Games.Inputmapping
            .Input.GetInputMappingClient(context);
        // Register listener before registering the provider.
        _inputMappingClient.RegisterRemappingListener(
            new InputSDKRemappingListener());
        _inputMappingClient.SetInputMappingProvider(_inputMapProvider);
        // Register context after you have registered the provider.
       _inputMappingClient.SetInputContext(
           InputSDKMappingProvider.menuSceneInputContext);
#endif
    }
}

Nettoyage

Désinscrivez votre instance InputMappingProvider et toute instance InputRemappingListener lorsque votre jeu est fermé, même si le SDK Input est assez intelligent pour éviter les fuites de ressources si vous ne le faites pas :

Kotlin

override fun onDestroy() {
    if (isGooglePlayGamesOnPC()) {
        val inputMappingClient = Input.getInputMappingClient(this)
        inputMappingClient.clearInputMappingProvider()
        inputMappingClient.clearRemappingListener()
    }

    super.onDestroy()
}

Java

@Override
protected void onDestroy() {
    if (isGooglePlayGamesOnPC()) {
        InputMappingClient inputMappingClient =
                Input.getInputMappingClient(this);
        inputMappingClient.clearInputMappingProvider();
        inputMappingClient.clearRemappingListener();
    }

    super.onDestroy();
}

C#

public class GameManager : MonoBehaviour
{
    private void OnDestroy()
    {
#if PLAY_GAMES_PC
        _inputMappingClient.ClearInputMappingProvider();
        _inputMappingClient.ClearRemappingListener();
#endif
    }
}

Test

Vous pouvez tester votre implémentation du SDK Input en ouvrant manuellement la superposition afin d'afficher l'expérience utilisateur. Vous pouvez aussi vous servir du shell adb pour un test et une vérification automatisés.

L'émulateur Google Play Jeux sur PC vérifie l'exactitude de votre mappe d'entrée en vérifiant les erreurs courantes. Pour certains scénarios, par exemple des identifiants uniques en double, une utilisation de mappages d'entrée différents ou l'échec des règles de remappage (si le remappage est activé), la superposition affiche un message d'erreur comme celui ci-dessous : La superposition du SDK Input.

Vérifiez votre implémentation du SDK Input à l'aide d'adb dans la ligne de commande. Pour obtenir le mappage actuel des entrées, utilisez la commande adb shell suivante (remplacez MY.PACKAGE.NAME par le nom de votre jeu) :

adb shell dumpsys input_mapping_service --get MY.PACKAGE.NAME

Un résultat semblable aux lignes suivantes devrait s'afficher si vous avez correctement enregistré votre InputMap :

Getting input map for com.example.inputsample...
Successfully received the following inputmap:
# com.google.android.libraries.play.games.InputMap@d73526e1
input_groups {
  group_label: "Basic Movement"
  input_actions {
    action_label: "Jump"
    input_controls {
      keycodes: 51
      keycodes: 19
    }
    unique_id: 0
  }
  input_actions {
    action_label: "Left"
    input_controls {
      keycodes: 29
      keycodes: 21
    }
    unique_id: 1
  }
  input_actions {
    action_label: "Right"
    input_controls {
      keycodes: 32
      keycodes: 22
    }
    unique_id: 2
  }
  input_actions {
    action_label: "Use"
    input_controls {
      keycodes: 33
      keycodes: 66
      mouse_actions: MOUSE_LEFT_CLICK
      mouse_actions_value: 0
    }
    unique_id: 3
  }
}
input_groups {
  group_label: "Special Input"
  input_actions {
    action_label: "Jump"
    input_controls {
      keycodes: 51
      keycodes: 19
      keycodes: 62
      mouse_actions: MOUSE_LEFT_CLICK
      mouse_actions_value: 0
    }
    unique_id: 4
  }
  input_actions {
    action_label: "Duck"
    input_controls {
      keycodes: 47
      keycodes: 20
      keycodes: 113
      mouse_actions: MOUSE_RIGHT_CLICK
      mouse_actions_value: 1
    }
    unique_id: 5
  }
}
mouse_settings {
  allow_mouse_sensitivity_adjustment: true
  invert_mouse_movement: true
}

Localisation

Le SDK Input n'utilise pas le système de localisation d'Android. Par conséquent, vous devez fournir des chaînes localisées lorsque vous envoyez une propriété InputMap. Vous pouvez aussi utiliser le système de localisation de votre moteur de jeu.

Proguard

Lorsque vous utilisez Proguard pour minimiser votre jeu, ajoutez les règles suivantes au fichier de configuration de Proguard pour vous assurer que le SDK n'est pas supprimé de votre package final :

-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }

Étapes suivantes

Après avoir intégré le SDK Input dans votre jeu, vous pouvez passer aux autres conditions à remplir pour Google Play Jeux sur PC. Pour en savoir plus, consultez Premiers pas avec Google Play Jeux sur PC.