Erste Schritte mit dem Input SDK

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

Vorbereitung

Bevor Sie das Input SDK in Ihr Spiel einbinden, müssen Sie die Eingabe über Tastatur und Maus mit dem Eingabesystem Ihrer Spiele-Engine unterstützen.

Das Input SDK liefert Informationen an Google Play Games auf dem PC darüber, welche Steuerelemente in Ihrem Spiel verwendet werden, damit sie dem Nutzer angezeigt werden können. Optional kann auch die Tastenzuordnung für Nutzer erlaubt werden.

Jede Steuerung ist ein InputAction (z. B. „J“ für „Jump“). Sie organisieren Ihre InputActions in InputGroups. Ein InputGroup kann einen anderen Modus in Ihrem Spiel darstellen, z. B. „Fahren“, „Gehen“ oder „Hauptmenü“. Sie können auch InputContexts verwenden, um anzugeben, welche Gruppen zu verschiedenen Zeitpunkten des Spiels aktiv sind.

Sie können die Tastenzuordnung automatisch vornehmen lassen. Wenn Sie jedoch lieber eine eigene Benutzeroberfläche für die Neuzuordnung von Steuerelementen bereitstellen möchten, können Sie die Neuzuordnung des Input SDK deaktivieren.

Das folgende Sequenzdiagramm beschreibt die Funktionsweise der API des Input SDK:

Ablaufdiagramm einer Spielimplementierung, die die Input SDK API aufruft, und der Interaktion mit dem Android-Gerät.

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

Das Google Play Games auf dem PC-Overlay

Im Google Play Games auf dem PC-Overlay („das Overlay“) werden die von Ihrem Spiel definierten Steuerelemente angezeigt. Nutzer können das Overlay jederzeit durch Drücken von Umschalttaste + Tabulatortaste aufrufen.

Das Google Play Games auf dem PC-Overlay

Best Practices für das Design von Tastenzuweisungen

Beachten Sie beim Entwerfen Ihrer Tastenzuweisungen die folgenden Best Practices:

  • Gruppieren Sie Ihre InputActions in logisch zusammenhängende InputGroups, um die Navigation und Auffindbarkeit der Steuerelemente während des Spiels zu verbessern.
  • Weisen Sie jedes InputGroup höchstens einem InputContext zu. Eine feine Granularität InputMap führt zu einer besseren Navigation in den Steuerelementen im Overlay.
  • Erstellen Sie für jeden unterschiedlichen Szenentyp Ihres Spiels ein InputContext. Normalerweise können Sie ein einzelnes InputContext für alle Szenen verwenden, die wie ein Menü aufgebaut sind. Verwenden Sie verschiedene InputContexts für Minispiele in Ihrem Spiel oder für alternative Steuerelemente für eine einzelne Szene.
  • Wenn für zwei Aktionen derselbe Schlüssel unter demselben InputContext verwendet werden soll, verwenden Sie den Labelstring „Interact / Fire“ (Interagieren / Auslösen).
  • Wenn zwei Tasten an dieselbe InputAction gebunden werden sollen, verwenden Sie zwei verschiedene InputActions, die dieselbe Aktion in Ihrem Spiel ausführen. Sie können denselben Label-String für beide InputActions verwenden, aber die ID muss unterschiedlich sein.
  • Wenn eine Modifikatortaste auf eine Reihe von Tasten angewendet wird, sollten Sie eine einzelne InputAction mit der Modifikatortaste anstelle mehrerer InputActions verwenden, die die Modifikatortaste kombinieren (z. B. Umschalttaste und W, A, S, D anstelle von Umschalttaste + W, Umschalttaste + A, Umschalttaste + S, Umschalttaste + D).
  • Die Eingabezuordnung wird automatisch deaktiviert, wenn der Nutzer Text in Textfelder eingibt. Befolgen Sie die Best Practices für die Implementierung von Android-Textfeldern, damit Android Textfelder in Ihrem Spiel erkennen und verhindern kann, dass neu zugewiesene Tasten sie beeinträchtigen. Wenn in Ihrem Spiel unkonventionelle Textfelder verwendet werden müssen, können Sie setInputContext() mit einem InputContext verwenden, das eine leere Liste von InputGroups enthält, um die Neuzuordnung manuell zu deaktivieren.
  • Wenn dein Spiel das Neubelegen von Tasten unterstützt, solltest du die Tastenbelegung als sensiblen Vorgang betrachten, der mit den vom Nutzer gespeicherten Versionen in Konflikt geraten kann. Vermeiden Sie es nach Möglichkeit, die IDs vorhandener Steuerelemente zu ändern.

Funktion zum Neuzuordnen von Tasten

Google Play Games auf dem PC unterstützt die Neubelegung von Tastatursteuerungen basierend auf den Tastenbelegungen, die Ihr Spiel über das Input SDK bereitstellt. Dies ist optional und kann vollständig deaktiviert werden. Möglicherweise möchten Sie beispielsweise eine eigene Tastaturbelegungsschnittstelle bereitstellen. Wenn Sie die Neubelegung für Ihr Spiel deaktivieren möchten, müssen Sie nur die Option für die Neubelegung für Ihr InputMap deaktivieren (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 Ereignis zum Neubelegen von Tasten ordnet Google Play Games auf dem PC jede vom Nutzer neu belegte Steuerung den Standardsteuerungen zu, die dein Spiel erwartet. Dein Spiel muss also nicht wissen, dass der Spieler Tasten neu belegt hat. Optional können Sie die Assets, die zum Anzeigen der Tastatursteuerung in Ihrem Spiel verwendet werden, aktualisieren, indem Sie einen Callback für das Neuzuordnen von Ereignissen hinzufügen.

Versuchen Sie, die Taste neu zu belegen.

In Google Play Games auf dem PC werden neu zugewiesene Steuerelemente lokal für jeden Nutzer gespeichert, sodass die Steuerung über Gaming-Sitzungen hinweg beibehalten wird. Diese Informationen werden nur für die PC-Plattform auf der Festplatte gespeichert und haben keine Auswirkungen auf die mobile Nutzung. Kontrolldaten werden gelöscht, wenn der Nutzer Google Play Games auf dem PC deinstalliert oder neu installiert. Diese Daten werden nicht auf mehreren PCs gespeichert.

Damit die Funktion zum Neubelegen von Tasten in Ihrem Spiel unterstützt wird, sollten Sie die folgenden Einschränkungen vermeiden:

Einschränkungen bei der Neuzuordnung

Die Funktion zum Neubelegen von Tasten kann in Ihrem Spiel deaktiviert werden, wenn die Tastenbelegungen einen der folgenden Fälle enthalten:

  • Tastenkombinationen aus mehreren Tasten InputActions, die nicht aus einer Modifikatortaste und einer Nicht-Modifikatortaste bestehen. Beispiel: Umschalttaste + A ist gültig, A + B, Strg + Alt oder Umschalttaste + A + Tab hingegen nicht.
  • Das Feld InputMap enthält InputActions, InputGroups oder InputContexts mit wiederholten eindeutigen IDs.

Einschränkungen bei der Neuzuordnung

Beachten Sie beim Entwerfen Ihrer Tastenzuweisungen für die Neubelegung die folgenden Einschränkungen:

  • Das Neubelegen von Tastenkombinationen wird nicht unterstützt. Nutzer können beispielsweise Umschalttaste + A nicht Strg + B oder A nicht Umschalttaste + A zuordnen.
  • Die Neuzuordnung wird für InputActions mit Maustasten nicht unterstützt. Umschalt + Rechtsklick kann beispielsweise nicht neu zugewiesen werden.

Tastenbelegung im Emulator für Google Play Games auf dem PC testen

Sie können die Funktion zum Neubelegen von Tasten jederzeit im Google Play Games auf dem PC-Emulator aktivieren, indem Sie den folgenden ADB-Befehl ausführen:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

Die Änderung des Overlays ist im folgenden Bild zu sehen:

Das Overlay mit aktivierter Tastenbelegung.

SDK hinzufügen

Installieren Sie das Input SDK entsprechend Ihrer Entwicklungsplattform.

Java und Kotlin

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

dependencies {
  implementation 'com.google.android.libraries.play.games:inputmapping:1.1.1-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 unitypackage-Datei des Input SDK mit allen zugehörigen Abhängigkeiten herunter. Sie können das .unitypackage installieren, indem Sie Assets > Import package > Custom Package auswählen und die heruntergeladene Datei suchen.

Mit UPM installieren

Alternativ können Sie das Paket mit dem Unity Package Manager installieren, indem Sie .tgz herunterladen und die zugehörigen Abhängigkeiten installieren:

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 des Input SDK finden Sie im AGDK Tunnel für Kotlin- oder Java-Spiele und in Trivial Kart für Unity-Spiele.

Tastenzuweisungen generieren

Registrieren Sie Ihre Tastenzuweisungen, indem Sie ein InputMap erstellen und es mit einem InputMappingProvider zurückgeben. Das folgende Beispiel zeigt ein InputMappingProvider-Objekt:

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 ein Schlüssel oder eine Tastenkombination einer Spielaktion zugeordnet. InputActions müssen für alle InputActions eindeutige IDs haben.

Wenn Sie die Neuzuordnung unterstützen, können Sie definieren, was neu zugeordnet werden kann.InputActions Wenn Ihr Spiel keine Neubelegung unterstützt, sollten Sie die Option für die Neubelegung für alle Ihre InputActions deaktivieren. Das Input SDK ist jedoch intelligent genug, um die Neubelegung zu deaktivieren, wenn sie in Ihrem InputMap nicht unterstützt wird.

In diesem Beispiel wird der space-Schlüssel der Drive-Aktion 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 InputAction für eine Taste 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
);

Die MouseInputAction, die im Overlay angezeigt wird.

Tastenkombinationen werden angegeben, indem Sie mehrere Tastencodes an Ihr InputAction übergeben. In diesem Beispiel wird Leertaste + Umschalt der Aktion Turbo zugewiesen, was auch dann funktioniert, wenn Leertaste Drive zugewiesen 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
);

Im Overlay wird eine InputAction mit mehreren Tasten angezeigt.

Mit dem Input SDK können Sie Maus- und Tastentasten für eine einzelne Aktion kombinieren. In diesem Beispiel wird gezeigt, dass durch gleichzeitiges Drücken von Umschalt und Rechtsklick in diesem Beispielspiel ein Wegpunkt 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
);

Kombination aus Taste und Maus-InputAction, die im Overlay angezeigt wird.

„InputAction“ hat die folgenden Felder:

  • ActionLabel: Der String, der in der Benutzeroberfläche angezeigt wird, um diese Aktion darzustellen. Die Lokalisierung erfolgt nicht automatisch. Sie müssen sie also im Voraus durchführen.
  • InputControls: Definiert die Eingabesteuerelemente, die von dieser Aktion verwendet werden. Die Steuerelemente sind konsistenten Glyphen im Overlay zugeordnet.
  • InputActionId: InputIdentifier-Objekt, in dem die Nummer-ID und die Version des InputAction gespeichert sind (weitere Informationen finden Sie unter Tracking Key IDs).
  • InputRemappingOption: entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Definiert, ob die Aktion neu zugeordnet werden kann. Wenn Ihr Spiel keine Neubelegung unterstützt, können Sie dieses Feld überspringen oder einfach deaktivieren.
  • RemappedInputControls: schreibgeschütztes InputControls-Objekt zum Lesen des vom Nutzer bei Neuzuordnungsvorgängen festgelegten neu zugeordneten Schlüsselsatzes (wird verwendet, um über Neuzuordnungsvorgänge benachrichtigt zu werden).

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

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

Eingabegruppen definieren

InputActions werden mit logisch zusammenhängenden Aktionen gruppiert, indem InputGroups verwendet wird, um die Navigation und die Auffindbarkeit von Steuerelementen im Overlay zu verbessern. Jede InputGroup-ID muss für alle InputGroups in Ihrem Spiel eindeutig sein.

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

Wenn Sie die Neuzuordnung unterstützen, können Sie definieren, was neu zugeordnet werden kann.InputGroups Wenn Ihr Spiel keine Neubelegung unterstützt, sollten Sie die Option für die Neubelegung für alle Ihre InputGroups deaktivieren. Das Input SDK ist jedoch intelligent genug, um die Neubelegung zu deaktivieren, wenn sie in Ihrem 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ßensteuerung und Menüsteuerung im Overlay angezeigt:

Das Overlay zeigt eine InputMap mit den Eingabegruppen „Road controls“ und „Menu controls“.

InputGroup hat 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 von InputAction-Objekten, die Sie im vorherigen Schritt definieren. Alle diese Aktionen werden unter der Gruppenüberschrift angezeigt.
  • InputGroupId: InputIdentifier-Objekt, in dem die Nummer-ID und die Version des 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, wird die Neuzuordnung für alle InputAction-Objekte dieser Gruppe deaktiviert, auch wenn die Neuzuordnungsoption aktiviert ist. Wenn diese Option aktiviert ist, können alle Aktionen in dieser Gruppe neu zugeordnet werden, sofern sie nicht durch die einzelnen Aktionen deaktiviert wurden.

Eingabekontexte definieren

Mit InputContexts kann Ihr Spiel für verschiedene Szenen unterschiedliche Tastatursteuerungen verwenden. Beispiel:

  • Sie können verschiedene Eingabesätze für die Menünavigation und die Bewegung im Spiel festlegen.
  • Je nach Fortbewegungsart im Spiel, z. B. Fahren oder Gehen, können Sie verschiedene Eingabesätze angeben.
  • Sie können je nach aktuellem Status Ihres Spiels unterschiedliche Eingabesätze angeben, z. B. für die Navigation in einer Oberwelt im Vergleich zum Spielen eines einzelnen Levels.

Bei Verwendung von InputContexts werden im Overlay zuerst die Gruppen des verwendeten Kontexts angezeigt. Rufen Sie setInputContext() auf, um den Kontext festzulegen, wenn Ihr Spiel in eine andere Szene wechselt. Das folgende Bild veranschaulicht dieses Verhalten: In der Szene „Fahren“ werden die Aktionen der Straßensteuerung oben im Overlay angezeigt. Wenn Sie das Menü „Store“ öffnen, werden die Aktionen für die Menüsteuerung oben im Overlay angezeigt.

InputContexts sortieren Gruppen im Overlay.

Diese Overlay-Aktualisierungen werden durch Festlegen eines anderen InputContext an verschiedenen Stellen im Spiel erreicht. Gehen Sie dazu so vor:

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

InputGroups, die zur selbenInputContextgehören, dürfen keine widersprüchlichenInputActionsmit demselben Schlüssel haben. Es empfiehlt sich, jedem InputGroup eine einzelne 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 hat die folgenden Felder:

  • LocalizedContextLabel: Ein String, der die Gruppen beschreibt, die zum Kontext gehören.
  • InputContextId: InputIdentifier-Objekt, in dem die Nummer-ID und die Version des InputContext gespeichert sind (weitere Informationen finden Sie unter Tracking Key IDs).
  • ActiveGroups: Eine Liste der InputGroups, die verwendet und oben im Overlay angezeigt werden sollen, wenn dieser Kontext aktiv ist.

Eingabeübersicht erstellen

Ein InputMap ist eine Sammlung aller InputGroup-Objekte, die in einem Spiel verfügbar sind, und daher aller InputAction-Objekte, die ein Spieler ausführen kann.

Wenn Sie Ihre Tastenzuweisungen melden, erstellen Sie ein InputMap mit allen InputGroups, die in Ihrem Spiel verwendet werden.

Wenn Ihr Spiel keine Neubelegung unterstützt, deaktivieren Sie die Option für die Neubelegung und lassen Sie die reservierten Tasten 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 hat die folgenden Felder:

  • InputGroups: Die von Ihrem Spiel gemeldeten InputGroups. Die Gruppen werden im Overlay in der Reihenfolge angezeigt, in der sie definiert sind, sofern nicht die aktuellen Gruppen mit setInputContext() aufgerufen werden.
  • MouseSettings: Das MouseSettings-Objekt gibt an, dass die Mausempfindlichkeit angepasst werden kann und die Maus auf der Y-Achse invertiert ist.
  • InputMapId: InputIdentifier-Objekt, in dem die Nummer-ID und die Version des InputMap gespeichert sind (weitere Informationen finden Sie unter Tracking Key IDs).
  • InputRemappingOption: entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Gibt an, ob das Remapping-Feature aktiviert ist.
  • ReservedControls: Eine Liste von InputControls, denen Nutzer keine neuen Tastenbelegungen zuweisen dürfen.

Schlüssel-IDs erfassen

Die Objekte InputAction, InputGroup, InputContext und InputMap enthalten ein InputIdentifier-Objekt, in dem eine eindeutige numerische ID und eine String-Versions-ID gespeichert sind. Die String-Version Ihrer Objekte zu erfassen, ist optional, wird aber empfohlen, um die Versionen Ihrer InputMap zu erfassen. Wenn keine String-Version angegeben ist, ist der String leer. Für InputMap-Objekte ist eine String-Version 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 Nummern-IDs von InputAction-Objekten müssen für alle InputActions in Ihrem InputMap eindeutig sein. Ebenso müssen InputGroup-Objekt-IDs für alle InputGroups in einem InputMap eindeutig sein. Im folgenden Beispiel wird gezeigt, wie Sie ein enum verwenden, um die eindeutigen IDs Ihres Objekts zu erfassen:

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 hat die folgenden Felder:

  • UniqueId: Eine eindeutige numerische ID, die einen bestimmten Satz von Eingabedaten eindeutig identifiziert.
  • VersionString: Ein für Menschen lesbarer Versionsstring, der festgelegt ist, um eine Version von Eingabedaten zwischen zwei Versionen von Änderungen an Eingabedaten zu identifizieren.

Benachrichtigungen zu Neuzuordnungsereignissen erhalten (optional)

Sie erhalten Benachrichtigungen zu Neubelegungsereignissen, damit Sie über die in Ihrem Spiel verwendeten Tasten informiert sind. So kann Ihr Spiel die Assets aktualisieren, die auf dem Spielbildschirm angezeigt werden und mit denen die Aktionssteuerelemente dargestellt werden.

Das folgende Bild zeigt ein Beispiel für dieses Verhalten. Nachdem die Tasten G, P und S den Tasten J, X bzw. T zugewiesen wurden, werden die UI-Elemente des Spiels aktualisiert, um die vom Nutzer festgelegten Tasten anzuzeigen.

Die Benutzeroberfläche reagiert auf Neuzuordnungsereignisse mithilfe des InputRemappingListener-Callbacks.

Diese Funktion wird durch die Registrierung eines InputRemappingListener-Rückrufs erreicht. 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

Die InputRemappingListener wird beim Start nach dem Laden der vom Nutzer gespeicherten neu zugewiesenen Steuerelemente und jedes Mal benachrichtigt, wenn der Nutzer seine Tasten neu zuweist.

Initialisierung

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

Wenn Sie InputRemappingListeners verwenden, um über Ereignisse zur Neuzuordnung benachrichtigt zu werden, registrieren Sie InputRemappingListener, bevor Sie InputMappingProvider registrieren. Andernfalls kann es sein, dass Ihr Spiel während der Einführung wichtige Ereignisse verpasst.

Das folgende Beispiel zeigt, 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
    }
}

Bereinigen

Heben Sie die Registrierung Ihrer InputMappingProvider-Instanz und aller InputRemappingListener-Instanzen auf, wenn Ihr Spiel geschlossen wird. Das Input SDK ist jedoch intelligent genug, um Ressourcenlecks zu vermeiden, wenn Sie dies 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 die Player-Oberfläche aufzurufen, oder über die adb-Shell für automatisierte Tests und die Überprüfung.

Der Emulator für Google Play Games auf dem PC prüft die Richtigkeit Ihrer Eingabebelegung anhand häufiger Fehler. Bei Szenarien wie doppelten eindeutigen IDs, der Verwendung unterschiedlicher Eingabekarten oder Fehlern bei den Neuzuordnungsregeln (wenn die Neuzuordnung aktiviert ist) wird im Overlay eine Fehlermeldung wie unten angezeigt: Das Overlay des Input SDK.

Überprüfen Sie Ihre Input SDK-Implementierung mit adb in der Befehlszeile. Verwenden Sie den folgenden adb shell-Befehl, um die aktuelle Eingabebelegung abzurufen (ersetzen Sie MY.PACKAGE.NAME durch den Namen Ihres Spiels):

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

Wenn Sie Ihre InputMap erfolgreich registriert haben, sehen Sie eine Ausgabe wie diese:

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. Daher müssen Sie lokalisierte Strings angeben, wenn Sie ein InputMap einreichen. Sie können auch das Lokalisierungssystem Ihrer Spiel-Engine verwenden.

Proguard

Wenn Sie Proguard zum Minimieren Ihres Spiels verwenden, fügen Sie der Proguard-Konfigurationsdatei die folgenden Regeln hinzu, damit das SDK nicht aus Ihrem 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 Sie das Input SDK in Ihr Spiel eingebunden haben, können Sie mit den verbleibenden Anforderungen für Google Play Games auf dem PC fortfahren. Weitere Informationen finden Sie unter Erste Schritte mit Google Play Games auf dem PC.