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:
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.
Praktik terbaik untuk mendesain binding tombol
Ketika mendesain binding tombol, pertimbangkan praktik terbaik berikut:
- Kelompokkan
InputActions
ke dalamInputGroups
yang terkait secara logis guna meningkatkan visibilitas navigasi dan kontrol selama gameplay. - Tetapkan setiap
InputGroup
ke paling banyak satuInputContext
.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 menggunakanInputContext
untuk semua suasana "menu-like". Gunakan beragamInputContexts
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 2InputActions
yang berlainan yang menjalankan tindakan yang sama dalam game Anda. Anda dapat menggunakan string label yang sama untukInputActions
, namun ID-nya harus berlainan. - Apabila tombol pengubah diterapkan ke serangkaian tombol, pertimbangkan agar memiliki satu
InputAction
dengan tombol pengubah, bukan beberapaInputActions
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()
denganInputContext
yang berisi daftar kosongInputGroups
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.
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
berisiInputActions
,InputGroups
atauInputContexts
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:
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:
- com.google.external-dependency-manager-1.2.172
- com.google.librarywrapper.java-0.2.0
- com.google.librarywrapper.openjdk8-0.2.0
- com.google.android.libraries.play.games.inputmapping-1.1.0-beta
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
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 );
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 );
Kombinasi tombol ditentukan dengan meneruskan beberapa kode tombol ke
InputAction
. Dalam contoh ini
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 );
Dengan Input SDK, Anda dapat menggabungkan mouse dan tombol secara bersamaan untuk
satu tindakan. Contoh ini menunjukkan ketika tombol
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 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
: ObjekInputIdentifier
yang menyimpan ID nomor dan versi dariInputAction
(lihat Melacak ID Tombol untuk informasi selengkapnya).InputRemappingOption
: salah satu dariInputEnums.REMAP_OPTION_ENABLED
atauInputEnums.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
: objekInputControls
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 nilaiMouseAction
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:
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 objekInputAction
yang Anda tentukan pada langkah terdahulu. Semua tindakan ini ditampilkan secara visual di bawah judul grup.InputGroupId
: objekInputIdentifier
yang menyimpan ID nomor dan versiInputGroup
. Lihat Pelacakan ID Tombol untuk informasi selengkapnya.InputRemappingOption
: salah satu dariInputEnums.REMAP_OPTION_ENABLED
atauInputEnums.REMAP_OPTION_DISABLED
. Apabila dinonaktifkan, semua objekInputAction
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.
Update overlay ini dicapai dengan menyetel InputContext
yang berbeda
pada titik yang berbeda dalam game. Untuk melakukannya:
- Kelompokkan
InputActions
dengan tindakan yang terkait secara logis menggunakanInputGroups
- Tetapkan
InputGroups
keInputContext
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
: ObjekInputIdentifier
yang menyimpan ID nomor dan versi dariInputContext
(lihat Melacak ID Tombol untuk informasi selengkapnya).ActiveGroups
: daftarInputGroups
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 panggilansetInputContext()
.MouseSettings
: ObjekMouseSettings
menunjukkan bahwa sensitivitas mouse dapat disesuaikan dan bahwa mouse terbalik pada sumbu y.InputMapId
: ObjekInputIdentifier
yang menyimpan ID nomor dan versiInputMap
(lihat Melacak ID Tombol untuk informasi selengkapnya).InputRemappingOption
: salah satu dariInputEnums.REMAP_OPTION_ENABLED
atauInputEnums.REMAP_OPTION_DISABLED
. Menentukan apakah fitur pemetaan ulang diaktifkan.ReservedControls
: daftarInputControls
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 ArrayListI<nteger(>)), 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
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:
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.