Inizia a utilizzare l'SDK Input

Questo documento descrive come configurare e visualizzare l'SDK Input nei giochi che supportano Google Play Giochi su PC. Le attività includono l'aggiunta dell'SDK al tuo gioco e la generazione di una mappa di input, che contiene le assegnazioni di azioni di gioco agli input utente.

Prima di iniziare

Prima di aggiungere l'SDK Input al tuo gioco, devi supportare l'input con tastiera e mouse utilizzando il sistema di input del tuo motore di gioco.

L'SDK Input fornisce a Google Play Giochi su PC informazioni su quali controlli vengono utilizzati dal tuo gioco, in modo che possano essere mostrati all'utente. Se vuoi, puoi anche consentire agli utenti di rimappare la tastiera.

Ogni controllo è un InputAction (ad es. "J" per "Salta") e puoi organizzare i InputAction in InputGroups.InputActions Un InputGroup potrebbe rappresentare un'altra modalità nel gioco, ad esempio "Guida", "A piedi" o "Menu principale". Puoi anche utilizzare InputContexts per indicare quali gruppi sono attivi in diversi punti del gioco.

Puoi attivare la gestione automatica della rimappatura della tastiera, ma se preferisci fornire la tua interfaccia di rimappatura dei controlli, puoi disattivare la rimappatura dell'SDK di input.

Il seguente diagramma di sequenza descrive il funzionamento dell'API dell'SDK Input:

Diagramma di sequenza di un'implementazione di un gioco che chiama l'API SDK Input
e la sua interazione con il dispositivo Android.

Quando il tuo gioco implementa l'SDK Input, i controlli vengono visualizzati nella sovrapposizione di Google Play Giochi su PC.

L'overlay di Google Play Giochi su PC

L'overlay di Google Play Giochi su PC ("l'overlay") mostra i controlli definiti dal tuo gioco. Gli utenti possono accedere all'overlay in qualsiasi momento premendo Maiusc + Tab.

L'overlay di Google Play Giochi su PC.

Best practice per la progettazione delle associazioni di tasti

Quando progetti le associazioni di tasti, tieni presenti le seguenti best practice:

  • Raggruppa i InputActions in InputGroups correlati logicamente per migliorare la navigazione e la rilevabilità dei controlli durante il gameplay.
  • Assegna ogni InputGroup a un massimo di un InputContext. Un valore InputMap granulare consente di navigare meglio tra i controlli nell'overlay.
  • Crea un InputContext per ogni tipo di scena del tuo gioco. In genere, puoi utilizzare un singolo InputContext per tutte le scene "tipo menu". Utilizza InputContexts diversi per i minigiochi nel tuo gioco o per i controlli alternativi di una singola scena.
  • Se due azioni sono progettate per utilizzare la stessa chiave nello stesso InputContext, utilizza la stringa dell'etichetta, ad esempio "Interagisci / Attiva".
  • Se due chiavi sono progettate per essere associate allo stesso InputAction, utilizza due InputActions diversi che eseguono la stessa azione nel gioco. Puoi utilizzare la stessa stringa di etichetta per entrambi i valori InputActions, ma il relativo ID deve essere diverso.
  • Se un tasto modificatore viene applicato a un insieme di tasti, valuta la possibilità di avere un singolo InputAction con il tasto modificatore anziché più InputAction che combinano il tasto modificatore (ad esempio, utilizza Maiusc e W, A, S, D anziché Maiusc + W, Maiusc + A, Maiusc + S, Maiusc + D).InputActions
  • La rimappatura dell'input viene disattivata automaticamente quando l'utente scrive nei campi di testo. Segui le best practice per l'implementazione dei campi di testo Android per assicurarti che Android possa rilevare i campi di testo nel tuo gioco e impedire alle chiavi rimappate di interferire con essi. Se il tuo gioco deve utilizzare campi di testo non convenzionali, puoi utilizzare setInputContext() con un InputContext contenente un elenco vuoto di InputGroups per disattivare la rimappatura manualmente.
  • Se il tuo gioco supporta la rimappatura, ti consigliamo di aggiornare le associazioni dei tasti come un'operazione sensibile che può entrare in conflitto con le versioni salvate dall'utente. Se possibile, evita di cambiare gli ID dei controlli esistenti.

La funzionalità di rimappatura

Google Play Giochi su PC supporta la rimappatura dei controlli della tastiera in base alle associazioni dei tasti fornite dal tuo gioco utilizzando l'SDK Input. Questa opzione è facoltativa e può essere disattivata completamente. Ad esempio, potresti voler fornire la tua interfaccia di rimappatura della tastiera. Per disattivare il rimappaggio per il tuo gioco, devi solo specificare l'opzione di rimappaggio disattivata per il tuo InputMap (consulta Creare un InputMap per ulteriori informazioni).

Per accedere a questa funzionalità, gli utenti devono aprire l'overlay e fare clic sull'azione che vogliono rimappare. Dopo ogni evento di rimappatura, Google Play Giochi su PC mappa ogni controllo rimappato dall'utente ai controlli predefiniti che il gioco si aspetta di ricevere, quindi il gioco non deve essere a conoscenza della rimappatura del giocatore. Se vuoi, puoi aggiornare gli asset utilizzati per visualizzare i controlli da tastiera nel tuo gioco aggiungendo un callback per la rimappatura degli eventi.

Prova a rimappare la chiave

Google Play Giochi su PC memorizza i controlli rimappati localmente per ogni utente, consentendo la persistenza dei controlli nelle sessioni di gioco. Queste informazioni vengono memorizzate su disco solo per la piattaforma PC e non influiscono sull'esperienza mobile. I dati di controllo vengono eliminati quando l'utente disinstalla o reinstalla Google Play Giochi su PC. Questi dati non sono permanenti su più dispositivi PC.

Per supportare la funzionalità di rimappatura nel tuo gioco, evita le seguenti limitazioni:

Limitazioni della mappatura dinamica

Le funzionalità di rimappatura possono essere disattivate nel gioco se le associazioni dei tasti contengono uno dei seguenti casi:

  • InputActions con più tasti che non sono composti da un tasto di modifica e un tasto non di modifica. Ad esempio, Maiusc+A è valido, ma A+B, Ctrl+Alt o Maiusc+A+Tab non lo sono.
  • InputMap contiene InputActions, InputGroups o InputContexts con ID univoci ripetuti.

Limitazioni della mappatura dinamica

Quando progetti le associazioni di tasti per la rimappatura, tieni conto delle seguenti limitazioni:

  • Il rimappaggio alle combinazioni di tasti non è supportato. Ad esempio, gli utenti non possono riassegnare Maiusc + A a Ctrl + B o A a Maiusc + A.
  • Il rimappaggio non è supportato per InputActions con i pulsanti del mouse. Ad esempio, Maiusc+clic destro non può essere rimappato.

Testare la rimappatura dei tasti sull'emulatore di Google Play Giochi su PC

Puoi attivare la funzionalità di rimappatura in Google Play Giochi sull'emulatore per PC in qualsiasi momento eseguendo il seguente comando adb:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

L'overlay cambia come nell'immagine seguente:

L'overlay con la rimappatura dei tasti abilitata.

Aggiungi l'SDK

Installa l'SDK Input in base alla tua piattaforma di sviluppo.

Java e Kotlin

Ottieni l'SDK Input per Java o Kotlin aggiungendo una dipendenza al file build.gradle a livello di modulo:

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

Unity

L'SDK Input è un pacchetto Unity standard con diverse dipendenze.

È obbligatoria l'installazione del pacchetto con tutte le dipendenze. Esistono diversi modi per installare i pacchetti.

Installa .unitypackage

Scarica il file unitypackage dell'SDK Input con tutte le relative dipendenze. Puoi installare .unitypackage selezionando Asset > Importa pacchetto > Pacchetto personalizzato e individuando il file scaricato.

Installazione tramite UPM

In alternativa, puoi installare il pacchetto utilizzando Unity Package Manager scaricando .tgz e installando le relative dipendenze:

Installazione tramite OpenUPM

Puoi installare il pacchetto utilizzando OpenUPM.

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

Esempi di giochi

Per esempi di come eseguire l'integrazione con l'SDK Input, consulta AGDK Tunnel per i giochi Kotlin o Java e Trivial Kart per i giochi Unity.

Generare le associazioni di tasti

Registra le associazioni di tasti creando un InputMap e restituiscelo con un InputMappingProvider. L'esempio seguente illustra 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

Definisci le azioni di input

La classe InputAction viene utilizzata per mappare una chiave o una combinazione di tasti a un'azione di gioco. InputActions deve avere ID univoci in tutti i InputActions.

Se supporti il ricalcolo, puoi definire cosa può essere InputActions. Se il tuo gioco non supporta il rimappaggio, devi impostare l'opzione di rimappaggio su disattivata per tutti i tuoi InputActions, ma l'SDK Input è abbastanza intelligente da disattivare il rimappaggio se non lo supporti nel tuo InputMap.

Questo esempio mappa la chiave space all'azione Drive.

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

InputAction con un solo tasto visualizzato nell&#39;overlay.

Le azioni possono rappresentare anche gli input del mouse. Questo esempio imposta Clic sinistro sull'azione Sposta:

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

Azione di input del mouse visualizzata nell&#39;overlay.

Le combinazioni di tasti vengono specificate passando più codici a InputAction. In questo esempio, Barra spaziatrice + Maiusc è mappato all'azione Turbo, che funziona anche quando Barra spaziatrice è mappata a Guida.

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

InputAction con più tasti visualizzato nell&#39;overlay.

L'SDK Input ti consente di combinare i pulsanti del mouse e dei tasti per una singola azione. Questo esempio indica che se premi contemporaneamente Maiusc e clic con il tasto destro del mouse, viene aggiunto un waypoint in questo gioco di esempio:

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

Combinazione di InputAction di tasti e mouse visualizzata nell&#39;overlay.

InputAction ha i seguenti campi:

  • ActionLabel: la stringa visualizzata nell'interfaccia utente per rappresentare questa azione. La localizzazione non viene eseguita automaticamente, quindi eseguila in anticipo.
  • InputControls: definisce i controlli di immissione utilizzati da questa azione. I controlli vengono mappati a glifi coerenti nell'overlay.
  • InputActionId: oggetto InputIdentifier che memorizza l'ID numero e la versione del InputAction (per ulteriori informazioni, consulta ID chiave di monitoraggio).
  • InputRemappingOption: uno di InputEnums.REMAP_OPTION_ENABLED o InputEnums.REMAP_OPTION_DISABLED. Definisce se l'azione è abilitata per la mappatura. Se il tuo gioco non supporta il ricollegamento, puoi saltare questo campo o impostarlo semplicemente su disattivato.
  • RemappedInputControls: oggetto InputControls di sola lettura utilizzato per leggere la chiave rimappata impostata dall'utente sugli eventi di rimappatura (utilizzato per ricevere notifiche sugli eventi di rimappatura).

InputControls rappresenta gli input associati a un'azione e contiene i seguenti campi:

  • AndroidKeycodes: è un elenco di numeri interi che rappresentano gli input da tastiera associati a un'azione. Questi sono definiti nella classe KeyEvent o nella classe AndroidKeycode per Unity.
  • MouseActions: è un elenco di valori MouseAction che rappresentano gli input del mouse associati a questa azione.

Definisci i gruppi di input

InputActions sono raggruppati con azioni correlate logicamente utilizzando InputGroups per migliorare la navigazione e la rilevabilità dei controlli nell'overlay. Ogni ID InputGroup deve essere univoco per tutti i InputGroups nel tuo gioco.

Se organizzi le azioni di input in gruppi, è più facile per un giocatore trovare la mappatura dei tasti corretta per il contesto corrente.

Se supporti il ricalcolo, puoi definire cosa può essere InputGroups. Se il tuo gioco non supporta il rimappaggio, devi impostare l'opzione di rimappaggio su disattivata per tutti i tuoi InputGroups, ma l'SDK Input è abbastanza intelligente da disattivare il rimappaggio se non lo supporti nel tuo 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'esempio seguente mostra i gruppi di input Controlli stradali e Controlli menu nell'overlay:

L&#39;overlay che mostra un InputMap contenente i gruppi di input dei controlli stradali e dei controlli del menu.

InputGroup contiene i seguenti campi:

  • GroupLabel: una stringa da visualizzare nell'overlay che può essere utilizzata per agrupare logicamente un insieme di azioni. Questa stringa non viene localizzata automaticamente.
  • InputActions: un elenco di oggetti InputAction definiti nel passaggio precedente. Tutte queste azioni vengono visualizzate sotto l'intestazione del gruppo.
  • InputGroupId: oggetto InputIdentifier che memorizza l'ID e la versione del numero di InputGroup. Per ulteriori informazioni, consulta ID chiave di monitoraggio.
  • InputRemappingOption: uno di InputEnums.REMAP_OPTION_ENABLED o InputEnums.REMAP_OPTION_DISABLED. Se disattivata, la rimappatura verrà disattivata per tutti gli oggetti InputAction appartenenti a questo gruppo, anche se viene specificata l'opzione di rimappatura attivata. Se abilitata, tutte le azioni appartenenti a questo gruppo possono essere rimappate, a meno che non sia specificato che sono disattivate dalle singole azioni.

Definisci i contesti di input

InputContexts consente al gioco di utilizzare un insieme diverso di controlli da tastiera per le varie scene. Ad esempio:

  • Puoi specificare insiemi diversi di input per la navigazione nei menu e per muoverti nel gioco.
  • Puoi specificare diversi insiemi di input a seconda della modalità di locomozione nel tuo gioco, ad esempio guida o camminata.
  • Puoi specificare diversi insiemi di input in base allo stato corrente del tuo gioco, ad esempio la navigazione in un overworld rispetto al gioco di un singolo livello.

Quando utilizzi InputContexts, l'overlay mostra prima i gruppi del contesto in uso. Per attivare questo comportamento, chiama setInputContext() per impostare il contesto ogni volta che il gioco entra in una scena diversa. L'immagine seguente dimostra questo comportamento: nella scena "Guida", le azioni Controlli stradali vengono mostrate nella parte superiore dell'overlay. Quando apri il menu "Negozio", le azioni "Controlli menu" vengono visualizzate nella parte superiore dell'overlay.

Gruppi di ordinamento InputContexts nell&#39;overlay.

Questi aggiornamenti dell'overlay vengono eseguiti impostando un InputContext diverso in punti diversi del gioco. Per:

  1. Raggruppa i InputActions con azioni correlate logicamente utilizzando InputGroups
  2. Assegna questi InputGroups a un InputContext per le diverse parti del tuo gioco

InputGroups che appartengono allo stessoInputContextnon possono avere parametri InputActions in conflitto se viene utilizzata la stessa chiave. È buona norma assegnare ogni InputGroup a un singolo InputContext.

Il seguente codice di esempio mostra la logica di 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 contiene i seguenti campi:

  • LocalizedContextLabel: una stringa che descrive i gruppi che appartengono al contesto.
  • InputContextId: oggetto InputIdentifier che memorizza l'ID numero e la versione del InputContext (per ulteriori informazioni, consulta ID chiave di monitoraggio).
  • ActiveGroups: un elenco di InputGroups da utilizzare e da visualizzare nella parte superiore dell'overlay quando questo contesto è attivo.

Crea una mappa di input

Un InputMap è una raccolta di tutti gli oggetti InputGroup disponibili in un gioco e, di conseguenza, di tutti gli oggetti InputAction che un giocatore può eseguire.

Quando segnali le associazioni di tasti, crei un InputMap con tutte le InputGroups utilizzate nel gioco.

Se il gioco non supporta il rimappaggio, imposta l'opzione di rimappaggio su disattivata e lascia vuote le chiavi riservate.

L'esempio seguente crea un InputMap utilizzato per segnalare una raccolta di 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 contiene i seguenti campi:

  • InputGroups: gli InputGroup segnalati dal gioco. I gruppi vengono visualizzati in ordine nell'overlay, a meno che non vengano specificati i gruppi correnti in uso chiamando setInputContext().
  • MouseSettings: l'oggetto MouseSettings indica che la sensibilità del mouse può essere regolata e che il mouse è invertito sull'asse y.
  • InputMapId: oggetto InputIdentifier che memorizza l'ID numero e la versione del InputMap (per ulteriori informazioni, consulta ID chiave di monitoraggio).
  • InputRemappingOption: uno di InputEnums.REMAP_OPTION_ENABLED o InputEnums.REMAP_OPTION_DISABLED. Definisce se la funzionalità di rimappatura è attivata.
  • ReservedControls: un elenco di InputControls a cui gli utenti non potranno eseguire la mappatura.

ID chiave traccia

Gli oggetti InputAction, InputGroup, InputContext e InputMap contengono un oggetto InputIdentifier che memorizza un ID numero univoco e un ID versione stringa. Il monitoraggio della versione della stringa degli oggetti è facoltativo, ma consigliato per monitorare le versioni di InputMap. Se la versione della stringa non è specificata, la stringa è vuota. Per gli oggetti InputMap è necessaria una versione di stringa.

L'esempio seguente assegna una versione di stringa a InputActions o 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

Gli ID numero degli oggetti InputAction devono essere univoci per tutti i InputActions nel InputMap. Analogamente, gli ID oggetto InputGroup devono essere univoci per tutti i InputGroups in un InputMap. L'esempio seguente mostra come utilizzare un enum per monitorare gli ID univoci dell'oggetto:

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 contiene i seguenti campi:

  • UniqueId: un ID numerico univoco impostato per identificare in modo chiaro un determinato insieme di dati di input.
  • VersionString: una stringa di versione leggibile da un utente impostata per identificare una versione di dati di input tra due versioni di modifiche ai dati di input.

Ricevere notifiche sugli eventi di rimappatura (facoltativo)

Ricevi notifiche sugli eventi di rimappatura per essere informato sulle chiavi utilizzate nel tuo gioco. In questo modo, il gioco può aggiornare gli asset mostrati sullo schermo del gioco utilizzati per visualizzare i controlli delle azioni.

L'immagine seguente mostra un esempio di questo comportamento: dopo aver rimappato le tasti G, P e S rispettivamente su J, X e T, gli elementi dell'interfaccia utente del gioco vengono aggiornati in modo da mostrare le tasti impostate dall'utente.

Interfaccia utente che reagisce agli eventi di rimappatura utilizzando il callback InputRemappingListener.

Questa funzionalità viene ottenuta registrando un callback InputRemappingListener. Per implementare questa funzionalità, inizia registrando un'istanza di 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

InputRemappingListener viene informato al momento del lancio dopo aver caricato i controlli rimappati salvati dall'utente e dopo ogni volta che l'utente rimappa le chiavi.

Inizializzazione

Se utilizzi InputContexts, imposta il contesto su ogni transizione a una nuova scena, incluso il primo contesto utilizzato per la scena iniziale. Devi impostare InputContext dopo aver registrato InputMap.

Se utilizzi InputRemappingListeners per ricevere notifiche sugli eventi di rimappatura, registrati su InputRemappingListener prima di registrarti su InputMappingProvider, altrimenti il tuo gioco potrebbe perdere eventi importanti durante il lancio.

L'esempio seguente mostra come inizializzare 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
    }
}

Pulizia

Registra la tua istanza InputMappingProvider e eventuali istanze InputRemappingListener quando il gioco è chiuso, anche se l'SDK Input è abbastanza intelligente da evitare la perdita di risorse se non lo fai:

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

Puoi testare l'implementazione dell'SDK Input aprendo manualmente l'overlay per visualizzare l'esperienza del player oppure tramite la shell adb per i test e le verifiche automatici.

L'emulatore di Google Play Giochi su PC controlla la correttezza della mappa di input rispetto agli errori comuni. Per scenari come ID univoci duplicati, utilizzo di mappe di input diverse o errori nelle regole di rimappatura (se la rimappatura è attivata), l'overlay mostra il seguente messaggio di errore: L&#39;overlay dell&#39;SDK Input.

Verifica l'implementazione dell'SDK Input utilizzando adb nella riga di comando. Per ottenere la mappa di input corrente, utilizza il seguente comando adb shell (sostituendoMY.PACKAGE.NAME con il nome della partita):

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

Se hai registrato correttamente il tuo InputMap, vedrai un output simile al seguente:

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
}

Localizzazione

L'SDK Input non utilizza il sistema di localizzazione di Android. Di conseguenza, devi fornire stringhe localizzate quando invii un InputMap. Puoi anche utilizzare il sistema di localizzazione del tuo motore grafico.

Proguard

Quando utilizzi Proguard per ridurre al minimo il tuo gioco, aggiungi le seguenti regole al file di configurazione di Proguard per assicurarti che l'SDK non venga rimosso dal package finale:

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

Passaggio successivo

Dopo aver integrato l'SDK Input nel tuo gioco, puoi continuare con gli eventuali requisiti rimanenti di Google Play Giochi su PC. Per ulteriori informazioni, consulta la guida introduttiva all'utilizzo di Google Play Giochi su PC.