Erste Schritte mit dem Input SDK

In diesem Dokument wird beschrieben, wie das Input SDK in Spielen eingerichtet und angezeigt wird, die Google Play Spiele auf dem PC unterstützen. Zu den Aufgaben gehört das Hinzufügen des SDK zu Ihrem Spiel und das Generieren einer Eingabezuordnung, die die Zuweisungen von Spielaktionen an Nutzereingaben enthält.

Vorbereitung

Bevor Sie Ihrem Spiel das Input SDK hinzufügen, müssen Sie die Tastatur- und Mauseingabe über das Eingabesystem der Spiel-Engine unterstützen.

Das Input SDK stellt Google Play Spiele auf dem PC Informationen darüber zur Verfügung, welche Steuerelemente Ihr Spiel verwendet, damit sie dem Nutzer angezeigt werden können. Optional kann die Tastatur auch für Nutzer neu zugeordnet werden.

Jedes Steuerelement ist ein InputAction (z.B. „J“ für „Jump“) und Sie organisieren Ihr InputActions in InputGroups. Ein InputGroup kann einen anderen Modus in deinem Spiel darstellen, z. B. „Fahren“, „Zu Fuß“ oder „Hauptmenü“. Du kannst auch InputContexts verwenden, um anzugeben, welche Gruppen zu verschiedenen Zeitpunkten im Spiel aktiv sind.

Sie können festlegen, dass die Neuzuordnung der Tastatur automatisch für Sie durchgeführt wird. Wenn Sie jedoch eine eigene Schnittstelle für die Neuzuordnung von Steuerelementen bereitstellen möchten, können Sie die Neuzuordnung des Eingabe-SDKs deaktivieren.

Das folgende Sequenzdiagramm beschreibt, wie die API des Input SDK funktioniert:

Sequenzdiagramm einer Spieleimplementierung, die die Input SDK API und ihre Interaktion mit dem Android-Gerät aufruft

Wenn das Input SDK in Ihrem Spiel implementiert ist, werden Ihre Steuerelemente im Overlay von Google Play Spiele auf dem PC angezeigt.

Overlay für Google Play Spiele auf dem PC

Das Overlay von Google Play Spiele auf dem PC („Overlay“) zeigt die von Ihrem Spiel definierten Steuerelemente an. Das Overlay kann jederzeit durch Drücken von Shift + Tabulatortaste aufgerufen werden.

Overlay von Google Play Spiele auf dem PC

Best Practices für das Entwerfen von Schlüsselbindungen

Berücksichtigen Sie beim Entwerfen Ihrer Schlüsselbindungen die folgenden Best Practices:

  • Gruppiere dein InputActions in logisch zusammengehörige InputGroups, um die Navigation und die Sichtbarkeit der Steuerelemente während des Spiels zu verbessern.
  • Weisen Sie jedes InputGroup maximal einem InputContext zu. Ein feines Detail des InputMap ermöglicht eine einfachere Navigation der Steuerelemente im Overlay.
  • Erstelle eine InputContext für jeden Szenentyp deines Spiels. In der Regel können Sie für alle Ihre „menüähnlichen“ Szenen eine einzelne InputContext verwenden. Verwende unterschiedliche InputContexts für alle Minispiele in deinem Spiel oder für alternative Steuerelemente für eine einzelne Szene.
  • Wenn zwei Aktionen denselben Schlüssel unter demselben InputContext verwenden sollen, verwenden Sie den Labelstring, z. B. „Interagieren / feuer“.
  • Wenn zwei Schlüssel an dasselbe InputAction gebunden werden sollen, verwenden Sie zwei verschiedene InputActions, die die gleiche Aktion in Ihrem Spiel ausführen. Sie können für beide InputActions denselben Labelstring verwenden, die ID muss jedoch unterschiedlich sein.
  • Wenn eine Modifikatortaste auf eine Gruppe von Tasten angewendet wird, sollten Sie statt mehrerer InputActions mit der Modifikatortaste ein einzelnes InputAction mit der Modifikatortaste verwenden. Verwenden Sie beispielsweise Umschalttaste und W, A, S, D statt Umschalttaste + W, Umschalttaste + A, Umschalttaste + S, Umschalttaste + D.
  • Die Neuzuordnung von Eingaben wird automatisch deaktiviert, wenn der Nutzer in Textfelder schreibt. Beachten Sie die Best Practices für die Implementierung von Android-Textfeldern. So sorgen Sie dafür, dass Android Textfelder in Ihrem Spiel erkennen kann und nicht durch neu zugeordnete Schlüssel beeinträchtigt wird. Wenn in Ihrem Spiel nicht-konventionelle Textfelder verwendet werden müssen, können Sie setInputContext() mit einem InputContext verwenden, das eine leere Liste mit InputGroups enthält, um die Neuzuordnung manuell zu deaktivieren.
  • Wenn Ihr Spiel Neuzuordnungen unterstützt, sollten Sie Ihre Tastenkombinationen aktualisieren. Dies ist ein sensibler Vorgang, der mit den vom Nutzer gespeicherten Versionen in Konflikt stehen kann. Ändern Sie die IDs vorhandener Steuerelemente nach Möglichkeit nicht.

Die Funktion für die Neuzuordnung von Karteninhalten

Google Play Spiele auf dem PC unterstützt die Neuzuordnung der Tastatursteuerung basierend auf den Tastenkombination, die dein Spiel über das Input SDK bereitstellt. Dies ist optional und kann vollständig deaktiviert werden. Sie können beispielsweise eine eigene Oberfläche für die Neuzuordnung der Tastatur bereitstellen. Wenn Sie die Neuzuordnung für Ihr Spiel deaktivieren möchten, müssen Sie nur die Option für die Neuzuordnung festlegen, die für InputMap deaktiviert ist. Weitere Informationen finden Sie unter InputMap erstellen.

Um auf diese Funktion zuzugreifen, müssen Nutzer das Overlay öffnen und dann auf die Aktion klicken, die sie neu zuordnen möchten. Nach jedem Neuzuordnungsereignis wird in Google Play Spiele auf dem PC jedem Nutzer eine neue Steuerung der Standardsteuerelemente zugewiesen, die Ihr Spiel erwarten soll. Ihr Spiel muss also die Neuzuordnungen des Spielers nicht erkennen. Du kannst optional die Assets aktualisieren, die zum Anzeigen der Tastatursteuerung in deinem Spiel verwendet werden. Füge dazu einen Callback für die Neuzuordnung von Ereignissen hinzu.

Versuchen, die Taste neu zuzuordnen

Google Play Spiele auf dem PC speichert neu zugeordnete Steuerelemente lokal für jeden Nutzer, sodass die Steuerung über Spielesitzungen hinweg aufrechterhalten werden kann. Diese Informationen werden nur für die PC-Plattform auf dem Laufwerk gespeichert und haben keine Auswirkungen auf die mobile Nutzung. Kontrolldaten werden gelöscht, wenn der Nutzer Google Play Spiele auf dem PC deinstalliert oder neu installiert. Diese Daten werden nicht über mehrere PC-Geräte hinweg gespeichert.

Damit die Funktion zur Neuzuordnung in Ihrem Spiel unterstützt wird, müssen Sie die folgenden Einschränkungen beachten:

Einschränkungen bei der Neuzuordnung

Die Funktionen zur Neuzuordnung von Elementen können in Ihrem Spiel deaktiviert werden, wenn die Tastenkombination eine der folgenden Fälle enthält:

  • InputActions mit mehreren Schlüsseln, die nicht aus einer Modifikatortaste und einem Nicht-Modifikatorschlüssel bestehen. Beispielsweise ist Umschalttaste + A gültig, A + B, Strg + Alt oder Umschalttaste + A + Tabulatortaste jedoch nicht.
  • InputMap enthält InputActions, InputGroups oder InputContexts mit wiederholten eindeutigen IDs.

Einschränkungen der Neuzuordnung

Berücksichtigen Sie beim Entwerfen Ihrer Schlüsselbindungen für die Neuzuordnung die folgenden Einschränkungen:

  • Eine Neuzuordnung zu Tastenkombinationen wird nicht unterstützt. Beispielsweise können Nutzer Umschalttaste + A nicht zu Strg + B oder A zu Umschalttaste + A zuordnen.
  • Die Neuzuordnung wird für InputActions mit Maustasten nicht unterstützt. Umschalttaste + Rechtsklick kann beispielsweise nicht neu zugeordnet werden.

Neuzuordnung von Tasten im Emulator für Google Play Spiele auf dem PC testen

Sie können die Funktion für die Neuzuordnung im Emulator für Google Play Spiele auf dem PC jederzeit mit dem folgenden ADB-Befehl aktivieren:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

Das Overlay ändert sich wie in der folgenden Abbildung:

Das Overlay mit aktivierter Tastenneuzuordnung.

SDK hinzufügen

Installieren Sie das Input SDK entsprechend Ihrer Entwicklungsplattform.

Java und Kotlin

Rufen Sie das Input SDK für Java oder Kotlin ab, indem Sie der Datei build.gradle auf Modulebene eine Abhängigkeit hinzufügen:

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

Unity

Das Input SDK ist ein Standard-Unity-Paket mit mehreren Abhängigkeiten.

Das Paket muss mit allen Abhängigkeiten installiert werden. Es gibt mehrere Möglichkeiten, die Pakete zu installieren.

.unitypackage installieren

Laden Sie die Input SDK-Unitypackage-Datei mit allen Abhängigkeiten herunter. Sie können .unitypackage installieren, indem Sie Assets > Paket importieren > Benutzerdefiniertes Paket auswählen und nach der heruntergeladenen Datei suchen.

Mit UPM installieren

Alternativ können Sie das Paket mit dem Unity's Package Manager installieren. Laden Sie dazu die .tgz herunter und installieren Sie die zugehörigen Abhängigkeiten:

Mit OpenUPM installieren

Sie können das Paket mit OpenUPM installieren.

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

Beispielspiele

Beispiele für die Integration mit dem Input SDK finden Sie unter AGDK-Tunnel für Kotlin- oder Java-Spiele und Trivial Kart für Unity-Spiele.

Schlüsselbindungen generieren

Registrieren Sie Ihre Schlüsselbindungen, indem Sie ein InputMap erstellen und mit einem InputMappingProvider zurückgeben. Im folgenden Beispiel wird ein InputMappingProvider dargestellt:

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

Eingabeaktionen definieren

Mit der Klasse InputAction wird einer Spielaktion ein Schlüssel oder eine Schlüsselkombination zugeordnet. InputActions muss in allen InputActions eindeutige IDs haben.

Wenn Sie die Neuzuordnung unterstützen, können Sie definieren, welche InputActions neu zugeordnet werden können. Wenn Ihr Spiel Neuzuordnungen nicht unterstützt, sollten Sie die Option für die Neuzuordnung für alle InputActions deaktivieren. Das Input SDK ist jedoch so intelligent, dass die Neuzuordnung deaktiviert wird, wenn sie in InputMap nicht unterstützt wird.

In diesem Beispiel wird der Schlüssel Leertaste der Aktion Drive zugeordnet.

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

Im Overlay wird eine einzelne Taste „InputAction“ angezeigt.

Aktionen können auch Mauseingaben darstellen. In diesem Beispiel wird Linksklick auf die Aktion Verschieben festgelegt:

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

MauseingabeAktion im Overlay.

Für Tastenkombinationen werden mehrere Schlüsselcodes an die InputAction übergeben. In diesem Beispiel wird Leertaste + Umschalttaste der Aktion Turbo zugeordnet. Diese funktioniert auch dann, wenn Leertaste der Aktion Drive zugeordnet ist.

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

Die Eingabeaktion mit mehreren Tasten wird im Overlay angezeigt.

Mit dem Input SDK können Sie Maus- und Tastentasten zu einer einzigen Aktion kombinieren. Dieses Beispiel zeigt an, dass durch gleichzeitiges Drücken von Umschalt und Rechtsklick ein Wegpunkt in diesem Beispielspiel hinzugefügt wird:

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

Im Overlay angezeigte Kombination aus Taste + Maus und InputAction.

InputAction enthält die folgenden Felder:

  • ActionLabel: String, der in der UI für diese Aktion angezeigt wird. Die Lokalisierung erfolgt nicht automatisch. Sie sollten sie daher vorab durchführen.
  • InputControls: definiert die Eingabesteuerelemente, die von dieser Aktion verwendet werden. Die Steuerelemente werden konsistenten Symbolen im Overlay zugeordnet.
  • InputActionId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version von InputAction gespeichert sind. Weitere Informationen finden Sie unter Tracking-Schlüssel-IDs.
  • InputRemappingOption: entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Definiert, ob die Aktion für die Neuzuordnung aktiviert wird. Wenn Ihr Spiel keine Neuzuordnungen unterstützt, können Sie dieses Feld überspringen oder es einfach deaktivieren.
  • RemappedInputControls: schreibgeschütztes InputControls-Objekt zum Lesen des neu zugeordneten Schlüssels, der vom Nutzer bei der Neuzuordnung von Ereignissen festgelegt wurde. Wird verwendet, um Benachrichtigungen über Neuzuordnungen von Ereignissen zu erhalten.

InputControls steht für die einer Aktion zugeordneten Eingaben und enthält die folgenden Felder:

  • AndroidKeycodes: ist eine Liste von Ganzzahlen, die die Tastatureingaben für eine Aktion darstellen. Diese werden in der Klasse KeyEvent oder der Klasse AndroidKeycode für Unity definiert.
  • MouseActions: ist eine Liste von MouseAction-Werten, die Mauseingaben für diese Aktion darstellen.

Eingabegruppen definieren

InputActions werden mithilfe von InputGroups mit logisch zusammenhängenden Aktionen gruppiert, um die Navigation zu verbessern und die Sichtbarkeit im Overlay zu steuern. Jede InputGroup-ID muss in allen InputGroups in deinem Spiel eindeutig sein.

Wenn Sie Ihre Eingabeaktionen in Gruppen organisieren, können Spieler leichter die richtige Tastenkombination für ihren aktuellen Kontext finden.

Wenn Sie die Neuzuordnung unterstützen, können Sie definieren, welche InputGroups neu zugeordnet werden können. Wenn Ihr Spiel Neuzuordnungen nicht unterstützt, sollten Sie die Option für die Neuzuordnung für alle InputGroups deaktivieren. Das Input SDK ist jedoch so intelligent, dass die Neuzuordnung deaktiviert wird, wenn sie in InputMap nicht unterstützt wird.

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

Im folgenden Beispiel werden die Eingabegruppen Straßensteuerelemente und Menüsteuerelemente im Overlay angezeigt:

Das Overlay mit einer InputMap, das die Straßensteuerelemente und die Menüsteuerelemente in die Eingabegruppen enthält.

InputGroup enthält die folgenden Felder:

  • GroupLabel: Ein String, der im Overlay angezeigt wird und mit dem eine Reihe von Aktionen logisch gruppiert werden kann. Dieser String wird nicht automatisch lokalisiert.
  • InputActions: eine Liste der InputAction-Objekte, die Sie im vorherigen Schritt definiert haben. All diese Aktionen werden unter der Überschrift der Gruppe angezeigt.
  • InputGroupId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version von InputGroup gespeichert sind. Weitere Informationen finden Sie unter Tracking-Schlüssel-IDs.
  • InputRemappingOption: entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Wenn diese Option deaktiviert ist, ist die Neuzuordnung für alle InputAction-Objekte in dieser Gruppe deaktiviert, selbst wenn deren Option für die Neuzuordnung aktiviert ist. Wenn diese Option aktiviert ist, können alle Aktionen, die zu dieser Gruppe gehören, neu zugeordnet werden können, sofern dies nicht durch die einzelnen Aktionen deaktiviert wurde.

Eingabekontexte definieren

Mit InputContexts kann dein Spiel unterschiedliche Tastatursteuerelemente für verschiedene Szenen deines Spiels verwenden. Beispiele:

  • Sie können für Navigationsmenüs andere Sätze von Eingaben angeben als für das Bewegen im Spiel.
  • Je nach Fortbewegungsmodus in Ihrem Spiel können Sie verschiedene Gruppen von Eingaben angeben, z. B. Autofahren oder Gehen.
  • Sie können je nach aktuellem Spielstand unterschiedliche Sätze von Eingaben angeben, z. B. das Navigieren durch eine Überwelt oder das Spielen eines einzelnen Levels.

Bei Verwendung von InputContexts werden im Overlay zuerst die Gruppen des verwendeten Kontexts angezeigt. Wenn Sie dieses Verhalten aktivieren möchten, rufen Sie setInputContext() auf. Damit wird der Kontext immer dann festgelegt, wenn Ihr Spiel eine andere Szene beginnt. Das wird in der folgenden Abbildung veranschaulicht: Beim Fahren sind die Aktionen der Straßensteuerelemente oben im Overlay zu sehen. Beim Öffnen des Menüs „Shop“ sind die Aktionen für die Menüsteuerelemente oben im Overlay zu sehen.

InputContexts, das Gruppen im Overlay sortiert

Um diese Overlay-Updates zu aktualisieren, legst du an verschiedenen Punkten im Spiel eine andere InputContext fest. Aktion:

  1. InputActions mithilfe von InputGroups mit logisch zusammenhängenden Aktionen gruppieren
  2. Weisen Sie diese InputGroups einem InputContext für die verschiedenen Teile Ihres Spiels zu.

InputGroups, die zum selben InputContext gehören, dürfen keine widersprüchlichen InputActions haben, wenn derselbe Schlüssel verwendet wird. Es empfiehlt sich, jede InputGroup einer einzelnen InputContext zuzuweisen.

Der folgende Beispielcode veranschaulicht die InputContext-Logik:

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 enthält die folgenden Felder:

  • LocalizedContextLabel: ein String, der die Gruppen beschreibt, die zum Kontext gehören.
  • InputContextId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version von InputContext gespeichert sind. Weitere Informationen finden Sie unter Tracking-Schlüssel-IDs.
  • ActiveGroups: Eine Liste von InputGroups, die verwendet und oben im Overlay angezeigt wird, wenn dieser Kontext aktiv ist.

Eingabezuordnung erstellen

Ein InputMap ist eine Sammlung aller InputGroup-Objekte, die in einem Spiel verfügbar sind. Daher sind alle InputAction-Objekte, die ein Spieler erwarten kann, zusammengefasst.

Wenn du deine Schlüsselbindungen meldest, erstellst du ein InputMap mit allen in deinem Spiel verwendeten InputGroups.

Wenn Ihr Spiel keine Neuzuordnungen unterstützt, deaktivieren Sie die Option für die Neuzuordnung und lassen Sie die reservierten Schlüssel leer.

Im folgenden Beispiel wird ein InputMap erstellt, mit dem eine Sammlung von InputGroups gemeldet wird.

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 enthält die folgenden Felder:

  • InputGroups: die von deinem Spiel gemeldeten InputGroups. Die Gruppen werden im Overlay der Reihe nach angezeigt, sofern nicht die aktuellen Gruppen angegeben sind, die zum Aufrufen von setInputContext() verwendet werden.
  • MouseSettings: Das MouseSettings-Objekt gibt an, dass die Mausempfindlichkeit angepasst werden kann und dass die Maus um die y-Achse umgekehrt wird.
  • InputMapId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version von InputMap gespeichert sind. Weitere Informationen finden Sie unter Tracking-Schlüssel-IDs.
  • InputRemappingOption: entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Definiert, ob die Funktion für die Neuzuordnung aktiviert ist.
  • ReservedControls: eine Liste von InputControls, denen Nutzer nicht neu zuordnen dürfen.

Tracking-Schlüssel-IDs

Die Objekte InputAction, InputGroup, InputContext und InputMap enthalten ein InputIdentifier-Objekt, das eine eindeutige Nummern-ID und eine String-Versions-ID speichert. Das Tracking der Stringversion Ihrer Objekte ist optional, wird jedoch empfohlen, um die Versionen Ihrer InputMap zu erfassen. Wenn keine Stringversion angegeben ist, ist der String leer. Für InputMap-Objekte ist eine Stringversion erforderlich.

Im folgenden Beispiel wird InputActions oder InputGroups eine Stringversion zugewiesen:

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

Die IDs von InputAction-Objekten müssen in allen InputActions in Ihrer InputMap eindeutig sein. Ebenso müssen InputGroup-Objekt-IDs in allen InputGroups in einem InputMap eindeutig sein. Im folgenden Beispiel wird gezeigt, wie Sie mit einem enum die eindeutigen IDs Ihres Objekts verfolgen:

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 enthält die folgenden Felder:

  • UniqueId: Eine eindeutige Nummern-ID, die einen bestimmten Satz von Eingabedaten eindeutig identifiziert.
  • VersionString: Ein menschenlesbarer Versionsstring, der festgelegt ist, um eine Version von Eingabedaten zwischen zwei Versionen von Eingabedatenänderungen zu identifizieren.

Benachrichtigung bei Neuzuordnung von Ereignissen erhalten (optional)

Du erhältst Benachrichtigungen zu Neuzuordnungsereignissen, um über die in deinem Spiel verwendeten Schlüssel informiert zu werden. Dadurch kann dein Spiel die Assets aktualisieren, die auf dem Spielbildschirm angezeigt werden, mit dem die Aktionssteuerung angezeigt wird.

Die folgende Abbildung zeigt ein Beispiel für dieses Verhalten, bei dem nach der Neuzuordnung der Schlüssel G, P und S zu J, X und T die UI-Elemente des Spiels aktualisiert werden, um die vom Nutzer festgelegten Schlüssel anzuzeigen.

Benutzeroberfläche, die auf die Neuzuordnung von Ereignissen mit dem InputRemappingListener-Callback reagiert

Um diese Funktion zu nutzen, wird ein InputRemappingListener-Callback registriert. Registrieren Sie zuerst eine InputRemappingListener-Instanz, um diese Funktion zu implementieren:

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

Der InputRemappingListener wird beim Start nach dem Laden der vom Nutzer gespeicherten neu zugeordneten Steuerelemente und jedes Mal benachrichtigt, wenn der Nutzer seine Schlüssel neu zuordnet.

Initialisierung

Wenn Sie InputContexts verwenden, legen Sie den Kontext bei jedem Übergang zu einer neuen Szene fest, einschließlich des ersten Kontexts, der für Ihre ursprüngliche Szene verwendet wird. Sie müssen die InputContext festlegen, nachdem Sie InputMap registriert haben.

Wenn Sie InputRemappingListeners verwenden, um über Neuzuordnungen von Ereignissen benachrichtigt zu werden, registrieren Sie Ihre InputRemappingListener, bevor Sie Ihre InputMappingProvider registrieren. Andernfalls kann Ihr Spiel während der Startzeit wichtige Ereignisse verpassen.

Im folgenden Beispiel wird gezeigt, wie die API initialisiert wird:

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

Aufräumen

Heben Sie die Registrierung Ihrer InputMappingProvider-Instanz und aller InputRemappingListener-Instanzen auf, wenn das Spiel geschlossen ist. Das Input SDK ist jedoch intelligent genug, um die Offenlegung von Ressourcen zu vermeiden, wenn Sie das nicht tun:

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

Sie können Ihre Input SDK-Implementierung testen, indem Sie das Overlay manuell öffnen, um das Spielerlebnis zu sehen, oder über die ADB-Shell für automatisierte Tests und Überprüfungen.

Der Emulator für Google Play Spiele auf dem PC prüft die Richtigkeit Ihrer Eingabezuordnung auf häufige Fehler. Für Szenarien wie doppelte eindeutige IDs, die Verwendung unterschiedlicher Eingabezuordnungen oder Fehler bei den Regeln für die Neuzuordnung (wenn die Neuzuordnung aktiviert ist), wird im Overlay eine Fehlermeldung wie unten angezeigt: Das Input SDK-Overlay

Prüfen Sie Ihre Input SDK-Implementierung mithilfe von adb in der Befehlszeile. Verwenden Sie den folgenden adb shell-Befehl, um die aktuelle Eingabezuordnung zu erhalten. Ersetzen Sie dabei MY.PACKAGE.NAME durch den Namen Ihres Spiels:

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

Wenn Sie InputMap erfolgreich registriert haben, sieht die Ausgabe in etwa so aus:

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
}

Lokalisierung

Das Input SDK verwendet nicht das Lokalisierungssystem von Android. Deshalb musst du lokalisierte Strings angeben, wenn du ein InputMap einreichst. Sie können auch das Lokalisierungssystem Ihrer Spiel-Engine verwenden.

Proguard

Wenn Sie Ihr Spiel mit Proguard komprimieren, fügen Sie der Proguard-Konfigurationsdatei die folgenden Regeln hinzu, damit das SDK nicht aus dem endgültigen Paket entfernt wird:

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

Nächste Schritte

Nachdem du das Input SDK in dein Spiel integriert hast, kannst du mit allen verbleibenden Anforderungen für Google Play Spiele auf dem PC fortfahren. Weitere Informationen findest du unter Erste Schritte mit Google Play Spiele auf dem PC.