Memulai Input SDK

Dokumen ini menjelaskan cara menyiapkan dan menampilkan Input SDK di game yang mendukung Google Play Game di PC. Tugasnya termasuk menambahkan SDK ke game Anda dan membuat peta input, yang berisi tugas input game‐action-to-user-input.

Sebelum memulai

Sebelum Anda menambahkan Input SDK ke game, Anda harus mendukung input keyboard dan mouse menggunakan sistem input game engine Anda.

Input SDK memberikan informasi ke Google Play Game di PC mengenai hal-hal yang mengontrol penggunaan game Anda, sehingga game tersebut dapat ditampilkan ke pengguna. Input SDK juga dapat secara opsional mengizinkan pemetaan ulang keyboard untuk pengguna.

Tiap-tiap kontrol merupakan InputAction (mis. "J" untuk "Jump") dan Anda menyusun InputActions ke dalam InputGroups. Sebuah InputGroup dapat menampilkan mode yang berbeda dalam game Anda, seperti "Mengemudi" atau "Berjalan" atau "Menu Utama". Anda juga dapat menggunakan InputContexts untuk menunjukkan grup mana yang aktif pada titik game yang berbeda.

Anda dapat mengaktifkan pemetaan ulang keyboard supaya dapat diatur secara otomatis untuk Anda, namun jika Anda memilih untuk menetapkan antarmuka pemetaan ulang kontrol Anda sendiri, Anda dapat menonaktifkan pemetaan ulang Input SDK.

Diagram urutan berikut menjelaskan cara kerja API Input SDK:

Diagram urutan penerapan game yang memanggil API Input SDK
serta interaksinya dengan perangkat
Android.

Ketika game Anda menerapkan Input SDK, kontrol Anda ditampilkan di overlay Google Play Game di PC.

Overlay Google Play Game di PC

Overlay Google Play Game di PC ("overlay") menampilkan kontrol yang ditetapkan oleh game Anda. Pengguna mengakses overlay kapan pun dengan menekan Shift + Tab.

Overlay Google Play Game di PC.

Praktik terbaik untuk mendesain binding tombol

Ketika mendesain binding tombol, pertimbangkan praktik terbaik berikut:

  • Kelompokkan InputActions ke dalam InputGroups yang terkait secara logis guna meningkatkan visibilitas navigasi dan kontrol selama gameplay.
  • Tetapkan setiap InputGroup ke paling banyak satu InputContext. InputMap yang ditingkatkan menghasilkan pengalaman yang lebih baik untuk menavigasi kontrol di overlay.
  • Buat InputContext untuk tiap-tiap jenis suasana game Anda. Biasanya, Anda dapat menggunakan InputContext untuk semua suasana "menu-like". Gunakan beragam InputContexts untuk minigame apa pun dalam game Anda atau untuk kontrol alternatif untuk satu suasana.
  • Jika dua tindakan didesain untuk menggunakan tombol yang sama dalam InputContext yang sama, gunakan string label seperti "Interact / Fire".
  • Jika dua tombol didesain untuk mengikat ke InputAction yang sama, gunakan 2 InputActions yang berlainan yang menjalankan tindakan yang sama dalam game Anda. Anda dapat menggunakan string label yang sama untuk InputActions, namun ID-nya harus berlainan.
  • Apabila tombol pengubah diterapkan ke serangkaian tombol, pertimbangkan agar memiliki satu InputAction dengan tombol pengubah, bukan beberapa InputActions yang mengkombinasikan tombol pengubah (contoh: gunakan Shift dan W, A, S, D bukan Shift + W, Shift + A, Shift + S, Shift + D).
  • Pemetaan ulang input dinonaktifkan secara otomatis ketika pengguna menulis ke dalam kolom teks. Ikuti praktik terbaik untuk menerapkan kolom teks Android guna memastikan bahwa Android dapat mendeteksi kolom teks dalam game Anda dan mencegah tombol yang dipetakan ulang mengganggu prosesnya. Jika game Anda harus menggunakan kolom teks non-konvensional, Anda dapat menggunakan setInputContext() dengan InputContext yang berisi daftar kosong InputGroups guna menonaktifkan pemetaan ulang secara otomatis.
  • Jika game Anda mendukung pemetaan ulang, sebaiknya update binding tombol menggunakan operasi sensitif yang dapat bertentangan dengan versi yang disimpan oleh pengguna. Jika memungkinkan, hindari mengubah ID kontrol yang sudah diterapkan.

Fitur pemetaan ulang

Google Play Game di PC mendukung pemetaan ulang kontrol keyboard berdasarkan binding tombol yang disediakan game Anda menggunakan Input SDK. Fitur ini merupakan pilihan dan dapat sepenuhnya dinonaktifkan. Misalnya, Anda mungkin ingin menetapkan antarmuka pemetaan ulang keyboard Anda sendiri. Guna menonaktifkan pemetaan ulang untuk game, Anda hanya perlu menentukan opsi pemetaan ulang dinonaktifkan untuk InputMap (lihat Build InputMap untuk informasi lebih lanjut).

Untuk mengakses fitur ini, pengguna harus membuka overlay, lalu mengklik tindakan yang ingin dipetakan ulang. Setelah setiap peristiwa pemetaan ulang, Google Play Game di PC memetakan setiap kontrol yang dipetakan oleh pengguna menjadi kontrol default yang diharapkan akan diterima game Anda, sehingga game Anda tidak perlu mengkhawatirkan adanya pemetaan ulang pemain. Anda dapat memilih untuk mengupdate aset yang digunakan untuk menampilkan kontrol keyboard dalam game dengan menambahkan callback untuk peristiwa pemetaan ulang.

Upaya untuk memetakan ulang tombol

Google Play Game di PC menyimpan kontrol yang sudah dipetakan ulang secara lokal untuk setiap pengguna, mengaktifkan persistensi kontrol di seluruh sesi game. Informasi ini disimpan di disk hanya untuk platform PC dan tidak memengaruhi pengalaman perangkat seluler. Data kontrol dihapus berdasarkan uninstal atau instal ulang Google Play Game di PC oleh pengguna. Data ini tidak berkesinambungan pada beragam perangkat PC.

Untuk mendukung fitur pemetaan ulang dalam game Anda, hindari batasan-batasan berikut:

Pembatasan pemetaan ulang

Fitur pemetaan ulang dapat dinonaktifkan dalam game Anda jika binding tombol berisi salah satu dari kasus-kasus berikut:

  • InputActions multitombol yang tidak ditulis dengan tombol pengubah + non tombol pengubah. Misalnya, Shift + A valid, namun A + B, Ctrl + Alt atau Shift + A + Tab tidak valid.
  • InputMap berisi InputActions, InputGroups atau InputContexts dengan ID unik yang berulang.

Pembatasan pemetaan ulang

Ketika mendesain binding tombol untuk pemetaan ulang, pertimbangkan pembatasan berikut:

  • Pemetaan ulang ke kombinasi tombol tidak didukung. Contohnya, pengguna tidak dapat memetakan ulang Shift + A menjadi Ctrl + B atau A menjadi Shift + A.
  • Pemetaan ulang tidak didukung untuk InputActions dengan tombol mouse. Sebagai contoh, Shift + Klik kanan tidak dapat dipetakan ulang.

Menguji pemetaan ulang tombol pada Emulator Google Play Game di PC

Anda dapat kapan pun mengaktifkan fitur pemetaan ulang di Emulator Google Play Game di PC dengan memberikan perintah adb berikut:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

Perubahan overlay seperti yang ada dalam gambar berikut:

Overlay dengan pemetaan ulang tombol diaktifkan.

Menambahkan SDK

Menginstal Input SDK sesuai dengan platform pengembangan Anda.

Java dan Kotlin

Dapatkan Input SDK untuk Java atau Kotlin dengan menambahkan dependensi ke file build.gradle level modul:

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

Unity

Input SDK adalah paket Unity standar dengan beberapa dependensi.

Diperlukan instalasi paket dengan semua dependensi. Ada beberapa cara untuk menginstal paket.

Menginstal .unitypackage

Download file unitypackage Input SDK dengan semua dependensinya. Anda dapat menginstal .unitypackage dengan memilih Assets > Import package > Custom Package serta menemukan lokasi file yang sudah didownload.

Menginstal menggunakan UPM

Anda juga bisa menginstal paket menggunakan Pengelola Paket Unity dengan mendownload .tgz dan menginstal dependensinya:

Menginstal menggunakan OpenUPM

Anda dapat menginstal paket menggunakan OpenUPM.

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

Contoh game

Untuk contoh cara berintegrasi dengan Input SDK, lihat AGDK Tunnel untuk game Kotlin atau Java, dan Trivial Kart untuk game Unity.

Membuat binding tombol Anda

Daftarkan binding tombol dengan membangun InputMap dan mengembalikannya dengan InputMappingProvider. Contoh berikut menguraikan 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

Menentukan tindakan input Anda

Class InputAction digunakan untuk memetakan kombinasi tombol atau tombol ke tindakan game. InputActions harus memiliki ID unik di seluruh InputActions.

Jika Anda mendukung pemetaan ulang, Anda dapat menentukan hal-hal yang dapat dipetakan ulang oleh InputActions. Jika game Anda tidak mendukung pemetaan ulang, Anda harus mengatur opsi pemetaan ulang dinonaktifkan untuk semua InputActions, namun Input SDK cukup cerdas untuk menonaktifkan pemetaan ulang jika Anda tidak mendukungnya dalam InputMap.

Contoh ini memetakan tombol spasi ke tindakan Drive.

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

Tombol InputAction tunggal ditampilkan di overlay.

Tindakan juga dapat mewakili input mouse. Contoh ini menetapkan Klik kiri ke tindakan Gerakan:

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 mouse ditampilkan di overlay.

Kombinasi tombol ditentukan dengan meneruskan beberapa kode tombol ke InputAction. Dalam contoh ini spasi + shift dipetakan ke tindakan Turbo, yang berfungsi bahkan saat Spasi dipetakan ke Drive.

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 multitombol ditampilkan di overlay.

Dengan Input SDK, Anda dapat menggabungkan mouse dan tombol secara bersamaan untuk satu tindakan. Contoh ini menunjukkan ketika tombol Shift dan Klik kanan ditekan secara bersamaan akan menambahkan titik jalan dalam game ini:

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

Kombinasi InputAction tombol + mouse ditampilkan di overlay.

InputAction memiliki kolom berikut:

  • ActionLabel: string yang ditampilkan di UI untuk mewakili tindakan ini. Pelokalan tidak dilakukan secara otomatis, jadi lakukan pelokalan apa pun terlebih dahulu.
  • InputControls: menentukan kontrol input yang digunakan tindakan ini. Kontrol dipetakan ke glyph yang konsisten di overlay.
  • InputActionId: Objek InputIdentifier yang menyimpan ID nomor dan versi dari InputAction (lihat Melacak ID Tombol untuk informasi selengkapnya).
  • InputRemappingOption: salah satu dari InputEnums.REMAP_OPTION_ENABLED atau InputEnums.REMAP_OPTION_DISABLED. Menentukan apabila tindakan diaktifkan untuk pemetaan ulang. Jika game tidak mendukung pemetaan ulang, Anda bisa melewati kolom ini atau cukup dengan menonaktifkannya.
  • RemappedInputControls: objek InputControls hanya-baca digunakan untuk membaca tombol yang dipetakan ulang oleh pengguna pada peristiwa pemetaan ulang (digunakan untuk mendapatkan pemberitahuan tentang pemetaan ulang peristiwa).

InputControls mewakili input yang terkait dengan suatu tindakan dan berisi kolom berikut:

  • AndroidKeycodes: adalah daftar bilangan bulat yang mewakili input keyboard yang terkait dengan suatu tindakan. Daftar tersebut ditentukan di class KeyEvent atau class AndroidKeycode untuk Unity.
  • MouseActions: adalah daftar nilai MouseAction yang mewakili input mouse yang terkait dengan tindakan ini.

Menentukan grup input

InputActions dikelompokkan dengan tindakan yang terkait secara logis menggunakan InputGroups untuk meningkatkan visibilitas navigasi dan kontrol di overlay. Tiap-tiap ID InputGroup harus berbentuk unik di seluruh InputGroups dalam game.

Dengan mengatur tindakan input ke dalam grup, Anda memudahkan pemain menemukan binding tombol yang tepat untuk situasi mereka saat ini.

Jika Anda mendukung pemetaan ulang, Anda dapat menentukan hal-hal yang dapat dipetakan ulang oleh InputGroups. Jika game Anda tidak mendukung pemetaan ulang, Anda harus mengatur opsi pemetaan ulang dinonaktifkan untuk semua InputGroups, namun Input SDK cukup cerdas untuk menonaktifkan pemetaan ulang jika Anda tidak mendukungnya dalam 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
);

Contoh berikut menampilkan Kontrol jalan dan grup input Kontrol menu di overlay:

Overlay menampilkan InputMap yang berisi kontrol Jalan dan
grup input kontrol Menu.

InputGroup memiliki kolom berikut:

  • GroupLabel: adalah string yang akan ditampilkan di overlay, yang dapat digunakan untuk mengelompokkan kumpulan tindakan secara logis. String ini tidak secara otomatis dilokalkan.
  • InputActions: daftar objek InputAction yang Anda tentukan pada langkah terdahulu. Semua tindakan ini ditampilkan secara visual di bawah judul grup.
  • InputGroupId: objek InputIdentifier yang menyimpan ID nomor dan versi InputGroup. Lihat Pelacakan ID Tombol untuk informasi selengkapnya.
  • InputRemappingOption: salah satu dari InputEnums.REMAP_OPTION_ENABLED atau InputEnums.REMAP_OPTION_DISABLED. Apabila dinonaktifkan, semua objek InputAction yang menjadi milik grup ini akan menonaktifkan pemetaan ulangnya bahkan jika objek tersebut menetapkan pengaktifan opsi pemetaan ulangnya. Jika diaktifkan, semua tindakan yang menjadi milik grup ini dapat dipetakan ulang kecuali ditentukan dinonaktifkan oleh tindakan perorangan.

Menentukan konteks input Anda

InputContexts memungkinkan game Anda menggunakan serangkaian kontrol keyboard yang berbeda untuk beragam suasana dalam game. Contoh:

  • Anda dapat menentukan rangkaian input yang berbeda untuk menavigasi menu versus gerakan dalam game.
  • Anda dapat menentukan kumpulan input yang berbeda, bergantung pada mode gerakan dalam game, seperti mengemudi vs berjalan.
  • Anda dapat menentukan kumpulan input yang berbeda berdasarkan status game saat ini, seperti membuka dunia dalam game versus memainkan tokoh game dalam level individu.

Ketika menggunakan InputContexts, overlay menunjukkan terlebih dahulu kelompok konteks yang digunakan. Untuk mengaktifkan perilaku ini, panggil setInputContext() untuk menentukan konteks kapan pun game memasuki suasana yang berbeda. Gambar berikut menunjukkan perilaku ini dalam suasana "mengemudi", tindakan Kontrol jalan ditampilkan di atas overlay. Ketika membuka menu "store", tindakan "Kontrol menu" ditampilkan di atas overlay.

InputContexts mengurutkan grup dalam overlay.

Update overlay ini dicapai dengan menyetel InputContext yang berbeda pada titik yang berbeda dalam game. Untuk melakukannya:

  1. Kelompokkan InputActions dengan tindakan yang terkait secara logis menggunakan InputGroups
  2. Tetapkan InputGroups ke InputContext untuk bagian yang berbeda dalam game

InputGroups yang menjadi milik InputContext yang sama tidak boleh memiliki InputActions yang bertentangan bila tombol yang sama digunakan. Merupakan praktik yang baik untuk menugaskan setiap InputGroup menjadi satu InputContext.

Kode contoh berikut menunjukkan logika 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 memiliki kolom berikut:

  • LocalizedContextLabel: string yang mendeskripsikan grup yang termasuk dalam konteksnya.
  • InputContextId: Objek InputIdentifier yang menyimpan ID nomor dan versi dari InputContext (lihat Melacak ID Tombol untuk informasi selengkapnya).
  • ActiveGroups: daftar InputGroups untuk digunakan dan ditampilkan di bagian atas overlay ketika konteks dalam keadaan aktif.

Membangun peta input

InputMap adalah kumpulan semua objek InputGroup yang tersedia dalam sebuah game, dan karena itu semua objek InputAction dapat diharapkan untuk dijalankan.

Ketika melaporkan binding tombol, Anda membangun InputMap dengan semua InputGroups yang digunakan dalam game.

Jika game tidak mendukung pemetaan ulang, atur opsi pemetaan ulang menjadi nonaktif dan tombol reservasi kosong.

Contoh berikut membangun InputMap yang digunakan untuk melaporkan sekumpulan 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 memiliki kolom berikut:

  • InputGroups: InputGroups yang dilaporkan oleh game Anda. Grup ditampilkan secara berurutan di overlay, kecuali ditentukan bahwa grup saat ini menggunakan panggilan setInputContext().
  • MouseSettings: Objek MouseSettings menunjukkan bahwa sensitivitas mouse dapat disesuaikan dan bahwa mouse terbalik pada sumbu y.
  • InputMapId: Objek InputIdentifier yang menyimpan ID nomor dan versi InputMap (lihat Melacak ID Tombol untuk informasi selengkapnya).
  • InputRemappingOption: salah satu dari InputEnums.REMAP_OPTION_ENABLED atau InputEnums.REMAP_OPTION_DISABLED. Menentukan apakah fitur pemetaan ulang diaktifkan.
  • ReservedControls: daftar InputControls yang tidak diizinkan untuk dipetakan ulang oleh pengguna.

Melacak ID tombol

Objek InputAction, InputGroup, InputContext dan InputMap berisi objek InputIdentifier yang menyimpan ID nomor unik dan ID versi string. Melacak versi string objek Anda bersifat opsional tetapi disarankan untuk melacak versi InputMap. Jika versi string tidak disediakan maka string kosong. Versi string diperlukan untuk objek InputMap.

Contoh berikut menetapkan versi string ke InputActions atau 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

ID nomor objek InputAction harus unik di seluruh InputActions di InputMap Anda. Demikian pula, ID objek InputGroup harus unik di seluruh InputGroups di InputMap. Contoh berikut menunjukkan cara menggunakan enum untuk melacak ID unik objek:

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 memiliki kolom berikut:

  • UniqueId: kumpulan ID nomor unik untuk mengidentifikasi kumpulan data input secara unik.
  • VersionString: string versi yang dapat dibaca manusia ditentukan untuk mengidentifikasi suatu versi data input antara 2 versi perubahan data input.

Mendapatkan notifikasi mengenai peristiwa pemetaan ulang (Opsional)

Terima notifikasi mengenai peristiwa pemetaan ulang, untuk diberitahu tentang tombol yang digunakan dalam game. Ini memungkinkan game Anda memperbarui aset yang ditampilkan di layar game yang digunakan untuk menampilkan kontrol tindakan.

Gambar berikut menunjukkan contoh perilaku ini, yaitu setelah memetakan ulang tombol G, P dan S menjadi J, X dan T, elemen UI game diperbarui supaya menampilkan tombol yang ditentukan oleh pengguna.

UI bereaksi terhadap peristiwa pemetaan ulang menggunakan callback InputRemappingListener.

Fungsi ini dicapai dengan mendaftarkan callback InputRemappingListener . Untuk mengimplementasikan fitur ini, mulailah dengan mendaftarkan instance 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 diberitahukan pada waktu peluncuran setelah memuat kontrol yang dipetakan ulang yang disimpan pengguna, dan setiap kali pengguna memetakan ulang tombolnya.

Inisialisasi

Jika Anda menggunakan InputContexts, setel konteks di tiap transisi ke suasana baru, termasuk konteks pertama yang digunakan untuk suasana awal. Anda harus menyetel InputContext setelah Anda mendaftarkan InputMap Anda.

Jika Anda menggunakan InputRemappingListeners untuk diberi tahu tentang pemetaan ulang peristiwa, daftarkan InputRemappingListener sebelum mendaftarkan InputMappingProvider. Jika tidak, game Anda dapat melewatkan peristiwa penting selama waktu peluncuran.

Contoh berikut menunjukkan cara menginisialisasi 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
    }
}

Pembersihan

Batalkan pendaftaran instance InputMappingProvider dan instance InputRemappingListener apa pun ketika game diakhiri, walaupun Input SDK cukup cerdas untuk menghindari bocornya aset, jika Anda tidak menyadarinya:

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

Pengujian

Anda dapat menguji penerapan Input SDK dengan membuka overlay secara manual untuk melihat pengalaman pemain, atau melalui adb shell untuk menguji dan memverifikasi secara otomatis.

Emulator Google Play Game di PC memeriksa ketepatan peta input untuk menangani error yang umum terjadi. Untuk skenario seperti duplikat ID unik, gunakan peta input yang berbeda atau gagal pada aturan pemetaan ulang (jika pemetaan ulang diaktifkan), overlay menampilkan pesan error seperti contoh berikut: Overlay Input SDK.

Verifikasi penerapan Input SDK menggunakan adb pada command line. Untuk mendapatkan peta input saat ini, gunakan perintah adb shell berikut (ganti MY.PACKAGE.NAME dengan nama game Anda):

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

Anda akan melihat output yang serupa dengan ini jika berhasil mendaftarkan 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
}

Pelokalan

Input SDK tidak menggunakan sistem pelokalan Android. Akibatnya, Anda harus menyediakan string yang dilokalkan saat mengirimkan InputMap. Anda juga dapat menggunakan sistem pelokalan game engine Anda.

Proguard

Ketika menggunakan Proguard untuk meminifikasi game, tambahkan aturan berikut ke file konfigurasi proguard guna memastikan SDK tidak dicopot dari paket final Anda:

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

Langkah berikutnya

Setelah mengintegrasikan Input SDK ke dalam game, Anda dapat melanjutkan persyaratan Google Play Game di PC lainnya. Untuk informasi lebih lanjut, lihat Memulai Google Play Game di PC.