Tài liệu này mô tả cách thiết lập và hiển thị SDK Đầu vào trong những trò chơi có hỗ trợ Google Play Games trên máy tính. Các tác vụ bao gồm thêm SDK cho trò chơi của mình và tạo một bản đồ đầu vào, trong đó chứa sự gán đầu vào của trò chơi với hành động của người dùng.
Trước khi bạn bắt đầu
Trước khi thêm SDK Đầu vào vào trò chơi, bạn phải hỗ trợ hoạt động đầu vào bằng bàn phím và chuột thông qua hệ thống đầu vào của công cụ phát triển trò chơi.
SDK Đầu vào cung cấp thông tin cho Google Play Games trên máy tính về những chế độ điều khiển mà trò chơi của bạn sử dụng để người dùng có thể thấy những chế độ đó. SDK này cũng tuỳ ý cho phép gán lại bằng bàn phím cho người dùng.
Mỗi chế độ điều khiển là một InputAction
(ví dụ: "J" cho "Nhảy") và bạn sẽ sắp xếp InputActions
thành InputGroups
. Một InputGroup
có thể đại diện cho một chế độ khác trong trò chơi, chẳng hạn như "Lái xe", "Đi bộ" hoặc "Trình đơn chính". Bạn cũng có thể dùng InputContexts
để cho biết nhóm nào đang hoạt động ở các thời điểm khác nhau của trò chơi.
Bạn có thể bật chế độ tự động xử lý hoạt động ánh xạ bằng bàn phím cho mình, nhưng nếu muốn cung cấp giao diện điều khiển hoạt động ánh xạ của riêng mình thì bạn có thể tắt chế độ ánh xạ lại SDK Đầu vào.
Sơ đồ trình tự sau đây mô tả cách thức API của SDK Đầu vào hoạt động:
Khi trò chơi của bạn triển khai SDK Đầu vào, các chế độ điều khiển của bạn sẽ hiển thị trong lớp phủ Google Play Games trên máy tính.
Lớp phủ Google Play Games trên máy tính
Lớp phủ Google Play Games trên máy tính ("lớp phủ") hiển thị các chế độ điều khiển do trò chơi của bạn xác định. Người dùng sẽ truy cập vào lớp phủ bất cứ lúc nào bằng cách nhấn tổ hợp phím Shift + Tab.
Các phương pháp hay nhất để thiết kế các liên kết phím
Khi thiết kế liên kết phím, hãy cân nhắc các phương pháp hay nhất sau đây:
- Nhóm
InputActions
vàoInputGroups
có liên quan về mặt logic để cải thiện khả năng điều hướng và khả năng được phát hiện của các chế độ điều khiển trong khi chơi. - Gán mỗi
InputGroup
cho tối đa mộtInputContext
.InputMap
chi tiết mang lại một trải nghiệm tốt hơn khi điều hướng các chế độ điều khiển của bạn trong lớp phủ. - Tạo một
InputContext
cho mỗi loại cảnh khác nhau của trò chơi. Thông thường, bạn có thể dùng mộtInputContext
cho mọi cảnh "giống với trình đơn" của mình. Hãy sử dụngInputContexts
khác cho mọi trò chơi nhỏ trong trò chơi của bạn hoặc cho các chế độ điều khiển thay thế của một cảnh. - Nếu 2 hành động được thiết kế để dùng cùng một phím trong cùng một
InputContext
, hãy tận dụng chuỗi nhãn như "Tương tác/Kích hoạt". - Nếu 2 phím được thiết kế để liên kết đến cùng một
InputAction
, hãy dùng 2InputActions
khác nhau để thực hiện cùng một hành động trong trò chơi. Bạn có thể tận dụng cùng một văn bản nhãn cho cả 2InputActions
, nhưng ID thì phải khác nhau. - Nếu một phím bổ trợ được áp dụng cho một loạt phím, hãy cân nhắc dùng một
InputAction
cho phím bổ trợ đó thay vì dùng nhiềuInputActions
cho các tổ hợp phím bổ trợ (ví dụ: dùng phím Shift cùng các phím W, A, S, D thay vì dùng các tổ hợp phím Shift + W, Shift + A, Shift + S, Shift + D). - Tính năng ánh xạ lại đầu vào sẽ tự động bị tắt khi người dùng ghi vào trường văn bản. Hãy áp dụng các phương pháp hay nhất khi triển khai các trường văn bản trong Android nhằm đảm bảo rằng Android có thể phát hiện các trường văn bản trong trò chơi của bạn và ngăn những phím được ánh xạ lại can thiệp vào các trường đó. Nếu trò chơi của bạn phải sử dụng các trường văn bản hiếm gặp, thì bạn có thể dùng
setInputContext()
vớiInputContext
có chứa một danh sáchInputGroups
trống để tắt thủ công tính năng ánh xạ lại. - Nếu trò chơi của bạn hỗ trợ tính năng ánh xạ lại, hãy nhớ rằng việc cập nhật các liên kết phím là một thao tác nhạy cảm có thể xung đột với các phiên bản mà người dùng đã lưu. Tránh thay đổi ID của các chế độ điều khiển hiện có khi có thể.
Tính năng gán lại
Google Play Games trên máy tính hỗ trợ tính năng ánh xạ lại chế độ điều khiển bằng bàn phím dựa trên các liên kết phím mà trò chơi của bạn cung cấp thông qua SDK Đầu vào. Đây là tính năng không bắt buộc và có thể tắt hoàn toàn. Ví dụ: bạn nên cung cấp giao diện ánh xạ lại bàn phím của riêng mình. Để tắt tính năng ánh xạ lại cho trò chơi, bạn chỉ cần chỉ định tuỳ chọn ánh xạ lại ở trạng thái tắt cho InputMap
(xem bài viết Tạo InputMap để biết thêm thông tin).
Để dùng tính năng này, người dùng cần mở lớp phủ rồi nhấp vào hành động mà họ muốn gán lại. Sau mỗi sự kiện ánh xạ lại, Google Play Games trên máy tính sẽ ánh xạ từng lựa chọn điều khiển do người dùng ánh xạ lại với các chế độ điều khiển mặc định mà trò chơi muốn nhận được, do đó, trò chơi của bạn không cần nhận biết về hoạt động ánh xạ lại của người chơi. Bạn có thể tuỳ ý cập nhật các thành phần dùng để hiển thị các chế độ điều khiển bằng bàn phím trong trò chơi của mình bằng cách thêm một lệnh gọi lại cho các sự kiện gán lại.
Google Play Games trên máy tính lưu trữ cục bộ các chế độ điều khiển được ánh xạ lại cho từng người dùng để họ có thể sử dụng cùng chế độ điều khiển đã lưu giữa các phiên chơi. Thông tin này chỉ được lưu trữ trên ổ đĩa dành cho nền tảng máy tính và không làm ảnh hưởng đến trải nghiệm trên thiết bị di động. Dữ liệu điều khiển sẽ bị xoá khi người dùng gỡ cài đặt hoặc cài đặt lại Google Play Games trên máy tính. Dữ liệu này không tồn tại vĩnh viễn trên nhiều thiết bị máy tính.
Để hỗ trợ tính năng gán lại trong trò chơi của bạn, hãy tránh các hạn chế sau:
Các hạn chế của tính năng gán lại
Bạn có thể tắt các tính năng ánh xạ lại trong trò chơi của mình nếu các liên kết phím có chứa bất kỳ trường hợp nào sau đây:
InputActions
dùng nhiều phím không có một phím bổ trợ + một phím không phải phím bổ trợ. Ví dụ: tổ hợp phím Shift + A là hợp lệ nhưng tổ hợp phím A + B, Ctrl + Alt hoặc Shift + A + Tab thì không.InputMap
có chứaInputActions
,InputGroups
hoặcInputContexts
có mã nhận dạng duy nhất bị lặp.
Các điểm hạn chế của tính năng gán lại
Khi thiết kế các liên kết phím để ánh xạ lại, hãy xem xét các điểm hạn chế sau:
- Không hỗ trợ tính năng gán lại cho các tổ hợp phím. Ví dụ: người dùng không thể gán lại tổ hợp phím Shift + A cho Ctrl + B hoặc phím A cho tổ hợp phím Shift + A.
- Không hỗ trợ tính năng ánh xạ lại cho
InputActions
bằng các nút trên chuột. Ví dụ: Không thể gán lại tổ hợp phím Shift + Nhấp chuột phải.
Kiểm thử tính năng gán lại phím trên Trình mô phỏng Google Play Games trên máy tính
Bạn có thể bật tính năng ánh xạ lại trong Trình mô phỏng Google Play Games trên máy tính bất cứ lúc nào bằng cách phát lệnh adb sau đây:
adb shell dumpsys input_mapping_service --set RemappingFlagValue true
Sự thay đổi lớp phủ như trong hình ảnh sau đây:
Thêm SDK
Cài đặt SDK Đầu vào theo nền tảng phát triển của bạn.
Java và Kotlin
Tải SDK Đầu vào cho Java hoặc Kotlin bằng cách thêm một phần phụ thuộc vào tệp build.gradle
ở cấp mô-đun:
dependencies {
implementation 'com.google.android.libraries.play.games:inputmapping:1.1.0-beta'
...
}
Unity
SDK Đầu vào là một gói Unity tiêu chuẩn có một vài phần phụ thuộc.
Bạn cần cài đặt gói này cùng với tất cả các phần phụ thuộc. Có một số cách để cài đặt các gói này.
Cài đặt .unitypackage
Tải tệp unitypackage của SDK Đầu vào xuống cùng với tất cả các phần phụ thuộc của nó. Bạn có thể cài đặt .unitypackage
bằng cách chọn Assets > Import package > Custom Package (Thành phần > Nhập gói > Gói tuỳ chỉnh) và tìm tệp bạn đã tải xuống.
Cài đặt bằng UPM
Ngoài ra, bạn có thể cài đặt gói này thông qua Trình quản lý gói của Unity bằng cách tải .tgz
xuống và cài đặt các phần phụ thuộc của nó:
- 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
Cài đặt bằng OpenUPM
Bạn có thể cài đặt gói này bằng cách sử dụng OpenUPM.
$ openupm add com.google.android.libraries.play.games.inputmapping
Trò chơi mẫu
Để biết ví dụ về cách tích hợp với SDK Đầu vào, hãy xem AGDK Tunnel (Đường hầm AGDK) dành cho các trò chơi viết bằng Kotlin hoặc Java và Trivial Kart dành cho trò chơi viết bằng Unity.
Tạo các liên kết phím
Đăng ký các liên kết phím của bạn bằng cách tạo một InputMap
và trả nó về bằng một InputMappingProvider
. Ví dụ sau đây mô tả một 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
Xác định hành động đầu vào
Lớp InputAction
dùng để liên kết một phím hoặc tổ hợp phím với một hành động trong trò chơi. InputActions
phải có mã nhận dạng duy nhất trên tất cả InputActions
.
Nếu đang hỗ trợ tính năng ánh xạ lại, thì bạn có thể xác định InputActions
nào có thể được ánh xạ lại. Nếu trò chơi của bạn không hỗ trợ tính năng ánh xạ lại, thì bạn nên đặt tuỳ chọn ánh xạ lại ở trạng thái tắt cho tất cả InputActions
, tuy nhiên, SDK Đầu vào có thể tắt tính năng ánh xạ lại nếu bạn không hỗ trợ tính năng này trong InputMap
.
Ví dụ sau liên kết phím
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 );
Các hành động cũng có thể đại diện cho thao tác đầu vào bằng chuột. Ví dụ sau gán thao tác Nhấp chuột trái cho hành động Move (Di chuyển):
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 );
Các tổ hợp phím được chỉ định bằng cách chuyển nhiều mã phím vào InputAction
của bạn. Trong ví dụ này, tổ hợp phím
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 );
SDK Đầu vào cho phép bạn kết hợp các nút trên chuột và phím cho một hành động. Ví dụ này cho thấy một điểm tham chiếu sẽ được thêm vào trò chơi mẫu sau đây khi nhấn đồng thời phím
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 có các trường sau đây:
ActionLabel
: là chuỗi hiển thị trong giao diện người dùng để thể hiện hành động này. Quá trình bản địa hoá không tự động được thực hiện, vì vậy, hãy thực hiện trước mọi quá trình bản địa hoá.InputControls
: xác định các chế độ điều khiển đầu vào mà hành động này sử dụng. Chế độ điều khiển liên kết với các ký tự nhất quán trong lớp phủ.InputActionId
: đối tượngInputIdentifier
có chứa phiên bản và mã số củaInputAction
(xem phần Theo dõi mã nhận dạng phím để biết thêm thông tin).InputRemappingOption
: một trong sốInputEnums.REMAP_OPTION_ENABLED
hoặcInputEnums.REMAP_OPTION_DISABLED
. Xác định xem hành động này có được phép gán lại không. Nếu trò chơi của bạn không hỗ trợ tính năng ánh xạ lại, thì bạn có thể bỏ qua trường này hoặc chỉ cần đặt trường này thành tắt.RemappedInputControls
: đối tượngInputControls
chỉ đọc dùng để đọc phím được ánh xạ lại do người dùng đặt trên các sự kiện ánh xạ lại (dùng để nhận thông báo về sự kiện ánh xạ lại).
InputControls
là đầu vào được liên kết với một hành động và có chứa các trường sau:
AndroidKeycodes
: là danh sách các số nguyên tượng trưng cho đầu vào bằng bàn phím được liên kết với một hành động. Các số nguyên này được xác định trong lớp KeyEvent hoặc lớp AndroidKeycode cho Unity.MouseActions
: là danh sách các giá trịMouseAction
tượng trưng cho đầu vào bằng chuột được liên kết với hành động này.
Xác định nhóm đầu vào
InputActions
được nhóm với các hành động có liên quan về mặt logic bằng cách sử dụng InputGroups
để cải thiện khả năng điều hướng và khả năng được phát hiện của các chế độ điều khiển trong lớp phủ. Mỗi mã InputGroup
phải là duy nhất trên tất cả InputGroups
trong trò chơi của bạn.
Bằng cách xếp hành động đầu vào thành các nhóm, bạn giúp người chơi tìm thấy đúng liên kết phím cho bối cảnh hiện tại của họ dễ dàng hơn.
Nếu đang hỗ trợ tính năng ánh xạ lại, thì bạn có thể xác định InputGroups
nào có thể được ánh xạ lại. Nếu trò chơi của bạn không hỗ trợ tính năng ánh xạ lại, thì bạn nên đặt tuỳ chọn ánh xạ lại ở trạng thái tắt cho tất cả InputGroups
, tuy nhiên, SDK Đầu vào có thể tắt tính năng ánh xạ lại nếu bạn không hỗ trợ tính năng này trong 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 );
Ví dụ sau đây hiển thị các nhóm đầu vào là Road controls (Điều khiển đường đi) và Menu controls (Điều khiển trình đơn) trong lớp phủ:
InputGroup
có các trường sau đây:
GroupLabel
: là một chuỗi hiển thị trong lớp phủ có thể dùng để nhóm một loạt hành động theo logic. Chuỗi này không tự động được bản địa hoá.InputActions
: là một danh sách các đối tượngInputAction
mà bạn xác định trong bước trước. Tất cả những hành động này đều được hiển thị trực quan bên dưới tiêu đề nhóm.InputGroupId
: đối tượngInputIdentifier
có chứa phiên bản và mã số củaInputGroup
. Hãy xem phần Theo dõi mã nhận dạng phím để biết thêm thông tin.InputRemappingOption
: một trong sốInputEnums.REMAP_OPTION_ENABLED
hoặcInputEnums.REMAP_OPTION_DISABLED
. Nếu bị tắt, tất cả các đối tượngInputAction
thuộc nhóm này sẽ bị tắt tính năng ánh xạ lại ngay cả khi chúng chỉ định tuỳ chọn ánh xạ lại ở trạng thái bật. Nếu được bật, tất cả các hành động thuộc nhóm này đều có thể ánh xạ lại trừ phi các hành động riêng lẻ chỉ định là tắt.
Xác định bối cảnh đầu vào
InputContexts
cho phép trò chơi của bạn sử dụng một loạt chế độ điều khiển khác bằng bàn phím cho các cảnh khác nhau của trò chơi. Ví dụ:
- Bạn có thể chỉ định các loạt đầu vào khác nhau để điều hướng trình đơn và di chuyển trong trò chơi.
- Bạn có thể chỉ định các loạt đầu vào riêng tuỳ theo chế độ chuyển động trong trò chơi, chẳng hạn như lái xe và đi bộ.
- Bạn có thể chỉ định các loạt đầu vào khác nhau tuỳ theo trạng thái hiện tại của trò chơi, chẳng hạn như khám phá tổng thể và chơi một cấp độ riêng lẻ.
Khi sử dụng InputContexts
, trước tiên, lớp phủ này sẽ hiện các nhóm bối cảnh đang sử dụng. Để cho phép hành động này, hãy gọi setInputContext()
để đặt bối cảnh bất cứ khi nào trò chơi của bạn chuyển sang một cảnh khác. Hình ảnh sau đây minh hoạ hành động này: trong cảnh "lái xe", hành động Road controls (Điều khiển đường đi) hiện ở đầu lớp phủ. Khi mở trình đơn "store" (cửa hàng), hành động "Menu controls" (Điều khiển trình đơn) hiển thị ở đầu lớp phủ.
Bạn sẽ thấy những thông tin cập nhật này về lớp phủ khi đặt một InputContext
khác tại các thời điểm khác nhau trong trò chơi. Cách thực hiện việc này:
- Nhóm
InputActions
với các hành động có liên quan về mặt logic bằngInputGroups
- Chỉ định những
InputGroups
này cho mộtInputContext
đối với các phần khác nhau trong trò chơi của bạn
InputGroups
thuộc cùng một InputContext
không thể có InputActions
xung đột khi dùng cùng một phím. Tốt nhất là nên chỉ định từng InputGroup
cho một InputContext
.
Mã mẫu sau đây minh hoạ logic 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
có các trường sau đây:
LocalizedContextLabel
: một chuỗi mô tả các nhóm thuộc bối cảnh này.InputContextId
: đối tượngInputIdentifier
có chứa phiên bản và mã số củaInputContext
(xem phần Theo dõi mã nhận dạng phím để biết thêm thông tin).ActiveGroups
: một danh sáchInputGroups
để dùng và hiển thị ở đầu lớp phủ khi bối cảnh này ở trạng thái hoạt động.
Tạo một bản đồ đầu vào
InputMap
là tập hợp tất cả các đối tượng InputGroup
có trong một trò chơi, do đó sẽ có mọi đối tượng InputAction
mà người chơi muốn thực hiện.
Khi báo cáo các liên kết phím, bạn sẽ tạo một InputMap
bằng tất cả các InputGroups
dùng trong trò chơi của mình.
Nếu trò chơi của bạn không hỗ trợ tính năng ánh xạ lại, hãy đặt tuỳ chọn ánh xạ lại ở trạng thái tắt và các phím dành riêng ở trạng thái trống.
Ví dụ sau đây tạo một InputMap
dùng để báo cáo một tập hợp 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
có các trường sau đây:
InputGroups
: InputGroups được trò chơi của bạn báo cáo. Các nhóm sẽ hiển thị theo thứ tự trong lớp phủ, trừ phi các nhóm hiện tại đang được sử dụng gọisetInputContext()
chỉ định khác.MouseSettings
: Đối tượngMouseSettings
cho biết rằng bạn có thể điều chỉnh độ nhạy của chuột và chuột được đảo ngược trên trục y.InputMapId
: đối tượngInputIdentifier
có chứa phiên bản và mã số củaInputMap
(xem phần Theo dõi mã nhận dạng phím để biết thêm thông tin).InputRemappingOption
: một trong sốInputEnums.REMAP_OPTION_ENABLED
hoặcInputEnums.REMAP_OPTION_DISABLED
. Xác định xem tính năng gán lại có được bật hay không.ReservedControls
: một danh sáchInputControls
mà người dùng sẽ không được phép gán lại.
Theo dõi mã nhận dạng phím
Các đối tượng InputAction
, InputGroup
, InputContext
và InputMap
chứa một đối tượng InputIdentifier
lưu trữ một mã phiên bản chuỗi và mã số duy nhất.
Việc theo dõi phiên bản chuỗi của các đối tượng là không bắt buộc nhưng bạn nên theo dõi các phiên bản của InputMap
. Nếu phiên bản chuỗi không được cung cấp, thì chuỗi đó trống. Bắt buộc phải có phiên bản chuỗi cho các đối tượng InputMap
.
Ví dụ sau đây sẽ chỉ định một phiên bản chuỗi cho InputActions
hoặc 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
Mã số của các đối tượng InputAction
phải là duy nhất trên tất cả các InputActions
trong InputMap
. Tương tự, mã đối tượng InputGroup
phải là duy nhất trên tất cả các InputGroups
trong một InputMap
. Mẫu sau đây minh hoạ cách dùng enum
để theo dõi mã nhận dạng duy nhất của đối tượng:
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
có các trường sau đây:
UniqueId
: một loạt mã số duy nhất dùng để xác định rõ một loạt dữ liệu đầu vào nhất định theo cách riêng.VersionString
: một loạt chuỗi phiên bản mà con người có thể đọc được để xác định một phiên bản dữ liệu đầu vào giữa 2 phiên bản thay đổi dữ liệu đầu vào.
Nhận thông báo về sự kiện gán lại (Không bắt buộc)
Nhận thông báo về các sự kiện gán lại để biết các phím đang được dùng trong trò chơi của bạn. Việc này cho phép trò chơi của bạn cập nhật các thành phần xuất hiện trên màn hình trò chơi dùng để hiển thị các chế độ điều khiển hành động.
Hình ảnh sau đây minh hoạ ví dụ về hành động này sau khi ánh xạ lại lần lượt các phím
Bạn có thể thực hiện chức năng này bằng cách đăng ký một lệnh gọi lại InputRemappingListener
. Để triển khai tính năng này, hãy bắt đầu bằng cách đăng ký một thực thể 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
nhận được thông báo tại thời điểm chạy sau khi tải các chế độ điều khiển ánh xạ lại do người dùng lưu và sau mỗi lần người dùng ánh xạ lại các phím của họ.
Khởi tạo
Nếu bạn đang dùng InputContexts
, hãy đặt bối cảnh trên mỗi lần chuyển đổi sang một cảnh mới, bao gồm cả bối cảnh đầu tiên dùng cho cảnh ban đầu của bạn. Bạn cần đặt InputContext
sau khi đã đăng ký InputMap
.
Nếu bạn đang dùng InputRemappingListeners
để nhận thông báo về các sự kiện ánh xạ lại, hãy đăng ký InputRemappingListener
trước khi đăng ký InputMappingProvider
, nếu không, trò chơi của bạn có thể bỏ lỡ các sự kiện quan trọng trong thời gian ra mắt.
Mẫu sau đây trình bày cách khởi tạo 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 } }
Dọn dẹp
Huỷ đăng ký thực thể InputMappingProvider
và mọi thực thể InputRemappingListener
khi trò chơi của bạn chuyển sang trạng thái đóng, mặc dù SDK Đầu vào có thể tránh được tình trạng rò rỉ tài nguyên nếu bạn không làm vậy:
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 } }
Kiểm thử
Bạn có thể kiểm thử quá trình triển khai SDK Đầu vào bằng cách mở thủ công lớp phủ để xem trải nghiệm của người chơi hoặc thông qua adb shell để xác minh và kiểm thử tự động.
Trình mô phỏng Google Play Games trên máy tính kiểm tra tính chính xác của bản đồ đầu vào đối với các lỗi thường gặp. Đối với các trường hợp như trùng lặp mã nhận dạng duy nhất, sử dụng các bản đồ đầu vào khác nhau hoặc không tuân thủ các quy tắc ánh xạ lại (nếu tính năng ánh xạ lại ở trạng thái bật), lớp phủ sẽ hiện một thông báo lỗi như bên dưới:
Xác minh quá trình triển khai SDK Đầu vào bằng adb
ở dòng lệnh.
Để tải bản đồ đầu vào hiện tại, hãy sử dụng lệnh adb shell
sau (thay thế MY.PACKAGE.NAME
bằng tên trò chơi của bạn):
adb shell dumpsys input_mapping_service --get MY.PACKAGE.NAME
Bạn sẽ thấy kết quả tương tự như sau nếu đăng ký thành công 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
}
Bản địa hoá
SDK Đầu vào không sử dụng hệ thống bản địa hoá của Android. Do đó, bạn phải cung cấp các chuỗi đã bản địa hoá khi gửi InputMap
. Bạn cũng có thể dùng hệ thống bản địa hoá của công cụ phát triển trò chơi.
Proguard
Khi dùng Proguard để thu nhỏ trò chơi, hãy thêm các quy tắc sau vào tệp cấu hình proguard để đảm bảo SDK không bị loại bỏ khỏi gói cuối cùng của bạn:
-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }
Các bước tiếp theo
Sau khi tích hợp SDK Đầu vào với trò chơi của mình, bạn có thể tiếp tục thực hiện mọi yêu cầu còn lại của Google Play Games trên máy tính. Để biết thêm thông tin, hãy xem bài viết Bắt đầu dùng Google Play Games trên máy tính.