Erste Schritte mit dem Input SDK

In diesem Dokument wird beschrieben, wie Sie das Input SDK in Spielen einrichten und anzeigen, die Google Play Spiele auf dem PC unterstützen. Dazu gehört, das SDK Ihrem Spiel hinzuzufügen und eine Eingabekarte zu generieren, die die Zuweisungen von Spielaktionen zu Nutzereingaben enthält.

Vorbereitung

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

Das Input SDK stellt Google Play Spiele auf dem PC Informationen zu den Steuerelementen Ihres Spiels zur Verfügung, damit sie den Nutzern angezeigt werden können. Optional kann auch die Tastenbelegung für Nutzer neu festgelegt werden.

Jedes Steuerelement ist ein InputAction (z.B. „J“ für „Springen“) und Sie organisieren Ihre InputActions in InputGroups. Ein InputGroup kann einen anderen Modus in Ihrem Spiel darstellen, z. B. „Autofahren“, „Zu Fuß gehen“ oder „Hauptmenü“. Mit InputContexts können Sie auch angeben, welche Gruppen zu verschiedenen Zeitpunkten des Spiels aktiv sind.

Sie können die automatische Tastaturzuordnung aktivieren. Wenn Sie lieber eine eigene Benutzeroberfläche für die Tastenzuordnung bereitstellen möchten, können Sie die Input SDK-Zuordnung deaktivieren.

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

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

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

Overlay von Google Play Spiele auf dem PC

Im Overlay von Google Play Spiele auf dem PC („das Overlay“) werden die von Ihrem Spiel definierten Steuerelemente angezeigt. Nutzer können das Overlay jederzeit aufrufen, indem sie die Umschalttaste + Tabulatortaste drücken.

Das Overlay von Google Play Spiele auf dem PC

Best Practices für die Gestaltung von Tastenkombinationen

Beachten Sie beim Entwerfen Ihrer Tastenkombinationen 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 jeder InputGroup höchstens eine InputContext zu. Eine detaillierte InputMap sorgt für eine bessere Navigation durch die Steuerelemente im Overlay.
  • Erstellen Sie eine InputContext für jeden Szenentyp in Ihrem Spiel. Normalerweise können Sie für alle „menüartigen“ Szenen eine einzige InputContext verwenden. Verwenden Sie unterschiedliche InputContexts für Minispiele in Ihrem Spiel oder für alternative Steuerelemente für eine einzelne Szene.
  • Wenn zwei Aktionen denselben Schlüssel unter derselben InputContext verwenden sollen, verwenden Sie den Label-String, z. B. „Interagieren / Ausführen“.
  • Wenn zwei Tasten an dieselbe InputAction gebunden sind, verwenden Sie zwei unterschiedliche InputActions, die dieselbe Aktion in Ihrem Spiel ausführen. Sie können für beide InputActions-Elemente denselben Labelstring verwenden, die ID muss jedoch unterschiedlich sein.
  • Wenn eine Modifikatortaste auf eine Gruppe von Tasten angewendet wird, sollten Sie eine einzelne InputAction mit der Modifikatortaste verwenden, anstatt mehrere InputActions, die die Modifikatortaste kombinieren. Beispiel: Verwenden Sie Umschalttaste und W, A, S, D anstelle von Umschalttaste + W, Umschalttaste + A, Umschalttaste + S, Umschalttaste + D.
  • Die Eingabeumwandlung 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 belegte Tasten die Funktion beeinträchtigen. Wenn in Ihrem Spiel nicht konventionelle Textfelder verwendet werden müssen, können Sie setInputContext() mit einem InputContext mit einer leeren Liste von InputGroups verwenden, um die Neuzuordnung manuell zu deaktivieren.
  • Wenn Ihr Spiel die Neuzuordnung unterstützt, sollten Sie die Tastenkombinationen mit Bedacht aktualisieren, da es zu Konflikten mit den vom Nutzer gespeicherten Versionen kommen kann. Ändern Sie nach Möglichkeit nicht die IDs vorhandener Steuerelemente.

Die Funktion zum Neuzuordnen

Google Play Spiele auf dem PC unterstützt die Umordnung der Tastatursteuerung basierend auf den Tastenkombinationen, die Ihr Spiel über das Input SDK bereitstellt. Diese Funktion ist optional und kann vollständig deaktiviert werden. Beispielsweise können Sie eine eigene Oberfläche für die Tastaturbelegung bereitstellen. Wenn Sie die Neuzuordnung für Ihr Spiel deaktivieren möchten, müssen Sie lediglich die Option „Neuzuordnung“ für Ihre 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 Neuzuordnungsereignis ordnet Google Play Spiele auf dem PC jede vom Nutzer neu zugewiesene Steuerung den Standardsteuerelementen zu, die Ihr Spiel erwartet. Ihr Spiel muss also nicht über die Neuzuordnung des Spielers informiert werden. Optional können Sie die Assets aktualisieren, die für die Anzeige der Tastatursteuerung in Ihrem Spiel verwendet werden, indem Sie einen Callback für die Neuzuordnung von Ereignissen hinzufügen.

Taste neu zuordnen

In Google Play Spiele auf dem PC werden neu zugewiesene Steuerelemente lokal für jeden Nutzer gespeichert, sodass die Steuerelemente über mehrere Gaming-Sitzungen hinweg erhalten bleiben. 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 sind nicht auf mehreren PCs verfügbar.

Beachten Sie die folgenden Einschränkungen, um die Funktion zum Neuzuordnen in Ihrem Spiel zu unterstützen:

Einschränkungen bei der Neuzuordnung

Die Funktionen zum Neuverknüpfen von Tasten können in Ihrem Spiel deaktiviert werden, wenn die Tastenkombinationen einen der folgenden Fälle enthalten:

  • Mehrere Tasten InputActions, die nicht aus einer Modifikatortaste und einer anderen Taste bestehen. Umschalttaste + A ist beispielsweise zulässig, A + B, Strg + Alt oder Umschalttaste + A + Tabulatortaste hingegen nicht.
  • InputMap enthält InputActions, InputGroups oder InputContexts mit wiederholten eindeutigen IDs.

Einschränkungen bei der Neuzuordnung

Beachten Sie beim Erstellen von Tastenkombinationen für die Neuzuordnung die folgenden Einschränkungen:

  • Die Umwandlung in Tastenkombinationen wird nicht unterstützt. So können Nutzer beispielsweise Umschalttaste + A nicht auf Strg + B oder A auf Umschalttaste + A umlegen.
  • Die Neuzuordnung wird für InputActions mit Mausschaltflächen nicht unterstützt. Umschalt + Rechtsklick kann beispielsweise nicht neu belegt werden.

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

Sie können die Neuzuordnungsfunktion in Google Play Spiele auf dem PC-Emulator jederzeit aktivieren, indem Sie den folgenden adb-Befehl ausführen:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

Das Overlay ändert sich wie im folgenden Bild:

Das Overlay mit aktivierter Tastenbelegung

SDK hinzufügen

Installieren Sie das Input SDK entsprechend Ihrer Entwicklungsplattform.

Java und Kotlin

Sie können das Input SDK für Java oder Kotlin herunterladen, indem Sie der Datei build.gradle 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

Lade die Unity-Paketdatei des Eingabe-SDKs mit allen zugehörigen Abhängigkeiten herunter. Sie können die .unitypackage installieren, indem Sie Assets > Paket importieren > Benutzerdefiniertes Paket 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 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 Einbindung in das Input SDK finden Sie unter AGDK Tunnel für Kotlin- oder Java-Spiele und Trivial Kart für Unity-Spiele.

Tastenkombinationen generieren

Registrieren Sie Ihre Tastenkombinationen, indem Sie einen InputMap erstellen und mit einem InputMappingProvider zurückgeben. Im folgenden Beispiel wird eine 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 eine Taste oder Tastenkombination einer Spielaktion zugeordnet. InputActions müssen für alle InputActions eindeutige IDs haben.

Wenn Sie die Neuzuordnung unterstützen, können Sie festlegen, welche InputActions neu zugeordnet werden können. Wenn dein Spiel die Tastenbelegung nicht unterstützt, solltest du die Option für alle InputActions deaktivieren. Das Input SDK ist jedoch intelligent genug, um die Tastenbelegung zu deaktivieren, wenn du sie in deinen InputActions nicht unterstützt.InputMap

In diesem Beispiel wird der Schlüssel space 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 Tastenaktion angezeigt.

Aktionen können auch Mauseingaben darstellen. In diesem Beispiel wird Linksklick für 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
);

Im Overlay angezeigte Mauseingabeaktion.

Tastenkombinationen werden angegeben, indem mehrere Tastencodes an InputAction übergeben werden. In diesem Beispiel ist Leertaste + Umschalttaste der Aktion Turbo zugewiesen. Diese Aktion funktioniert auch dann, wenn Leertaste der Aktion Fahren 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
);

Mehrere Tasten für die InputAction, die im Overlay angezeigt werden.

Mit dem Input SDK können Sie Maus- und Tastenkombinationen für eine einzelne Aktion kombinieren. In diesem Beispiel wird angezeigt, dass durch gleichzeitiges Drücken der Tasten 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 Mauseingabeaktion, die im Overlay angezeigt wird.

„InputAction“ hat die folgenden Felder:

  • ActionLabel: Der String, der in der Benutzeroberfläche für diese Aktion angezeigt wird. Die Lokalisierung erfolgt nicht automatisch. Führen Sie sie daher im Voraus durch.
  • InputControls: Hier werden die Eingabesteuerelemente für diese Aktion definiert. Die Steuerelemente werden den einheitlichen Schriftzeichen im Overlay zugeordnet.
  • InputActionId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version der InputAction gespeichert werden (weitere Informationen finden Sie unter Tracking-Schlüssel-IDs).
  • InputRemappingOption: Entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Gibt an, ob die Aktion für die Neuzuordnung aktiviert ist. Wenn Ihr Spiel die Neuzuordnung nicht unterstützt, können Sie dieses Feld überspringen oder einfach deaktivieren.
  • RemappedInputControls: Schreibgeschütztes InputControls-Objekt, mit dem der vom Nutzer bei Neuzuordnungsereignissen festgelegte neu zugeordnete Schlüssel gelesen wird (wird verwendet, um über Neuzuordnungsereignisse 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 Klasse AndroidKeycode für Unity definiert.
  • MouseActions: Eine Liste von MouseAction-Werten, die die mit dieser Aktion verbundenen Mauseingaben darstellen.

Eingabegruppen definieren

InputActions werden mit logisch zusammenhängenden Aktionen gruppiert, um die Navigation und die Sichtbarkeit der Steuerelemente im Overlay zu verbessern.InputGroups 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 Tastenkombination für ihren aktuellen Kontext leichter finden.

Wenn Sie die Neuzuordnung unterstützen, können Sie festlegen, welche InputGroups neu zugeordnet werden können. Wenn dein Spiel die Tastenbelegung nicht unterstützt, solltest du die Option für alle InputGroups deaktivieren. Das Input SDK ist jedoch intelligent genug, um die Tastenbelegung zu deaktivieren, wenn du sie in deinen InputGroups nicht unterstützt.InputMap

Kotlin

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

Java

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

C#

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

Im folgenden Beispiel sind die Eingabegruppen Straßenelemente und Menüelemente im Overlay zu sehen:

Das Overlay mit einer InputMap, die die Eingabegruppen für die Straßen- und Menüsteuerelemente enthält.

InputGroup hat die folgenden Felder:

  • GroupLabel: Ein String, der im Overlay angezeigt wird und mit dem sich eine Reihe von Aktionen logisch gruppieren lässt. Dieser String wird nicht automatisch lokalisiert.
  • InputActions: Eine Liste von InputAction-Objekten, die Sie im vorherigen Schritt definiert haben. Alle diese Aktionen werden unter der Gruppenüberschrift angezeigt.
  • InputGroupId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version der InputGroup gespeichert werden. 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 Option für die Neuzuordnung aktiviert ist. Wenn diese Option aktiviert ist, können alle zu dieser Gruppe gehörenden Aktionen neu zugeordnet werden, sofern dies nicht für die einzelnen Aktionen angegeben ist.

Eingabekontexte definieren

InputContexts ermöglicht es, für verschiedene Szenen des Spiels unterschiedliche Tastatursteuerungen zu verwenden. Beispiel:

  • Sie können unterschiedliche Eingaben für die Menünavigation und die Bewegung im Spiel festlegen.
  • Je nach Fortbewegungsart in Ihrem Spiel können Sie unterschiedliche Eingaben angeben, z. B. für das Fahren oder Gehen.
  • Je nach aktuellem Status des Spiels können Sie unterschiedliche Eingaben angeben, z. B. für die Navigation in einer Überwelt oder für das Spielen eines einzelnen Levels.

Wenn Sie InputContexts verwenden, werden im Overlay zuerst die Gruppen des verwendeten Kontexts angezeigt. Wenn du dieses Verhalten aktivieren möchtest, ruf setInputContext() auf, um den Kontext festzulegen, wenn dein Spiel in eine andere Szene wechselt. Das folgende Bild veranschaulicht dieses Verhalten: In der Szene „Autofahren“ werden die Aktionen für Straßeneinrichtungen oben im Overlay angezeigt. Wenn du das Menü „Shop“ öffnest, werden die Aktionen „Menüsteuerung“ oben im Overlay angezeigt.

InputContexts-Sortierung von Gruppen im Overlay

Diese Overlay-Updates werden durch Festlegen eines anderen InputContext an verschiedenen Stellen in Ihrem Spiel erreicht. Ziel

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

InputGroups, die zum selbenInputContext gehören, dürfen keine sich überschneidenden InputActions haben, für die derselbe Schlüssel verwendet wird. Es empfiehlt sich, jeder InputGroup eine einzelne InputContext zuzuweisen.

Im folgenden Beispielcode wird die InputContext-Logik veranschaulicht:

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 Nummern-ID und die Version der InputContext gespeichert werden (weitere Informationen finden Sie unter Tracking-Schlüssel-IDs).
  • ActiveGroups: Eine Liste von InputGroups, die verwendet und oben im Overlay angezeigt werden, wenn dieser Kontext aktiv ist.

Eingabekarte erstellen

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

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

Wenn Ihr Spiel die Umwandlung nicht unterstützt, deaktivieren Sie die Option und lassen Sie die reservierten Tasten leer.

Im folgenden Beispiel wird ein InputMap erstellt, mit dem eine Sammlung von InputGroups erfasst 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 in setInputContext() verwendet werden, sofern nicht anders angegeben.
  • MouseSettings: Das MouseSettings-Objekt gibt an, dass die Mausempfindlichkeit angepasst werden kann und dass die Maus auf der y-Achse invertiert ist.
  • InputMapId: InputIdentifier-Objekt, in dem die Nummern-ID und die Version der InputMap gespeichert werden (weitere Informationen finden Sie unter Tracking-Schlüssel-IDs).
  • InputRemappingOption: Entweder InputEnums.REMAP_OPTION_ENABLED oder InputEnums.REMAP_OPTION_DISABLED. Gibt an, ob die Neuzuordnungsfunktion aktiviert ist.
  • ReservedControls: Eine Liste von InputControls, auf die Nutzer nicht umverknüpfen dürfen.

Schlüssel-IDs erfassen

InputAction-, InputGroup-, InputContext- und InputMap-Objekte enthalten ein InputIdentifier-Objekt, in dem eine eindeutige Nummern-ID und eine Stringversions-ID gespeichert werden. Das Erfassen der Stringversion Ihrer Objekte ist optional, wird aber 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 der InputAction-Objekte müssen für alle InputActions in Ihrer InputMap eindeutig sein. Ebenso müssen InputGroup-Objekt-IDs für alle InputGroups in einer InputMap eindeutig sein. Im folgenden Beispiel wird gezeigt, wie du mit einem enum die eindeutigen IDs deiner Objekte verfolgen kannst:

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 Nummern-ID, die einen bestimmten Satz von Eingabedaten eindeutig identifiziert.
  • VersionString: Ein visuell lesbarer Versionsstring, der festgelegt ist, um eine Version von Eingabedaten zwischen zwei Versionen von Eingabedatenänderungen zu identifizieren.

Benachrichtigungen zu Ereignissen zur Neuzuordnung erhalten (optional)

Sie erhalten Benachrichtigungen zu Neuzuordnungsereignissen, um über die in Ihrem Spiel verwendeten Tasten informiert zu werden. So können die Assets auf dem Spielbildschirm, die für die Anzeige der Aktionssteuerung verwendet werden, aktualisiert werden.

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

Die Benutzeroberfläche reagiert über den InputRemappingListener-Callback auf Neuzuordnungsereignisse.

Dazu wird ein InputRemappingListener-Callback registriert. Wenn du diese Funktion implementieren möchtest, musst du zuerst eine InputRemappingListener-Instanz registrieren:

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 Starten nach dem Laden der vom Nutzer gespeicherten neu zugeordneten Steuerelemente und jedes Mal benachrichtigt, wenn der Nutzer die Tasten neu zuordnet.

Initialisierung

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

Wenn Sie InputRemappingListeners verwenden, um über Neuzuordnungsereignisse benachrichtigt zu werden, registrieren Sie Ihre InputRemappingListener, bevor Sie Ihre InputMappingProvider registrieren. Andernfalls können bei Ihrem Spiel wichtige Ereignisse während der Einführungsphase verpasst werden.

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

Bereinigen

Deregistrieren Sie Ihre InputMappingProvider-Instanz und alle InputRemappingListener-Instanzen, wenn Ihr Spiel geschlossen ist. Das Input SDK ist jedoch intelligent genug, um Ressourcenlecks 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

Du kannst die Implementierung deines Input SDK testen, indem du das Overlay manuell öffnest, um die Wiedergabe zu sehen, oder über die adb-Shell für automatische Tests und Überprüfungen.

Der Emulator für Google Play Spiele auf dem PC prüft die Richtigkeit Ihrer Eingabekarte auf häufige Fehler. In Fällen wie doppelten eindeutigen IDs, der Verwendung verschiedener Eingabekarten oder Fehlern bei den Regeln zur Neuzuordnung (falls diese aktiviert ist) wird im Overlay eine Fehlermeldung wie unten angezeigt: Das Overlay des Input SDK

Überprüfen Sie die Implementierung des Input SDK mit adb in der Befehlszeile. Um die aktuelle Eingabekarte abzurufen, verwenden Sie den folgenden adb shell-Befehl. Ersetzen Sie dabei 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, sollte die Ausgabe in etwa so aussehen:

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 beim Einreichen einer InputMap lokalisierte Strings angeben. Sie können auch das Lokalisierungssystem Ihrer Spiel-Engine verwenden.

Proguard

Wenn Sie Proguard zum Minimieren Ihres Spiels verwenden, fügen Sie Ihrer 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 übrigen Anforderungen von Google Play Spiele auf dem PC fortfahren. Weitere Informationen finden Sie unter Erste Schritte mit Google Play Spiele auf dem PC.