Pierwsze kroki z pakietem wejściowego SDK

Ten dokument opisuje, jak skonfigurować i wyświetlić pakiet SDK wejściowych w które obsługują Gry Google Play na PC. Zadania obejmują dodanie pakietu SDK do gry i generując mapę wejściową, która zawiera przypisania działań i danych wejściowych użytkownika w grze.

Zanim rozpoczniesz

Zanim dodasz pakiet SDK wejściowych do gry, musisz obsługiwać wprowadzanie tekstu za pomocą klawiatury i myszy za pomocą silnika gry .

Pakiet SDK wejściowych dostarcza do Gier Google Play na PC informacje o tym, które elementy sterujące grą są używane, aby można je było wyświetlić użytkownikowi. Może też opcjonalnie zezwolić użytkownikom na ponowne przypisywanie klawiatury.

Każdy element sterujący to InputAction (np. „J” zamiast „Jump”) i porządkujesz InputActions do InputGroups. Element InputGroup może reprezentować inny tryb gry, np. „Jazda samochodem”. lub „Pieszo” lub „Menu główne”. Możesz też użyj parametru InputContexts, aby wskazać, które grupy są aktywne w różnych punktach w całej grze.

Możesz włączyć automatyczne oznaczanie klawiatury, ale jeśli wolisz mieć własny interfejs ponownego mapowania elementów sterujących, możesz go wyłączyć Ponowne mapowanie wejściowe pakietu SDK.

Poniższy diagram sekwencji opisuje sposób działania interfejsu API pakietu SDK danych wejściowych:

Diagram sekwencji przedstawiającej implementację gry, która wywołuje interfejs API pakietu SDK wejścia
i jego interakcja z Androidem
urządzenia.

Gdy gra korzysta z pakietu SDK wejścia, widoczne są elementy sterujące w nakładce Gry Google Play na PC.

Nakładka Gry Google Play na PC

Nakładka Gry Google Play na PC („nakładka”) z elementami sterującymi które uwzględnia gra. Użytkownicy mogą w każdej chwili przejść do nakładki: naciskając Shift + Tab.

Nakładka Gry Google Play na PC.

Sprawdzone metody projektowania powiązań kluczy

Podczas projektowania powiązań kluczy kieruj się tymi sprawdzonymi metodami:

  • Aby ulepszyć działanie usługi, pogrupuj InputActions w logicznie powiązane InputGroups nawigacji i wykrywalności elementów sterujących podczas rozgrywki.
  • Przypisz każde InputGroup do maksymalnie jednego elementu InputContext. Drobnoziarnisty InputMap ułatwia poruszanie się po elementach sterujących aby wyświetlić nakładkę.
  • Utwórz InputContext dla każdego rodzaju sceny w grze. Zwykle możesz użyć jednego InputContext do wszystkich elementów menu podobnych do tych w menu. wiele scen. Używaj różnych InputContexts do wszystkich minigier w grze lub alternatywnych elementów sterujących pojedynczej sceny.
  • Jeśli 2 działania są zaprojektowane tak, aby korzystały z tego samego klucza w ramach tego samego klucza InputContext, użyj ciągu etykiety, np. „Interakcja / ogień”.
  • Jeśli 2 klucze mają służyć do powiązania z tym samym elementem InputAction, użyj 2 różne InputActions, które wykonują to samo działanie w Twojej grze. Możesz użyć tego samego ciągu etykiety w przypadku obu właściwości InputActions, ale jego identyfikator musi być ciągiem w inny sposób.
  • Jeśli do zestawu kluczy jest stosowany klawisz modyfikujący, należy rozważyć używanie jednego InputAction klawiszem modyfikującym, a nie z kilkoma argumentami InputActions, połącz klawisz modyfikujący (np. użyj Shift oraz W, A, S, D Shift + W, Shift + A, Shift + S, Shift + D).
  • Ponowne mapowanie danych wejściowych jest wyłączane automatycznie, gdy użytkownik pisze tekst . Postępuj zgodnie ze sprawdzonymi metodami implementacji pól tekstowych Androida, aby mieć pewność, aby Android mógł wykrywać pola tekstowe w grze i zapobiegać zmapowaniu klawiszy ingerencji w te prawa. Jeśli gra musi korzystać z niekonwencjonowanego tekstu możesz użyć pola setInputContext() z parametrem InputContext zawierającym pusta lista wartości InputGroups, aby ręcznie wyłączyć ponowne mapowanie.
  • Jeśli Twoja gra obsługuje ponowne mapowanie, rozważ zaktualizowanie powiązań klawiszy poufna operacja, która może kolidować z wersjami zapisanymi przez użytkownika. Unikaj zmienianie identyfikatorów istniejących elementów sterujących w miarę możliwości.

Funkcja ponownego mapowania

Gry Google Play na PC obsługują przemapowywanie sterowania za pomocą klawiatury na podstawie klawisza powiązaniach dostarczanych przez grę za pomocą pakietu danych wejściowych. To opcjonalne, a można całkowicie wyłączyć. Na przykład możesz mieć własną klawiaturę mapowania interfejsu. Aby wyłączyć ponowne mapowanie gier, musisz określić, jak opcja ponownego mapowania jest wyłączona dla urządzenia InputMap (zobacz Utwórz mapę wejściową, aby dowiedzieć się więcej).

Aby uzyskać dostęp do tej funkcji, użytkownik musi otworzyć nakładkę, a potem kliknąć działanie. chcą zmienić mapowanie. Po każdym wydarzeniu z Gier Google Play na PC przypisane przez użytkownika elementy sterujące do domyślnych ustawień, więc gra nie musi pamiętać o mapowaniu graczy. Ty może opcjonalnie aktualizować zasoby używane do wyświetlania elementów sterujących gry przez dodanie wywołania zwrotnego dla ponownego mapowania zdarzeń.

Spróbuj ponownie zmapować klucz

Gry Google Play na PC zapisują elementy sterujące lokalnie dla każdego użytkownika. co daje możliwość zachowania kontroli w sesjach gier. Te informacje są przechowywane tylko na dysku komputera i nie ma wpływu na korzystanie z wersji na urządzenia mobilne. Dane kontrolne są usuwane po odinstalowaniu lub ponownym zainstalowaniu Gier Google Play na PC. Te dane nie są trwałe na wielu urządzeniach PC.

Aby korzystać z funkcji ponownego mapowania w grze, unikaj tych ograniczeń:

Ograniczenia ponownego mapowania

Funkcje ponownego mapowania mogą zostać wyłączone w grze, jeśli powiązania klawiszy zawierają jakiekolwiek za:

  • Wiele kluczy InputActions, które nie składają się z klawisza modyfikującego + A bez klawisza modyfikującego. Na przykład Shift + A jest prawidłowy, ale A + B, Ctrl + Alt lub Shift + A + Tab – nie.
  • InputMap zawiera InputActions, InputGroups lub InputContexts z powtarzającymi się unikalnymi identyfikatorami.
.

Ograniczenia ponownego mapowania

Podczas projektowania wiązań klawiszy pod kątem ponownego mapowania weź pod uwagę te kwestie Ograniczenia:

  • Mapowanie do kombinacji klawiszy nie jest obsługiwane. Użytkownicy nie mogą na przykład: zmapuj klawisze Shift + A na Ctrl + B lub A na Shift + A.
  • Ponowne mapowanie przy użyciu przycisków myszy nie jest obsługiwane w przypadku elementu InputActions. Dla: Na przykład nie można ponownie zmapować klawisza Shift + prawym przyciskiem myszy.

Przetestuj ponowne mapowanie klawiszy w emulatorze Gier Google Play na PC

Funkcję ponownego mapowania w Emulatorze Gier Google Play na PC możesz włączyć w każdej chwili W tym celu uruchom to polecenie adb:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

Nakładka zmieni się jak na obrazie poniżej:

Nakładka z włączonym ponownym mapowaniem klawiszy.

Dodaj pakiet SDK

Zainstaluj pakiet SDK wejściowych zgodnie ze swoją platformą deweloperską.

Java i Kotlin

Pobierz pakiet SDK wejściowych dla języka Java lub Kotlin, dodając zależność do plik build.gradle na poziomie modułu:

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

Jedność

Pakiet SDK danych wejściowych to standardowy pakiet Unity z kilkoma zależnościami.

Wymagane jest zainstalowanie pakietu ze wszystkimi zależnościami. Jest kilka sposobów , aby zainstalować pakiety.

Zainstaluj aplikację .unitypackage

Pobierz plik pakietu jednostkowego pakietu SDK wejściowego ze wszystkimi zależnościami. Możesz zainstalować aplikację .unitypackage, wybierając Zasoby > Importuj pakiet > Niestandardowy pakiet i lokalizowanie pobranego pliku.

Instalowanie za pomocą UPM

Możesz też zainstalować pakiet za pomocą Unity's Package Manager (Menedżer pakietów Unity) Pobieram .tgz i instaluję jego zależności:

Zainstaluj za pomocą OpenUPM

Pakiet możesz zainstalować za pomocą OpenUPM.

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

Przykładowe gry

Przykłady integracji z pakietem SDK wejściowych: Tunel AGDK dla gier Kotlin i Javy oraz Gokarta trygonometryczna w grach Unity.

Wygeneruj powiązania kluczy

Zarejestruj powiązania kluczy, tworząc obiekt InputMap i zwracając go za pomocą InputMappingProvider W poniższym przykładzie InputMappingProvider:

Kotlin

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

Java

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

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

C#

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

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

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

Zdefiniuj działania wejściowe

Klasa InputAction służy do mapowania klucza lub kombinacji klawiszy na grę. działania. InputActions musi mieć unikalne identyfikatory w całym elemencie InputActions.

Jeśli wspierasz ponowne mapowanie, możesz określić, czym może być obiekt InputActions przeniesione. Jeśli Twoja gra nie obsługuje ponownego mapowania, musisz je ustawić. wyłączono opcję dla wszystkich Twoich InputActions, ale pakiet SDK wejścia jest na tyle inteligentnych, aby wyłączyć ponowne mapowanie, jeśli nie jest obsługiwane InputMap

W tym przykładzie klawisz spacja jest mapowany na działanie Dysk.

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

Jeden klawisz EnterAction wyświetlany w nakładce.

Działania mogą też reprezentować dane wejściowe myszki. W tym przykładzie opcja Kliknięcie lewym przyciskiem myszy ustawiana jest na wartość działanie Przenieś:

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

Działanie kursora myszy wyświetlane w nakładce.

Kombinacje klawiszy są określane przez przekazanie wielu kodów klawiszy na klucz InputAction W tym przykładzie spacja + Shift jest zmapowana na działanie Turbo, które działa nawet wtedy, gdy Spacja jest zmapowana na Dysk.

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

Wielokrotna metoda wprowadzania danych wejściowych wyświetlana w nakładce.

Pakiet danych wejściowych zawiera pakiet SDK do wprowadzania danych, który pozwala łączyć jednocześnie przyciski myszy i klawiszy jedno działanie. Ten przykład wskazuje, że klawisze Shift i kliknięcie prawym przyciskiem myszy naciśnięcie razem dodaje punkt pośredni w tej przykładowej grze:

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

Kombinacja naciśnięcia klawisza/wejścia myszki wyświetlanej w nakładce.

Dane wejściowe działania mają te pola:

  • ActionLabel: ciąg znaków wyświetlany w interfejsie oznaczający to działanie. Lokalizacja nie jest wykonywana automatycznie, więc ją tłumacz z przodu.
  • InputControls: określa elementy sterujące danymi wejściowymi używane przez to działanie. elementy sterujące mapą na spójne glify w nakładce.
  • InputActionId: obiekt InputIdentifier, który przechowuje identyfikator i wersję numeru InputAction (zobacz identyfikatory kluczy śledzenia, aby dowiedzieć się więcej) ).
  • InputRemappingOption: jedna z InputEnums.REMAP_OPTION_ENABLED lub InputEnums.REMAP_OPTION_DISABLED Określa, czy działanie jest włączone ich mapowanie. Jeśli Twoja gra nie obsługuje ponownego mapowania, możesz pominąć to pole lub po prostu wyłączyć tę funkcję.
  • RemappedInputControls: tylko do odczytu obiekt InputControls używany do odczytu przemapowany klawisz ustawiony przez użytkownika przy mapowaniu zdarzeń (używane w przypadku otrzymywać powiadomienia o remapowaniu zdarzeń).

InputControls reprezentuje dane wejściowe powiązane z działaniem i zawiera tych pól:

  • AndroidKeycodes: to lista liczb całkowitych reprezentujących dane wejściowe z klawiatury powiązane z działaniem. Są one zdefiniowane w Kluczowe zdarzenie lub AndroidKeycode dla Unity.
  • MouseActions: to lista wartości MouseAction reprezentujących dane wejściowe myszy powiązane z tym działaniem.

Zdefiniuj grupy danych wejściowych

InputActions są zgrupowane z działaniami powiązanymi logicznie za pomocą argumentu InputGroups do poprawić nawigację i wykrywalność elementów sterujących w nakładce. Każdy Identyfikator InputGroup musi być unikalny wśród wszystkich elementów (InputGroups) w Twojej grze.

Łącząc działania wejściowe w grupy, ułatwiasz graczowi aby znaleźć prawidłowe powiązanie klucza dla bieżącego kontekstu.

Jeśli wspierasz ponowne mapowanie, możesz określić, czym może być obiekt InputGroups przeniesione. Jeśli Twoja gra nie obsługuje ponownego mapowania, musisz je ustawić. wyłączono opcję dla wszystkich Twoich InputGroups, ale pakiet SDK wejścia jest na tyle inteligentnych, aby wyłączyć ponowne mapowanie, jeśli nie jest obsługiwane 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
);

W przykładzie poniżej widać Elementy sterujące drogi i Elementy sterujące menu grupy wejściowe w nakładce:

Nakładka wyświetlająca mapę wejściową zawierającą elementy sterujące drogą
Grupy wejściowe elementów sterujących menu.

InputGroup zawiera te pola:

  • GroupLabel: ciąg znaków do wyświetlania w nakładce, którego można użyć, pogrupować logicznie zbiór działań. Ten ciąg nie jest automatycznie i zlokalizowanego.
  • InputActions: lista InputAction obiektów zdefiniowanych w poprzedniej sekcji krok po kroku. Wszystkie te działania są wyświetlane wizualnie pod nagłówkiem grupy.
  • InputGroupId: obiekt InputIdentifier, który przechowuje identyfikator numeru i wersji InputGroup. Zobacz Identyfikatory kluczy śledzenia: znajdziesz więcej informacji.
  • InputRemappingOption: jedna z InputEnums.REMAP_OPTION_ENABLED lub InputEnums.REMAP_OPTION_DISABLED Jeśli zasada jest wyłączona, wszystkie InputAction obiekty należące do tej grupy będą wyłączone ponownie, nawet jeśli włącz opcję ponownego mapowania. Jeśli ta opcja jest włączona, wszystkie działania należące do do tej grupy można przypisać ponownie, chyba że zostanie wyłączona przez osobę .
.

Zdefiniuj konteksty danych wejściowych

W funkcji InputContexts gra może używać innego zestawu sterowania za pomocą klawiatury różne sceny gry. Na przykład:

  • Możesz określić różne zestawy danych wejściowych do poruszania się po menu i inne dane wejściowe do poruszania się po menu w danej grze.
  • Możesz określić różne zestawy danych wejściowych w zależności od trybu ruchu. takich jak jazda samochodem czy chodzenie.
  • Możesz określić różne zestawy danych wejściowych w zależności od bieżącego stanu np. poruszanie się po świecie, a nie granie na poziomie indywidualnym.

Gdy używasz interfejsu InputContexts, nakładka pokazuje najpierw grupy kontekstu w użyciu. Aby włączyć to zachowanie, wywołaj setInputContext() w celu ustawienia za każdym razem, gdy gra wkracza w inną scenę. Następujący obraz demonstruje takie zachowanie: podczas jazdy elementy sterujące drogą, działania są wyświetlane w górnej części nakładki. Podczas otwierania „sklepu” , „Elementy sterujące menu” działania są wyświetlane w górnej części nakładki.

Sortowanie grup wejściowych w kontekście wejściowym w nakładce.

Te aktualizacje nakładki są osiągane przez ustawienie innego parametru InputContext na poziomie w różnych punktach gry. Aby to zrobić:

  1. Pogrupuj InputActions za pomocą logicznie powiązanych działań za pomocą argumentu InputGroups
  2. Przypisz te elementy (InputGroups) do elementu InputContext obejmującego różne części Twoja gra

InputGroups należące do tego samego InputContextnie mogą powodować konfliktów InputActions w przypadku tego samego klucza. Dobrze jest przypisać każdej z nich InputGroup do pojedynczej kolumny InputContext.

Poniższy przykładowy kod ilustruje logikę InputContext:

Kotlin

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

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

Java

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

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

C#

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

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

InputContext zawiera te pola:

  • LocalizedContextLabel: ciąg opisujący grupy należące do i dodaje kontekst.
  • InputContextId: obiekt InputIdentifier, który przechowuje identyfikator i wersję numeru InputContext (zobacz identyfikatory kluczy śledzenia, aby dowiedzieć się więcej) ).
  • ActiveGroups: lista wartości InputGroups, która będzie używana i wyświetlana u góry nakładki, gdy ten kontekst jest aktywny.

Tworzenie mapy wejściowej

Element InputMap to kolekcja wszystkich obiektów InputGroup dostępnych w czyli wszystkie obiekty InputAction, których gracz może się spodziewać skuteczność.

Podczas raportowania powiązań kluczy tworzysz InputMap ze wszystkimi InputGroups wykorzystane w grze.

Jeśli Twoja gra nie obsługuje ponownego mapowania, wyłącz opcję ponownego mapowania. zarezerwowane klucze są puste.

Poniższy przykład pozwala utworzyć obiekt InputMap używany do raportowania kolekcji InputGroups

Kotlin

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

Java

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

C#

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

InputMap zawiera te pola:

  • InputGroups: grupy wejściowe zgłaszane przez grę. Te grupy są wyświetlane w nakładce w kolejności, o ile nie określono bieżących grup w użyj połączenia setInputContext().
  • MouseSettings: obiekt MouseSettings wskazuje czułość myszy. może zostać odwrócona, a mysz znajduje się na osi Y.
  • InputMapId: obiekt InputIdentifier, który przechowuje identyfikator numeru i wersję InputMap (zobacz identyfikatory kluczy śledzenia, ).
  • InputRemappingOption: jedna z InputEnums.REMAP_OPTION_ENABLED lub InputEnums.REMAP_OPTION_DISABLED Określa, czy funkcja ponownego mapowania jest .
  • ReservedControls: lista elementów InputControls, których użytkownicy nie będą mogli robić i zmapować je.

Identyfikatory kluczy śledzenia

Obiekty InputAction, InputGroup, InputContext i InputMap zawierają Obiekt InputIdentifier, który przechowuje unikalny identyfikator numeru i identyfikator wersji ciągu. Śledzenie wersji w postaci ciągów znaków jest opcjonalne, ale zalecane, aby można było śledzić wersje systemu InputMap. Jeśli nie podano wersji ciągu znaków, ciąg jest pusty. W przypadku obiektów InputMap wymagana jest wersja ciągu znaków.

W tym przykładzie do InputActions lub InputGroups:

Kotlin

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

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

Java

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

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

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

C#


#if PLAY_GAMES_PC

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

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

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

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

Identyfikatory numerów obiektów InputAction muszą być unikalne wśród wszystkich InputActions w InputMap. Podobnie identyfikatory obiektów InputGroup muszą być unikalne wśród wszystkich InputGroups w: InputMap. Poniższy przykład pokazuje, jak korzystać z enum, aby śledzić unikalne identyfikatory obiektu:

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 zawiera te pola:

  • UniqueId: unikalny identyfikator numeru ustawiony, aby jednoznacznie identyfikować określony zbiór danych wejściowych. danych w unikalny sposób.
  • VersionString: zrozumiały dla człowieka ciąg znaków wersji identyfikujący wersję. danych wejściowych między 2 wersjami danych wejściowych.

Otrzymuj powiadomienia o ponownym mapowaniu zdarzeń (opcjonalnie)

Otrzymuj powiadomienia o zdarzeniach zmiany mapowania, aby otrzymywać informacje o używanych kluczach Twojej gry. Dzięki temu gra może aktualizować zasoby wyświetlane na ekranie gry służy do wyświetlania elementów sterujących działaniami.

Poniższy obraz przedstawia przykład tego działania, w którym po ponownym zmapowaniu klawisze G, P i S do J, X i T, elementy interfejsu gry są aktualizowane aby wyświetlić klucze ustawione przez użytkownika.

Interfejs przedstawiający remapowanie zdarzeń za pomocą wywołania zwrotnego WriteRemappingListener.

Jest to możliwe przez zarejestrowanie InputRemappingListener oddzwanianie. Aby wdrożyć to rozwiązanie, zacznij od zarejestrowania Instancja InputRemappingListener:

Kotlin

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

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

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

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

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

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

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

Java

public class InputSDKRemappingListener implements InputRemappingListener {

    private static final String TAG = "InputSDKRemappingListener";

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

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

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

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

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

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

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

C#

#if PLAY_GAMES_PC

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

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

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

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

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

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

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

Aplikacja InputRemappingListener zostanie powiadomiona w momencie uruchomienia po wczytaniu zapisanych przez użytkownika elementów sterujących i za każdym razem, gdy użytkownik ponownie przyporządkuje klawisze.

Inicjalizacja

Jeśli używasz InputContexts, ustaw kontekst dla każdego przejście do nowej sceny, łącznie z pierwszym kontekstem użytym na początku scena. InputContext musisz ustawić po zarejestrowaniu InputMap

Jeśli używasz usługi InputRemappingListeners do otrzymywania powiadomień o ponownym mapowaniu zdarzeń zarejestruj: InputRemappingListener, zanim zarejestrujesz InputMappingProvider, w przeciwnym razie gra może przegapić ważne wydarzenia w czasie czasu uruchomienia.

Poniższy przykład pokazuje, jak zainicjować interfejs API:

Kotlin

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

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

Java

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

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

C#

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

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

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

Uporządkuj

Wyrejestruj instancję InputMappingProvider i wszystkie instancje InputRemappingListener gdy gra jest zamknięta, mimo że pakiet SDK wejścia jest inteligentny aby uniknąć wycieku zasobów, jeśli:

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

Możesz przetestować implementację pakietu SDK wejściowego, ręcznie otwierając nakładkę, aby wyświetlić działanie odtwarzacza, lub za pomocą powłoki adb. do automatycznego testowania i weryfikacji.

Emulator Gier Google Play na PC sprawdza poprawność mapy wejściowej z typowymi błędami. W przypadku powielonych unikalnych identyfikatorów przy użyciu różnych lub nieprawidłowe reguły mapowania (jeśli jest włączone ponowne mapowanie), wyświetla się następujący komunikat o błędzie: Nakładka pakietu SDK.

Sprawdź implementację pakietu SDK wejściowego, używając narzędzia adb w wierszu poleceń. Aby pobrać bieżącą mapę wejściową, użyj tego polecenia adb shell (zastąp MY.PACKAGE.NAME nazwą swojej gry):

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

W przypadku pomyślnego zarejestrowania domeny wyświetli się wynik podobny do tego. InputMap:

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

Lokalizacja

Pakiet SDK danych wejściowych nie używa systemu lokalizacji Androida. Jako musisz podać zlokalizowane ciągi tekstowe, gdy przesyłasz pole InputMap. Ty może też używać systemu lokalizacji silnika gry.

ProGuard

Jeśli używasz ProGuard do minifikacji gry, dodaj do swojego przed usunięciem pakietu SDK. końcowy pakiet:

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

Co dalej

Możesz kontynuować, gdy zintegrujesz pakiet SDK wejściowych z grą z pozostałymi wymaganiami dotyczącymi Gier Google Play na PC. Aby dowiedzieć się więcej, Więcej informacji znajdziesz w artykule Pierwsze kroki z Grami Google Play na PC.