Начало работы с Input SDK

В этом документе рассказывается, как настроить и показывать Input SDK в играх, поддерживающих Google Play Games на компьютере. Вам нужно будет добавить SDK в игру и создать карту ввода, в которой будут указаны соответствия между действиями в игре и действиями пользователя.

Перед началом работы

Прежде чем добавлять Input SDK в игру, убедитесь, что в ней поддерживается ввод с клавиатуры и мыши с помощью системы ввода игрового движка.

Input SDK предоставляет Google Play Играм на компьютере информацию о том, какие элементы управления используются в вашей игре, чтобы их можно было показывать пользователю. Также можно разрешить пользователям переназначать клавиши клавиатуры.

Каждое действие обозначается клавишей InputAction (например, "J" для перехода к следующему треку), а клавиши InputActions можно объединять в группы InputGroups. Объект InputGroup может представлять разные режимы игры, например "Вождение", "Ходьба" или "Главное меню". Вы также можете использовать InputContexts, чтобы указать, какие группы активны в разные моменты игры.

Вы можете включить автоматическое переназначение клавиш, но если вы хотите создать собственный интерфейс для этого, то можете отключить переназначение в Input SDK.

На приведенной ниже диаграмме последовательности показано, как работает API Input SDK:

Диаграмма последовательности для реализации игры, которая вызывает API Input SDK и взаимодействует с устройством Android.

Когда в игре реализован Input SDK, элементы управления отображаются в оверлее Google Play Игр на компьютере.

Оверлей Google Play Games на компьютере

Оверлей Google Play Игр на компьютере ("оверлей") показывает элементы управления, заданные в вашей игре. Пользователи могут в любое время открыть оверлей, нажав Shift + Tab.

Оверлей Google Play Games на компьютере.

Рекомендации по назначению клавиш

При назначении клавиш учитывайте следующие рекомендации:

  • Группируйте InputActions в логически связанные InputGroups, чтобы во время игры было проще ориентироваться и находить нужные элементы управления.
  • Каждому значению InputGroup можно назначить не более одного значения InputContext. Чем меньше шаг, тем удобнее пользоваться элементами управления в оверлее.InputMap
  • Создайте элемент InputContext для каждого типа сцены в игре. Обычно для всех сцен, похожих на меню, можно использовать один и тот же тег InputContext. Используйте разные InputContexts для мини-игр или альтернативных способов управления в одной сцене.
  • Если два действия должны использовать один и тот же ключ в рамках одного и того же InputContext, используйте строку ярлыка, например "Взаимодействовать / Стрелять".
  • Если два ключа должны быть привязаны к одному и тому же InputAction, используйте два разных InputActions, которые выполняют одно и то же действие в игре. Вы можете использовать одну и ту же строку ярлыка для обоих свойств InputActions, но идентификаторы должны быть разными.
  • Если клавиша-модификатор применяется к набору клавиш, рекомендуем использовать одну клавишу InputAction с клавишей-модификатором вместо нескольких клавиш InputActions, которые сочетают клавишу-модификатор (например, используйте Shift и W, A, S, D вместо Shift + W, Shift + A, Shift + S, Shift + D).
  • Переназначение клавиш автоматически отключается, когда пользователь вводит текст в текстовые поля. Чтобы Android мог распознавать текстовые поля в вашей игре и предотвращать их блокировку переназначенными клавишами, следуйте рекомендациям по реализации текстовых полей Android. Если в вашей игре используются нестандартные текстовые поля, вы можете отключить переназначение вручную, используя setInputContext() с InputContext, содержащим пустой список InputGroups.
  • Если в вашей игре поддерживается переназначение клавиш, не меняйте их настройки, так как это может привести к конфликту с сохраненными пользователем версиями. По возможности не меняйте идентификаторы существующих элементов управления.

Функция переназначения

Google Play Игры на компьютере поддерживают переназначение клавиш на основе привязок, которые вы задали в игре с помощью Input SDK. Это необязательная функция, которую можно отключить. Например, вы можете создать собственный интерфейс для переназначения клавиш. Чтобы отключить переназначение клавиш в игре, нужно указать, что параметр переназначения отключен для InputMap (подробнее о том, как создать InputMap…).

Чтобы использовать эту функцию, пользователям нужно открыть оверлей и нажать на действие, которое они хотят переназначить. После каждого переназначения клавиш Google Play Games на компьютере сопоставляет переназначенные пользователем клавиши с клавишами по умолчанию, которые ожидает получить ваша игра. Таким образом, игра не должна знать о переназначении клавиш. При необходимости вы можете обновить объекты, используемые для показа элементов управления клавиатурой в игре, добавив обратный вызов для переназначения событий.

Попробуйте переназначить клавишу.

Google Play Игры на компьютере сохраняют переназначенные элементы управления локально для каждого пользователя, поэтому настройки сохраняются между игровыми сессиями. Эта информация хранится на диске только на платформе ПК и не влияет на работу мобильных устройств. Данные управления удаляются, когда пользователь удаляет или переустанавливает Google Play Игры на компьютере. Эти данные не сохраняются на нескольких устройствах.

Чтобы в игре можно было переназначать кнопки, соблюдайте следующие ограничения:

Ограничения переназначения

Переназначение клавиш может быть отключено в игре, если в настройках управления есть следующие случаи:

  • Сочетания клавиш InputActions, которые не состоят из клавиши-модификатора и обычной клавиши. Например, Shift + A – допустимое сочетание, а A + B, Ctrl + Alt или Shift + A + Tab – нет.
  • Поле InputMap содержит InputActions, InputGroups или InputContexts с повторяющимися уникальными идентификаторами.

Ограничения переназначения

При назначении клавиш для переназначения учитывайте следующие ограничения:

  • Переназначение на сочетания клавиш не поддерживается. Например, пользователи не могут переназначить сочетание клавиш Shift + A на Ctrl + B или A на Shift + A.
  • Переназначение кнопок мыши на клавиши InputActions не поддерживается. Например, нельзя переназначить сочетание Shift + правая кнопка мыши.

Как проверить переназначение клавиш в эмуляторе Google Play Игр на компьютере

Вы можете включить функцию переназначения в эмуляторе Google Play Games на компьютере в любое время, выполнив следующую команду adb:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

Наложение изменится, как показано на изображении ниже.

Оверлей с включенным переназначением клавиш.

Как добавить SDK

Установите Input SDK в соответствии с вашей платформой разработки.

Java и Kotlin

Чтобы получить Input SDK для Java или Kotlin, добавьте зависимость в файл build.gradle на уровне модуля:

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

Unity

Input SDK – это стандартный пакет Unity с несколькими зависимостями.

Необходимо установить пакет со всеми зависимостями. Установить пакеты можно несколькими способами.

Как установить .unitypackage

Скачайте файл Input SDK unitypackage со всеми зависимостями. Установить .unitypackage можно, выбрав Assets > Import package > Custom Package и указав скачанный файл.

Установка с помощью UPM

Вы также можете установить пакет с помощью Unity Package Manager, скачав файл .tgz и установив его зависимости:

Установка с помощью OpenUPM

Вы можете установить пакет с помощью OpenUPM.

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

Примеры игр

Примеры интеграции с Input SDK можно найти в AGDK Tunnel для игр на Kotlin или Java и Trivial Kart для игр на Unity.

Как создать сочетания клавиш

Зарегистрируйте сочетания клавиш, создав InputMap и вернув его с помощью InputMappingProvider. Ниже приведен пример 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

Как задать действия для ввода

Класс InputAction используется для сопоставления клавиши или сочетания клавиш с действием в игре. У всех объектов InputActions должны быть уникальные идентификаторы InputActions.

Если вы поддерживаете переназначение клавиш, вы можете указать, какие клавиши можно переназначать.InputActions Если ваша игра не поддерживает переназначение, отключите эту функцию для всех InputActions. Однако Input SDK достаточно интеллектуален, чтобы отключить переназначение, если оно не поддерживается в InputMap.

В этом примере клавиша Пробел сопоставлена с действием Диск.

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

Одно клавишное сочетание, отображаемое на оверлее.

Действия также могут представлять собой ввод с помощью мыши. В этом примере для нажатия левой кнопки мыши задано действие Переместить:

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

Действие мыши, отображаемое в оверлее.

Сочетания клавиш задаются путем передачи нескольких кодов клавиш в метод InputAction. В этом примере пробел + Shift сопоставляется с действием Турбо, которое работает, даже если пробел сопоставляется с Диском.

Kotlin

companion object {
  private val turboInputAction = InputAction.create(
    "Turbo",
    InputActionsIds.TURBO.ordinal.toLong(),
    InputControls.create(
      listOf(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SPACE),
      emptyList()),
    InputEnums.REMAP_OPTION_ENABLED)
}

Java

private static final InputAction turboInputAction = InputAction.create(
    "Turbo",
    InputActionsIds.TURBO.ordinal(),
    InputControls.create(
            Arrays.asList(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SPACE),
            Collections.emptyList()
    ),
    InputEnums.REMAP_OPTION_ENABLED
);

C#

private static readonly InputAction turboInputAction = InputAction.Create(
    "Turbo",
    (long)InputEventIds.TURBO,
    InputControls.Create(
        new[]
        {
            new Integer(AndroidKeyCode.KEYCODE_SHIFT_LEFT),
            new Integer(AndroidKeyCode.KEYCODE_SPACE)
        }.ToJavaList(),
        new ArrayList<Integer>()),
    InputEnums.REMAP_OPTION_ENABLED
);

Многоклавишное действие InputAction, отображаемое в оверлее.

Input SDK позволяет объединять кнопки мыши и клавиши для выполнения одного действия. В этом примере показано, что одновременное нажатие клавиши Shift и правой кнопки мыши добавляет в игру путевую точку.

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

Сочетание клавиши и действия мыши, отображаемое в оверлее.

Объект InputAction содержит следующие поля:

  • ActionLabel – строка, которая отображается в интерфейсе для представления этого действия. Локализация не выполняется автоматически, поэтому ее нужно сделать заранее.
  • InputControls – определяет элементы управления, которые используются для этого действия. Элементы управления сопоставляются с глифами на наложении.
  • InputActionId – объект InputIdentifier, в котором хранятся идентификатор и версия InputAction (дополнительную информацию можно найти в разделе Идентификаторы ключей отслеживания).
  • InputRemappingOption – одно из следующих значений: InputEnums.REMAP_OPTION_ENABLED или InputEnums.REMAP_OPTION_DISABLED. Определяет, можно ли переназначать действие. Если в вашей игре не поддерживается переназначение клавиш, вы можете пропустить это поле или просто установить для него значение "Отключено".
  • RemappedInputControls: объект InputControls, доступный только для чтения, который используется для считывания набора переназначенных клавиш, заданного пользователем при переназначении событий (используется для получения уведомлений о переназначении событий).

InputControls представляет собой входные данные, связанные с действием, и содержит следующие поля:

  • AndroidKeycodes – это список целых чисел, представляющих собой ввод с клавиатуры, связанный с определенным действием. Они определены в классе KeyEvent или классе AndroidKeycode для Unity.
  • MouseActions – список значений MouseAction, представляющих входные данные мыши, связанные с этим действием.

Как определить группы входов

InputActions сгруппированы с логически связанными действиями с помощью InputGroups, чтобы улучшить навигацию и обнаружение элементов управления в оверлее. Каждый идентификатор InputGroup должен быть уникальным для всех объектов InputGroups в игре.

Разбивая действия на группы, вы помогаете игрокам находить нужные сочетания клавиш.

Если вы поддерживаете переназначение клавиш, вы можете указать, какие клавиши можно переназначать.InputGroups Если ваша игра не поддерживает переназначение, отключите эту функцию для всех InputGroups. Однако Input SDK достаточно интеллектуален, чтобы отключить переназначение, если оно не поддерживается в 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
);

В следующем примере показаны группы элементов управления Дорога и Меню на наложении:

Оверлей, на котором показан InputMap, содержащий группы элементов управления Road и Menu.

InputGroup содержит следующие поля:

  • GroupLabel – строка, которая будет показываться в оверлее и может использоваться для логического объединения набора действий. Эта строка не локализуется автоматически.
  • InputActions – список объектов InputAction, которые вы определили на предыдущем шаге. Все эти действия будут показаны под заголовком группы.
  • InputGroupId: объект InputIdentifier, в котором хранится идентификатор номера и версия InputGroup. Подробнее об идентификаторах ключей отслеживания…
  • InputRemappingOption – одно из следующих значений: InputEnums.REMAP_OPTION_ENABLED или InputEnums.REMAP_OPTION_DISABLED. Если отключить эту функцию, для всех объектов InputAction этой группы будет отключено переназначение, даже если в них указано, что оно включено. Если этот параметр включен, все действия, относящиеся к этой группе, можно переназначать, если только для отдельных действий не указано, что это запрещено.

Как задать контексты ввода

InputContexts позволяет использовать разные наборы клавиш для управления в разных сценах игры. Пример:

  • Вы можете задать разные наборы входных данных для навигации по меню и перемещения в игре.
  • Вы можете указать разные наборы входных данных в зависимости от способа передвижения в игре, например при вождении или ходьбе.
  • Вы можете указать разные наборы входных данных в зависимости от текущего состояния игры, например при перемещении по карте мира или при прохождении отдельного уровня.

При использовании InputContexts на оверлее сначала показываются группы контекста, которые используются в данный момент. Чтобы включить такое поведение, вызывайте setInputContext() для установки контекста при переходе на другую сцену. На изображении ниже показано, что в сцене "Вождение" действия Управление дорогой отображаются в верхней части оверлея. При открытии меню "Магазин" действия "Управление меню" отображаются вверху оверлея.

Группы сортировки InputContexts в оверлее.

Чтобы изменить оверлей, задайте разные значения параметра InputContext в разных частях игры. Вот как это сделать:

  1. Группируйте действия, связанные с InputActions, с помощью InputGroups
  2. Назначьте эти InputGroups InputContext для разных частей игры.

InputGroups, относящиеся к одномуInputContext, не могут иметь конфликтующиеInputActions, если используется один и тот же ключ. Рекомендуется назначать каждому InputGroup только один InputContext.

В приведенном ниже образце кода показана логика параметра 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 содержит следующие поля:

  • LocalizedContextLabel – строка с описанием групп, относящихся к контексту.
  • InputContextId – объект InputIdentifier, в котором хранятся идентификатор и версия InputContext (дополнительную информацию можно найти в разделе Идентификаторы ключей отслеживания).
  • ActiveGroups – список объектов InputGroups, которые будут использоваться и показываться вверху оверлея, когда этот контекст активен.

Как создать карту ввода

InputMap – это коллекция всех объектов InputGroup, доступных в игре, а значит, и всех объектов InputAction, с которыми может взаимодействовать игрок.

При создании отчета о назначении клавиш вы составляете InputMap со всеми InputGroups, используемыми в игре.

Если игра не поддерживает переназначение клавиш, отключите эту функцию и не назначайте клавиши.

В следующем примере создается объект InputMap, который используется для передачи данных о коллекции объектов 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 содержит следующие поля:

  • InputGroups – группы входных данных, которые передает ваша игра. Группы отображаются в наложении в том порядке, в котором они перечислены, если только текущие группы не указаны с помощью вызова setInputContext().
  • MouseSettings – MouseSettings объект, указывающий, что чувствительность мыши можно настроить и что мышь инвертирована по оси Y.
  • InputMapId – объект InputIdentifier, в котором хранятся числовой идентификатор и версия InputMap (дополнительную информацию можно найти в разделе Идентификаторы ключей отслеживания).
  • InputRemappingOption – одно из следующих значений: InputEnums.REMAP_OPTION_ENABLED или InputEnums.REMAP_OPTION_DISABLED. Определяет, включена ли функция переназначения.
  • ReservedControls – список InputControls, которые пользователи не смогут переназначать.

Идентификаторы ключей отслеживания

Объекты InputAction, InputGroup, InputContext и InputMap содержат объект InputIdentifier, в котором хранятся уникальный числовой идентификатор и строковый идентификатор версии. Отслеживать строковую версию объектов необязательно, но рекомендуется, чтобы отслеживать версии InputMap. Если версия строки не указана, строка будет пустой. Для объектов InputMap требуется строковая версия.

В следующем примере строковая версия присваивается параметру InputActions или 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

Идентификаторы объектов InputAction должны быть уникальными для всех объектов InputActions в вашем InputMap. Аналогично, идентификаторы объектов InputGroup должны быть уникальными для всех объектов InputGroups в InputMap. В примере ниже показано, как использовать элемент enum для отслеживания уникальных идентификаторов объектов.

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 содержит следующие поля:

  • UniqueId – уникальный числовой идентификатор, который позволяет однозначно определить набор входных данных.
  • VersionString – строка, понятная человеку, которая позволяет идентифицировать версию входных данных между двумя изменениями входных данных.

Уведомления о переназначении событий (необязательно)

Получать уведомления о переназначении клавиш, чтобы знать, какие клавиши используются в игре. Это позволяет игре обновлять объекты, которые показываются на экране и используются для отображения элементов управления.

На изображении ниже показано, как после переназначения клавиш G, P и S на J, X и T соответственно элементы интерфейса игры обновляются и отображают клавиши, заданные пользователем.

Интерфейс реагирует на события переназначения с помощью обратного вызова InputRemappingListener.

Для этого нужно зарегистрировать обратный вызов InputRemappingListener. Чтобы реализовать эту функцию, сначала зарегистрируйте экземпляр InputRemappingListener:

Kotlin

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

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

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

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

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

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

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

Java

public class InputSDKRemappingListener implements InputRemappingListener {

    private static final String TAG = "InputSDKRemappingListener";

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

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

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

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

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

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

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

C#

#if PLAY_GAMES_PC

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

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

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

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

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

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

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

InputRemappingListener получает уведомление при запуске после загрузки переназначенных пользователем элементов управления, а также каждый раз, когда пользователь переназначает клавиши.

Инициализация

Если вы используете InputContexts, задайте контекст для каждого перехода к новой сцене, включая первый контекст, используемый для начальной сцены. Установить InputContext можно только после регистрации InputMap.

Если вы используете InputRemappingListeners, чтобы получать уведомления о переназначении событий, зарегистрируйте InputRemappingListener до регистрации InputMappingProvider. В противном случае во время запуска игры могут быть пропущены важные события.

В примере ниже показано, как инициализировать 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
    }
}

Удалите ненужные объекты

Отмените регистрацию экземпляра InputMappingProvider и всех экземпляров InputRemappingListener, когда игра будет закрыта. Впрочем, Input SDK достаточно умный, чтобы избежать утечки ресурсов, даже если вы этого не сделаете:

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

Тест

Вы можете протестировать реализацию Input SDK, вручную открыв оверлей, чтобы посмотреть, как выглядит проигрыватель, или с помощью оболочки adb для автоматического тестирования и проверки.

Эмулятор Google Play Games на компьютере проверяет правильность сопоставления клавиш и выявляет распространенные ошибки. В таких случаях, как дублирование уникальных идентификаторов, использование разных входных карт или сбой в правилах переназначения (если оно включено), на оверлее появляется сообщение об ошибке, как показано ниже: Оверлей Input SDK.

Проверьте реализацию Input SDK с помощью команды adb в командной строке. Чтобы получить текущую карту ввода, используйте следующую команду adb shell (замените MY.PACKAGE.NAME названием вашей игры):

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

Если вы успешно зарегистрировали пакет 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
}

Локализация

Input SDK не использует систему локализации Android. Поэтому при отправке InputMap необходимо указывать локализованные строки. Вы также можете использовать систему локализации игрового движка.

Proguard

Если вы используете Proguard для минимизации игры, добавьте в файл конфигурации Proguard следующие правила, чтобы SDK не был удален из конечного пакета:

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

Что дальше

После того как вы интегрируете Input SDK в игру, вы можете выполнить оставшиеся требования для Google Play Игр на компьютере. Подробнее о том, как начать работу с Google Play Играми на компьютере…