במסמך הזה מוסבר איך להגדיר ולהציג את ה-SDK לקלט משחקים שתומכים ב-Google Play Games במחשב. המשימות כוללות את הוספת ה-SDK למשחק שלך וליצור מפת קלט, שמכילה את הקצאות של game-actions-to-user-input.
לפני שמתחילים
לפני שמוסיפים את ה-SDK לקלט למשחק, צריך לתמוך קלט מקלדת ועכבר באמצעות מנוע המשחק מערכת הקלט.
ה-SDK של קלט מספק ל-Google Play Games במחשב מידע על אילו גורמים שולטים בשימוש במשחק שלך, כדי שהם יוכלו להופיע בפני המשתמש. אפשר גם לאפשר למשתמשים מיפוי מחדש של המקלדת.
כל פקד הוא InputAction
(למשל J עבור 'Jump') ואתם מארגנים את
InputActions
בתוך InputGroups
. InputGroup
יכול לייצג
במצב המשחק, כמו 'נהיגה' או "הליכה" או 'תפריט ראשי'. אפשר גם
יש להשתמש ב-InputContexts
כדי לציין אילו קבוצות פעילות בנקודות שונות של
את המשחק.
אתם יכולים להפעיל את המיפוי מחדש של המקלדת כדי שיטופל בשבילכם באופן אוטומטי, אבל אם אתם מעדיפים לספק ממשק משלכם למיפוי מחדש. אז אתם יכולים להשבית מיפוי מחדש של ה-SDK.
בתרשים הרצף הבא מוסבר איך פועל ה-API של ה-SDK לקליטת נתונים:
כשמטמיעים במשחק את ה-SDK לקלט, הפקדים מוצגים בשכבת-העל של Google Play Games במחשב.
שכבת-על של Google Play Games במחשב
בשכבת-העל של Google Play Games במחשב ("שכבת-העל") מוצגים הפקדים מוגדר במשחק. המשתמשים ניגשים לשכבת-העל בכל עת על ידי מקישים על Shift + Tab.
שיטות מומלצות לעיצוב קישורי מפתחות
כשמתכננים את קישורי המפתחות, כדאי ליישם את השיטות המומלצות הבאות:
- כדי להשתפר, צריך לקבץ את
InputActions
ל-InputGroups
עם קשר לוגי ניווט ויכולת גילוי של הפקדים במהלך המשחק. - אפשר להקצות כל
InputGroup
ל-InputContext
אחד לכל היותר. גרגרים דקים בזכותInputMap
, חוויית הניווט באמצעי הבקרה שלך טובה יותר את שכבת-העל. - יוצרים
InputContext
לכל סוג סצנה במשחק. בדרך כלל אפשר להשתמש ב-InputContext
אחד לכל הפריטים מהסוגים "כמו תפריט" סצנות. אפשר להשתמש בהגדרותInputContexts
שונות לכל מיני-משחקים במשחק או עבור פקדים חלופיים לסצנה אחת. - אם שתי פעולות מתוכננות להשתמש באותו מפתח
InputContext
, אפשר להשתמש במחרוזת התווית כמו "Interact / Fire" (אינטראקציה / אש). - אם שני מפתחות נועדו להיות מקושרים לאותו
InputAction
, צריך להשתמש ב-2InputActions
שונות שמבצעות את אותה פעולה במשחק. אפשר להשתמש באותה מחרוזת תווית ב-InputActions
, אבל המזהה חייב להיות אחרת. - אם מקש צירוף מופעל על קבוצה של מפתחות, כדאי להשתמש במקש צירוף
InputAction
מחליפים באמצעות מקש הצירוף במקום כמה פעמיםInputActions
לשלב את מקש הצירוף (לדוגמה, להשתמש במקום זאת ב-Shift וב-W, A, S, D Shift + W, Shift + A, Shift + S, Shift + D). - מיפוי מחדש של קלט מושבת באופן אוטומטי כשהמשתמש כותב בטקסט
. כדי לוודא שהטמעת שדות טקסט ב-Android, יש לפעול לפי השיטות המומלצות
שמערכת Android יכולה לזהות שדות טקסט במשחק ולמנוע מקשים שמופו מחדש
להפריע להם. אם צריך להשתמש בטקסט לא קונבנציונלי במשחק
שדות שבהם אפשר להשתמש ב-
setInputContext()
עםInputContext
שמכיל רשימה ריקה שלInputGroups
כדי להשבית מיפוי מחדש באופן ידני. - אם המשחק שלך תומך במיפוי מחדש, כדאי לעדכן את קישורי המפתחות פעולה רגישה שעלולה להתנגש עם הגרסאות השמורות של המשתמש. בלי שינוי המזהים של אמצעי הבקרה הקיימים, כשהדבר אפשרי.
תכונת המיפוי מחדש
Google Play Games במחשב תומך במיפוי מחדש של השליטה במקלדת על סמך המקש
הקישורים שהמשחק שלך מספק באמצעות קלט SDK. הפעולה הזו היא אופציונלית
ניתן להשבית לגמרי. לדוגמה, ייתכן שתרצו לספק מקלדת משלכם.
למיפוי מחדש. כדי להשבית מיפוי מחדש של המשחק, צריך רק לציין
אפשרות המיפוי מחדש מושבתת ל-InputMap
(יש לעיין
כדי ליצור מפת קלט לקבלת מידע נוסף).
כדי לגשת לתכונה הזו, המשתמשים צריכים לפתוח את שכבת-העל וללחוץ על הפעולה שהם רוצים למפות מחדש. אחרי כל אירוע של מיפוי מחדש, Google Play Games במפות Google במחשב כל פקד שמופה מחדש על ידי המשתמש לפקדי ברירת המחדל שהמשחק מצפה לקבל מקבלים, כך שהמשחק לא צריך להיות מודע למיפוי מחדש של השחקן. שלך יכול לעדכן את הנכסים שמשמשים להצגת לחצני המקלדת את המשחק על ידי הוספת קריאה חוזרת (callback) למיפוי מחדש של אירועים.
ב-Google Play Games במחשב מאוחסנים אמצעי הבקרה שמופו מחדש באופן מקומי לכל משתמש, שמאפשרת שליטה באופן עקבי בכל סשנים של גיימינג. המידע הזה נשמר בדיסק רק לפלטפורמת ה-PC, ולא משפיע על החוויה בנייד. נתוני הבקרה נמחקים אחרי שהמשתמש מסיר את ההתקנה של Google Play Games במחשב או מתקין אותו מחדש. הנתונים האלה לא קבועים בכמה מכשירי מחשב.
כדי לתמוך בתכונת המיפוי מחדש במשחק שלך, עליך להימנע מההגבלות הבאות:
ההגבלות של מיפוי מחדש
אפשר להשבית תכונות של מיפוי מחדש במשחק אם קישורי המקשים כוללים במקרים הבאים:
- כמה מקשים
InputActions
שלא נכתבו על ידי מקש צירוף + a מקש ללא משנה. לדוגמה, Shift + A חוקי, אבל A + B, Ctrl + Alt או Shift + A + Tab לא מתאימים. - השדה
InputMap
מכיל את הערךInputActions
,InputGroups
אוInputContexts
עם מזהים ייחודיים שחוזרים על עצמם.
המגבלות של המיפוי מחדש
כשמתכננים את קישורי המפתחות למיפוי מחדש, כדאי לשקול את הדברים הבאים מגבלות:
- אין תמיכה במיפוי מחדש לשילובי מקשים. לדוגמה, משתמשים לא יכולים ממפים מחדש את Shift + A ל-Ctrl + B או A ל-Shift + A.
- אין תמיכה במיפוי מחדש עבור
InputActions
באמצעות לחצני העכבר. עבור לדוגמה, אי אפשר למפות מחדש את Shift + לחיצה ימנית.
בדיקת מיפוי מחדש של מפתחות באמולטור Google Play Games במחשב
אפשר להפעיל את תכונת המיפוי מחדש באמולטור Google Play Games במחשב בכל שלב על ידי ביצוע פקודת adb הבאה:
adb shell dumpsys input_mapping_service --set RemappingFlagValue true
שכבת-העל משתנה כמו בתמונה הבאה:
הוספת ה-SDK
מתקינים את ה-SDK לקלט בהתאם לפלטפורמת הפיתוח.
Java ו-Kotlin
קבלת ה-SDK של קלט עבור Java או Kotlin על ידי הוספת תלות
קובץ build.gradle
ברמת המודול:
dependencies {
implementation 'com.google.android.libraries.play.games:inputmapping:1.1.0-beta'
...
}
אחדות
ה-SDK לקלט הוא חבילת Unity רגילה עם מספר יחסי תלות.
נדרשת התקנת החבילה עם כל יחסי התלות. יש כמה דרכים כדי להתקין את החבילות.
התקנת .unitypackage
הורדת קובץ ה-unitypackage של קלט ה-SDK
על כל יחסי התלות שלו. אפשר להתקין את .unitypackage
על ידי בחירה של
נכסים > ייבא חבילה > חבילה מותאמת אישית ואיתור הקובץ שהורדתם.
התקנה באמצעות UPM
לחלופין אפשר להתקין את החבילה באמצעות
Package Manager של Unity מאת
מורידים את .tgz
ומתקינים את יחסי התלות שלו:
- 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
התקנה באמצעות OpenUPM
אפשר להתקין את החבילה באמצעות OpenUPM.
$ openupm add com.google.android.libraries.play.games.inputmapping
משחקים לדוגמה
דוגמאות לאופן השילוב עם קלט SDK: מנהרת AGDK למשחקי Kotlin או Java Trivial Kart למשחקי Unity.
יצירת קישורי המפתחות
לרשום את קישורי המפתחות על ידי יצירה של InputMap
והחזרה עם
InputMappingProvider
. הדוגמה הבאה מפרטת
InputMappingProvider
:
Kotlin
class InputSDKProvider : InputMappingProvider { override fun onProvideInputMap(): InputMap { TODO("Not yet implemented") } }
Java
public class InputSDKProvider implements InputMappingProvider { private static final String INPUTMAP_VERSION = "1.0.0"; @Override @NonNull public InputMap onProvideInputMap() { // TODO: return an InputMap } }
C#
#if PLAY_GAMES_PC using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; public class InputSDKProvider : InputMappingProviderCallbackHelper { public static readonly string INPUT_MAP_VERSION = "1.0.0"; public override InputMap OnProvideInputMap() { // TODO: return an InputMap } } #endif
הגדרת פעולות הקלט
המחלקה InputAction
משמשת למיפוי של שילוב מקשים או שילוב מקשים למשחק
פעולה. ל-InputActions
חייבים להיות מזהים ייחודיים בכל InputActions
.
אם בחרת לתמוך במיפוי מחדש, אפשר להגדיר איך InputActions
יכול להיות
מיפוי מחדש. אם המשחק שלך לא תומך במיפוי מחדש, עליך להגדיר את המיפוי מחדש
האפשרות מושבתת בכל InputActions
שלך, אבל ה-SDK לקליטת נתונים
מספיק חכמה כדי להשבית את המיפוי מחדש אם אתם לא תומכים בו
InputMap
.
בדוגמה הזו מתבצע מיפוי של מקש
Kotlin
companion object { private val driveInputAction = InputAction.create( "Drive", InputActionsIds.DRIVE.ordinal.toLong(), InputControls.create(listOf(KeyEvent.KEYCODE_SPACE), emptyList()), InputEnums.REMAP_OPTION_ENABLED) }
Java
private static final InputAction driveInputAction = InputAction.create( "Drive", InputEventIds.DRIVE.ordinal(), InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_SPACE), Collections.emptyList()), InputEnums.REMAP_OPTION_ENABLED );
C#
private static readonly InputAction driveInputAction = InputAction.Create( "Drive", (long)InputEventIds.DRIVE, InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(), new ArrayList<Integer>()), InputEnums.REMAP_OPTION_ENABLED );
פעולות יכולות לייצג גם קלט של עכבר. בדוגמה הזו, לחיצה שמאלית היא הפעולה Move:
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
בדוגמה הזו, המקשים
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 לקלט מאפשר לשלב לחצני עכבר ומקשים ביחד
פעולה אחת. בדוגמה הזו אפשר לראות שהפעולה
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 );
קלטAction כולל את השדות הבאים:
ActionLabel
: המחרוזת שמוצגת בממשק המשתמש כדי לייצג את הפעולה הזו. ההתאמה לשוק המקומי לא מתבצעת באופן אוטומטי, לכן צריך לבצע את ההתאמה לשוק המקומי הצד הקדמי.InputControls
: מגדיר את פקדי הקלט שבהם הפעולה הזו משתמשת. ממפים לגליפים עקביים בשכבת-העל.InputActionId
: אובייקטInputIdentifier
שמאחסן את המזהה והגרסה של המספר שלInputAction
(למידע נוסף, יש לעיין במזהים של מפתחות למעקב מידע).InputRemappingOption
: אחד מתוךInputEnums.REMAP_OPTION_ENABLED
אוInputEnums.REMAP_OPTION_DISABLED
. קביעה אם הפעולה מופעלת למפות מחדש. אם המשחק שלך לא תומך במיפוי מחדש, אפשר לדלג על השדה הזה או פשוט משביתים אותה.RemappedInputControls
: אובייקטInputControls
לקריאה בלבד המשמש לקריאת מפתחות שמופו מחדש על ידי המשתמש במיפוי מחדש של אירועים (משמשים למטרות לקבל התראות לגבי מיפוי מחדש של אירועים).
InputControls
מייצג את הקלטים שמשויכים לפעולה ומכיל את
השדות הבאים:
AndroidKeycodes
: הוא רשימה של מספרים שלמים שמייצגים את הקלט מהמקלדת שמשויכים לפעולה מסוימת. הם מוגדרים אירוע מרכזי או מחלקה של AndroidKeycode ל-Unity.MouseActions
: היא רשימה של ערכים מסוגMouseAction
שמייצגים קלט מהעכבר שמשויכים לפעולה הזו.
הגדרת קבוצות הקלט
InputActions
מקובצות עם פעולות שקשורות לוגיות באמצעות InputGroups
כדי
לשפר את הניווט ואת יכולת הגילוי בשכבת-העל. כל אחד
המזהה של InputGroup
צריך להיות ייחודי בכל InputGroups
במשחק שלך.
אם מארגנים את פעולות הקלט בקבוצות, קל יותר לשחקן למצוא את קישור המפתחות הנכון להקשר הנוכחי.
אם בחרת לתמוך במיפוי מחדש, אפשר להגדיר איך InputGroups
יכול להיות
מיפוי מחדש. אם המשחק שלך לא תומך במיפוי מחדש, עליך להגדיר את המיפוי מחדש
האפשרות מושבתת בכל InputGroups
שלך, אבל ה-SDK לקליטת נתונים
מספיק חכמה כדי להשבית את המיפוי מחדש אם אתם לא תומכים בו
InputMap
.
Kotlin
companion object { private val menuInputGroup = InputGroup.create( "Menu keys", listOf( navigateUpInputAction, navigateLeftInputAction, navigateDownInputAction, navigateRightInputAction, openMenuInputAction, returnMenuInputAction), InputGroupsIds.MENU_ACTION_KEYS.ordinal.toLong(), InputEnums.REMAP_OPTION_ENABLED ) }
Java
private static final InputGroup menuInputGroup = InputGroup.create( "Menu keys", Arrays.asList( navigateUpInputAction, navigateLeftInputAction, navigateDownInputAction, navigateRightInputAction, openMenuInputAction, returnMenuInputAction), InputGroupsIds.MENU_ACTION_KEYS.ordinal(), REMAP_OPTION_ENABLED );
C#
private static readonly InputGroup menuInputGroup = InputGroup.Create( "Menu keys", new[] { navigateUpInputAction, navigateLeftInputAction, navigateDownInputAction, navigateRightInputAction, openMenuInputAction, returnMenuInputAction, }.ToJavaList(), (long)InputGroupsIds.MENU_ACTION_KEYS, InputEnums.REMAP_OPTION_ENABLED );
בדוגמה הבאה מופיעים פקדי הכביש ופקדי התפריט. קבוצות קלט בשכבת-העל:
InputGroup
כולל את השדות הבאים:
GroupLabel
: מחרוזת להצגה בשכבת-על שאפשר להשתמש בה לקבץ באופן לוגי קבוצת פעולות. המחרוזת הזו לא מופעלת באופן אוטומטי מותאם לשוק המקומי.InputActions
: רשימה שלInputAction
אובייקטים שהגדרתם קודם לכן בכל פעימה. כל הפעולות האלה מוצגות באופן חזותי מתחת לכותרת הקבוצה.InputGroupId
: אובייקטInputIdentifier
שמאחסן את מזהה המספר שלInputGroup
. ראה מזהים של מפתחות מעקב עבור מידע נוסף.InputRemappingOption
: אחד מתוךInputEnums.REMAP_OPTION_ENABLED
אוInputEnums.REMAP_OPTION_DISABLED
. אם המדיניות מושבתת, כלInputAction
המיפוי מחדש של אובייקטים ששייכים לקבוצה הזו יושבת גם אם הם לציין שאפשרות המיפוי מחדש מופעלת. אם ההגדרה מופעלת, כל הפעולות השייכות לקבוצה זו ניתן יהיה לשנות את כתובתה, אלא אם כן פעולות.
הגדרה של הקשרי הקלט
השירות InputContexts
מאפשר למשחק להשתמש בקבוצה אחרת של פקדי מקלדת
סצנות שונות במשחק. לדוגמה:
- אפשר לציין קבוצות שונות של קלט לניווט בתפריטים לעומת העברה בתוך המשחק.
- אפשר לציין קבוצות שונות של קלט, בהתאם למצב התנועה במשחק, למשל נהיגה לעומת הליכה.
- אפשר לציין קבוצות שונות של מקורות קלט בהתאם למצב הנוכחי של משחק, כמו ניווט בעולם עליון לעומת משחק ברמה ספציפית.
כשמשתמשים במאפיין InputContexts
, שכבת-העל מציגה קודם את הקבוצות של ההקשר
בשימוש. כדי להפעיל את ההתנהגות הזו, צריך להפעיל את setInputContext()
כדי להגדיר
ההקשר בכל פעם שהמשחק נכנס לסצנה אחרת. התמונה הבאה
ממחישה את ההתנהגות הזאת: של הסצנה, אמצעי הבקרה בכבישים
פעולות מוצגות בחלק העליון של שכבת-העל. כשפותחים את ה'חנות' תפריט,
'פקדי תפריט' פעולות מוצגות בחלק העליון של שכבת-העל.
העדכונים האלה בשכבת-העל מתבצעים על ידי הגדרת InputContext
שונה ב-
נקודות שונות במשחק. לשם כך:
- קיבוץ
InputActions
עם פעולות שקשורות לוגיות באמצעותInputGroups
- הקצאת ה
InputGroups
האלה ל-InputContext
עבור החלקים השונים של המשחק שלך
לא ניתן להגדיר התנגשות בין InputGroups
ששייכים לאותו InputContext
InputActions
כאשר משתמשים באותו מפתח. מומלץ להקצות לכל אחד מהכרטיסים
InputGroup
ל-InputContext
בודד.
הקוד לדוגמה הבא מדגים את הלוגיקה InputContext
:
Kotlin
companion object { val menuSceneInputContext = InputContext.create( "Menu", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.MENU_SCENE.ordinal.toLong()), listOf(basicMenuNavigationInputGroup, menuActionsInputGroup)) val gameSceneInputContext = InputContext.create( "Game", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.GAME_SCENE.ordinal.toLong()), listOf( movementInputGroup, mouseActionsInputGroup, emojisInputGroup, gameActionsInputGroup)) }
Java
public static final InputContext menuSceneInputContext = InputContext.create( "Menu", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.MENU_SCENE.ordinal()), Arrays.asList( basicMenuNavigationInputGroup, menuActionsInputGroup ) ); public static final InputContext gameSceneInputContext = InputContext.create( "Game", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.GAME_SCENE.ordinal()), Arrays.asList( movementInputGroup, mouseActionsInputGroup, emojisInputGroup, gameActionsInputGroup ) );
C#
public static readonly InputContext menuSceneInputContext = InputContext.Create( "Menu", InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputContextsIds.MENU_SCENE), new[] { basicMenuNavigationInputGroup, menuActionsInputGroup }.ToJavaList() ); public static readonly InputContext gameSceneInputContext = InputContext.Create( "Game", InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputContextsIds.GAME_SCENE), new[] { movementInputGroup, mouseActionsInputGroup, emojisInputGroup, gameActionsInputGroup }.ToJavaList() );
InputContext
כולל את השדות הבאים:
LocalizedContextLabel
: מחרוזת שמתארת את הקבוצות ששייכות אל הקשר מסוים.InputContextId
: אובייקטInputIdentifier
שמאחסן את המזהה והגרסה של המספר שלInputContext
(למידע נוסף, יש לעיין במזהים של מפתחות למעקב מידע).ActiveGroups
: רשימה שלInputGroups
לשימוש ולהציג בחלק העליון של שכבת-העל כשההקשר הזה פעיל.
יצירה של מפת קלט
InputMap
הוא אוסף של כל האובייקטים InputGroup
שזמינים
ולכן כל האובייקטים InputAction
שהשחקן יכול לצפות להם
או ביצועים.
כשמדווחים על קישורי המפתחות, יוצרים InputMap
עם כל
נעשה שימוש ב-InputGroups
במשחק שלך.
אם המשחק שלכם לא תומך במיפוי מחדש, עליכם להגדיר את אפשרות המיפוי מחדש מושבתת המפתחות השמורים ריקים.
בדוגמה הבאה נוצר InputMap
שמשמש לדיווח על אוסף של
InputGroups
.
Kotlin
companion object { val gameInputMap = InputMap.create( listOf( basicMenuNavigationInputGroup, menuActionKeysInputGroup, movementInputGroup, mouseMovementInputGroup, pauseMenuInputGroup), MouseSettings.create(true, false), InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID.toLong()), InputEnums.REMAP_OPTION_ENABLED, // Use ESCAPE as reserved remapping key listof(InputControls.create(listOf(KeyEvent.KEYCODE_ESCAPE), emptyList())) ) }
Java
public static final InputMap gameInputMap = InputMap.create( Arrays.asList( basicMenuNavigationInputGroup, menuActionKeysInputGroup, movementInputGroup, mouseMovementInputGroup, pauseMenuInputGroup), MouseSettings.create(true, false), InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID), REMAP_OPTION_ENABLED, // Use ESCAPE as reserved remapping key Arrays.asList( InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_ESCAPE), Collections.emptyList() ) ) );
C#
public static readonly InputMap gameInputMap = InputMap.Create( new[] { basicMenuNavigationInputGroup, menuActionKeysInputGroup, movementInputGroup, mouseMovementInputGroup, pauseMenuInputGroup, }.ToJavaList(), MouseSettings.Create(true, false), InputIdentifier.Create(INPUT_MAP_VERSION, INPUT_MAP_ID), InputEnums.REMAP_OPTION_ENABLED, // Use ESCAPE as reserved remapping key new[] { InputControls.Create( New[] { new Integer(AndroidKeyCode.KEYCODE_ESCAPE) }.ToJavaList(), new ArrayList<Integer>()) }.ToJavaList() );
InputMap
כולל את השדות הבאים:
InputGroups
: קבוצות הקלט שדווחו על ידי המשחק שלך. הקבוצות מוצגות לפי הסדר בשכבת-העל, אלא אם ציינת את הקבוצות הנוכחיות להשתמש בהתקשרות אלsetInputContext()
.MouseSettings
: האובייקטMouseSettings
מציין שרגישות העכבר וששינוי העכבר הפוך על ציר ה-y.InputMapId
: אובייקטInputIdentifier
שמאחסן את מזהה המספר והגרסה שלInputMap
(למידע נוסף, יש לעיין במזהי מפתחות למעקב מידע).InputRemappingOption
: אחד מתוךInputEnums.REMAP_OPTION_ENABLED
אוInputEnums.REMAP_OPTION_DISABLED
. מציין אם תכונת המיפוי מחדש מופעל.ReservedControls
: רשימה שלInputControls
שהמשתמשים לא מורשים לעשות למפות מחדש אל.
מעקב אחר מזהי מפתחות
אובייקטים מסוג InputAction
, InputGroup
, InputContext
ו-InputMap
מכילים
אובייקט InputIdentifier
שמאחסן מזהה מספר ייחודי ומזהה גרסת מחרוזת.
לא חובה לעקוב אחרי גרסת המחרוזת של האובייקטים, אבל מומלץ לעקוב אחרי הגרסה הזו.
הגרסאות של InputMap
. אם לא תספקו גרסת מחרוזת,
המחרוזת ריקה. צריך להגדיר גרסת מחרוזת ל-InputMap
אובייקטים.
הדוגמה הבאה מקצה גרסת מחרוזת ל-InputActions
או
InputGroups
:
Kotlin
class InputSDKProviderKotlin : InputMappingProvider { companion object { const val INPUTMAP_VERSION = "1.0.0" private val enterMenuInputAction = InputAction.create( "Enter menu", InputControls.create(listOf(KeyEvent.KEYCODE_ENTER), emptyList()), InputIdentifier.create( INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal.toLong()), InputEnums.REMAP_OPTION_ENABLED ) private val movementInputGroup = InputGroup.create( "Basic movement", listOf( moveUpInputAction, moveLeftInputAction, moveDownInputAction, mouseGameInputAction), InputIdentifier.create( INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal.toLong()), InputEnums.REMAP_OPTION_ENABLED) } }
Java
public class InputSDKProvider implements InputMappingProvider { public static final String INPUTMAP_VERSION = "1.0.0"; private static final InputAction enterMenuInputAction = InputAction.create( "Enter menu", InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_ENTER), Collections.emptyList()), InputIdentifier.create( INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal()), InputEnums.REMAP_OPTION_ENABLED ); private static final InputGroup movementInputGroup = InputGroup.create( "Basic movement", Arrays.asList( moveUpInputAction, moveLeftInputAction, moveDownInputAction, moveRightInputAction, mouseGameInputAction ), InputIdentifier.create( INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal()), InputEnums.REMAP_OPTION_ENABLED ); }
C#
#if PLAY_GAMES_PC using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; public class InputSDKMappingProvider : InputMappingProviderCallbackHelper { public static readonly string INPUT_MAP_VERSION = "1.0.0"; private static readonly InputAction enterMenuInputAction = InputAction.Create( "Enter menu", InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE)}.ToJavaList(), new ArrayList<Integer>()), InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputEventIds.ENTER_MENU), InputEnums.REMAP_OPTION_ENABLED ); private static readonly InputGroup movementInputGroup = InputGroup.Create( "Basic movement", new[] { moveUpInputAction, moveLeftInputAction, moveDownInputAction, moveRightInputAction, mouseGameInputAction }.ToJavaList(), InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputGroupsIds.BASIC_MOVEMENT), InputEnums.REMAP_OPTION_ENABLED ); } #endif
המזהים של מספרי אובייקטים מסוג InputAction
צריכים להיות ייחודיים בכל ה-InputActions
של
InputMap
. באופן דומה, מזהי אובייקטים של InputGroup
חייבים להיות ייחודיים בכל
InputGroups
בInputMap
. הדוגמה הבאה ממחישה איך להשתמש
enum
כדי לעקוב אחר המזהים הייחודיים של האובייקט:
Kotlin
enum class InputActionsIds { NAVIGATE_UP, NAVIGATE_DOWN, ENTER_MENU, EXIT_MENU, // ... JUMP, RUN, EMOJI_1, EMOJI_2, // ... } enum class InputGroupsIds { // Main menu scene BASIC_NAVIGATION, // WASD, Enter, Backspace MENU_ACTIONS, // C: chat, Space: quick game, S: store // Gameplay scene BASIC_MOVEMENT, // WASD, space: jump, Shift: run MOUSE_ACTIONS, // Left click: shoot, Right click: aim EMOJIS, // Emojis with keys 1,2,3,4 and 5 GAME_ACTIONS, // M: map, P: pause, R: reload } enum class InputContextIds { MENU_SCENE, // Basic menu navigation, menu actions GAME_SCENE, // Basic movement, mouse actions, emojis, game actions } const val INPUT_MAP_ID = 0
Java
public enum InputActionsIds { NAVIGATE_UP, NAVIGATE_DOWN, ENTER_MENU, EXIT_MENU, // ... JUMP, RUN, EMOJI_1, EMOJI_2, // ... } public enum InputGroupsIds { // Main menu scene BASIC_NAVIGATION, // WASD, Enter, Backspace MENU_ACTIONS, // C: chat, Space: quick game, S: store // Gameplay scene BASIC_MOVEMENT, // WASD, space: jump, Shift: run MOUSE_ACTIONS, // Left click: shoot, Right click: aim EMOJIS, // Emojis with keys 1,2,3,4 and 5 GAME_ACTIONS, // M: map, P: pause, R: reload } public enum InputContextIds { MENU_SCENE, // Basic navigation, menu actions GAME_SCENE, // Basic movement, mouse actions, emojis, game actions } public static final long INPUT_MAP_ID = 0;
C#
public enum InputActionsIds { NAVIGATE_UP, NAVIGATE_DOWN, ENTER_MENU, EXIT_MENU, // ... JUMP, RUN, EMOJI_1, EMOJI_2, // ... } public enum InputGroupsIds { // Main menu scene BASIC_NAVIGATION, // WASD, Enter, Backspace MENU_ACTIONS, // C: chat, Space: quick game, S: store // Gameplay scene BASIC_MOVEMENT, // WASD, space: jump, Shift: run MOUSE_ACTIONS, // Left click: shoot, Right click: aim EMOJIS, // Emojis with keys 1,2,3,4 and 5 GAME_ACTIONS, // M: map, P: pause, R: reload } public enum InputContextIds { MENU_SCENE, // Basic navigation, menu actions GAME_SCENE, // Basic movement, mouse actions, emojis, game actions } public static readonly long INPUT_MAP_ID = 0;
InputIdentifier
כולל את השדות הבאים:
UniqueId
: מזהה מספר ייחודי המוגדר כדי לזהות בבירור קבוצת קלט מסוימת את הנתונים באופן ייחודי.VersionString
: מחרוזת גרסה קריאות (לבני אדם) שמוגדרת לזיהוי גרסה של נתוני קלט בין שתי גרסאות של שינויים בנתוני הקלט.
קבלת התראות לגבי מיפוי מחדש של אירועים (אופציונלי)
אפשר לקבל התראות לגבי מיפוי מחדש של אירועים לקבלת עדכונים לגבי המפתחות שנמצאים בשימוש במשחק שלך. פעולה זו מאפשרת למשחק לעדכן את הנכסים המוצגים במסך המשחק משמש להצגת לחצני הפעולות.
התמונה הבאה מציגה דוגמה להתנהגות כזו, שבה אחרי מיפוי מחדש של
המקשים
אפשר לעשות את זה באמצעות רישום של InputRemappingListener
קריאה חוזרת. כדי ליישם את התכונה הזו, תחילה צריך לרשום
מופע של InputRemappingListener
:
Kotlin
class InputSDKRemappingListener : InputRemappingListener { override fun onInputMapChanged(inputMap: InputMap) { Log.i(TAG, "Received update on input map changed.") if (inputMap.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { return } for (inputGroup in inputMap.inputGroups()) { if (inputGroup.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { continue } for (inputAction in inputGroup.inputActions()) { if (inputAction.inputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) { // Found InputAction remapped by user processRemappedAction(inputAction) } } } } private fun processRemappedAction(remappedInputAction: InputAction) { // Get remapped action info val remappedControls = remappedInputAction.remappedInputControls() val remappedKeyCodes = remappedControls.keycodes() val mouseActions = remappedControls.mouseActions() val version = remappedInputAction.inputActionId().versionString() val remappedActionId = remappedInputAction.inputActionId().uniqueId() val currentInputAction: Optional<InputAction> currentInputAction = if (version == null || version.isEmpty() || version == InputSDKProvider.INPUTMAP_VERSION ) { getCurrentVersionInputAction(remappedActionId) } else { Log.i(TAG, "Detected version of user-saved input action defers from current version") getCurrentVersionInputActionFromPreviousVersion( remappedActionId, version) } if (!currentInputAction.isPresent) { Log.e(TAG, String.format( "can't find remapped input action with id %d and version %s", remappedActionId, if (version == null || version.isEmpty()) "UNKNOWN" else version)) return } val originalControls = currentInputAction.get().inputControls() val originalKeyCodes = originalControls.keycodes() Log.i(TAG, String.format( "Found input action with id %d remapped from key %s to key %s", remappedActionId, keyCodesToString(originalKeyCodes), keyCodesToString(remappedKeyCodes))) // TODO: make display changes to match controls used by the user } private fun getCurrentVersionInputAction(inputActionId: Long): Optional<InputAction> { for (inputGroup in InputSDKProvider.gameInputMap.inputGroups()) { for (inputAction in inputGroup.inputActions()) { if (inputAction.inputActionId().uniqueId() == inputActionId) { return Optional.of(inputAction) } } } return Optional.empty() } private fun getCurrentVersionInputActionFromPreviousVersion( inputActionId: Long, previousVersion: String ): Optional<InputAction7gt; { // TODO: add logic to this method considering the diff between the current and previous // InputMap. return Optional.empty() } private fun keyCodesToString(keyCodes: List<Int>): String { val builder = StringBuilder() for (keyCode in keyCodes) { if (!builder.toString().isEmpty()) { builder.append(" + ") } builder.append(keyCode) } return String.format("(%s)", builder) } companion object { private const val TAG = "InputSDKRemappingListener" } }
Java
public class InputSDKRemappingListener implements InputRemappingListener { private static final String TAG = "InputSDKRemappingListener"; @Override public void onInputMapChanged(InputMap inputMap) { Log.i(TAG, "Received update on input map changed."); if (inputMap.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { return; } for (InputGroup inputGroup : inputMap.inputGroups()) { if (inputGroup.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { continue; } for (InputAction inputAction : inputGroup.inputActions()) { if (inputAction.inputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) { // Found InputAction remapped by user processRemappedAction(inputAction); } } } } private void processRemappedAction(InputAction remappedInputAction) { // Get remapped action info InputControls remappedControls = remappedInputAction.remappedInputControls(); List<Integer> remappedKeyCodes = remappedControls.keycodes(); List<Integer> mouseActions = remappedControls.mouseActions(); String version = remappedInputAction.inputActionId().versionString(); long remappedActionId = remappedInputAction.inputActionId().uniqueId(); Optional<InputAction> currentInputAction; if (version == null || version.isEmpty() || version.equals(InputSDKProvider.INPUTMAP_VERSION)) { currentInputAction = getCurrentVersionInputAction(remappedActionId); } else { Log.i(TAG, "Detected version of user-saved input action defers " + "from current version"); currentInputAction = getCurrentVersionInputActionFromPreviousVersion( remappedActionId, version); } if (!currentInputAction.isPresent()) { Log.e(TAG, String.format( "input action with id %d and version %s not found", remappedActionId, version == null || version.isEmpty() ? "UNKNOWN" : version)); return; } InputControls originalControls = currentInputAction.get().inputControls(); List<Integer> originalKeyCodes = originalControls.keycodes(); Log.i(TAG, String.format( "Found input action with id %d remapped from key %s to key %s", remappedActionId, keyCodesToString(originalKeyCodes), keyCodesToString(remappedKeyCodes))); // TODO: make display changes to match controls used by the user } private Optional<InputAction> getCurrentVersionInputAction( long inputActionId) { for (InputGroup inputGroup : InputSDKProvider.gameInputMap.inputGroups()) { for (InputAction inputAction : inputGroup.inputActions()) { if (inputAction.inputActionId().uniqueId() == inputActionId) { return Optional.of(inputAction); } } } return Optional.empty(); } private Optional<InputAction> getCurrentVersionInputActionFromPreviousVersion( long inputActionId, String previousVersion) { // TODO: add logic to this method considering the diff between your // current and previous InputMap. return Optional.empty(); } private String keyCodesToString(List<Integer> keyCodes) { StringBuilder builder = new StringBuilder(); for (Integer keyCode : keyCodes) { if (!builder.toString().isEmpty()) { builder.append(" + "); } builder.append(keyCode); } return String.format("(%s)", builder); } }
C#
#if PLAY_GAMES_PC using System.Text; using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; using UnityEngine; public class InputSDKRemappingListener : InputRemappingListenerCallbackHelper { public override void OnInputMapChanged(InputMap inputMap) { Debug.Log("Received update on remapped controls."); if (inputMap.InputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { return; } List<InputGroup> inputGroups = inputMap.InputGroups(); for (int i = 0; i < inputGroups.Size(); i ++) { InputGroup inputGroup = inputGroups.Get(i); if (inputGroup.InputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { continue; } List<InputAction> inputActions = inputGroup.InputActions(); for (int j = 0; j < inputActions.Size(); j ++) { InputAction inputAction = inputActions.Get(j); if (inputAction.InputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) { // Found action remapped by user ProcessRemappedAction(inputAction); } } } } private void ProcessRemappedAction(InputAction remappedInputAction) { InputControls remappedInputControls = remappedInputAction.RemappedInputControls(); List<Integer> remappedKeycodes = remappedInputControls.Keycodes(); List<Integer> mouseActions = remappedInputControls.MouseActions(); string version = remappedInputAction.InputActionId().VersionString(); long remappedActionId = remappedInputAction.InputActionId().UniqueId(); InputAction currentInputAction; if (string.IsNullOrEmpty(version) || string.Equals( version, InputSDKMappingProvider.INPUT_MAP_VERSION)) { currentInputAction = GetCurrentVersionInputAction(remappedActionId); } else { Debug.Log("Detected version of used-saved input action defers" + " from current version"); currentInputAction = GetCurrentVersionInputActionFromPreviousVersion( remappedActionId, version); } if (currentInputAction == null) { Debug.LogError(string.Format( "Input Action with id {0} and version {1} not found", remappedActionId, string.IsNullOrEmpty(version) ? "UNKNOWN" : version)); return; } InputControls originalControls = currentInputAction.InputControls(); List<Integer> originalKeycodes = originalControls.Keycodes(); Debug.Log(string.Format( "Found Input Action with id {0} remapped from key {1} to key {2}", remappedActionId, KeyCodesToString(originalKeycodes), KeyCodesToString(remappedKeycodes))); // TODO: update HUD according to the controls of the user } private InputAction GetCurrentVersionInputAction( long inputActionId) { List<InputGroup> inputGroups = InputSDKMappingProvider.gameInputMap.InputGroups(); for (int i = 0; i < inputGroups.Size(); i++) { InputGroup inputGroup = inputGroups.Get(i); List<InputAction> inputActions = inputGroup.InputActions(); for (int j = 0; j < inputActions.Size(); j++) { InputAction inputAction = inputActions.Get(j); if (inputAction.InputActionId().UniqueId() == inputActionId) { return inputAction; } } } return null; } private InputAction GetCurrentVersionInputActionFromPreviousVersion( long inputActionId, string version) { // TODO: add logic to this method considering the diff between your // current and previous InputMap. return null; } private string KeyCodesToString(List<Integer> keycodes) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < keycodes.Size(); i ++) { Integer keycode = keycodes.Get(i); if (builder.Length > 0) { builder.Append(" + "); } builder.Append(keycode.IntValue()); } return string.Format("({0})", builder.ToString()); } } #endif
המכשיר InputRemappingListener
מקבל התראה בזמן ההשקה אחרי הטעינה של
פקדים מופו מחדש שנשמרו על ידי המשתמש, ואחרי כל פעם שהמשתמש ממופה מחדש את המפתחות שלו.
אתחול
אם משתמשים ב-InputContexts
, צריך להגדיר את ההקשר בכל פריט
לסצנה חדשה, כולל ההקשר הראשון ששימש
לסצנה. צריך להגדיר את InputContext
אחרי שרושמים את
InputMap
.
אם בחרת להשתמש ב-InputRemappingListeners
כדי לקבל התראות לגבי אירועים למיפוי מחדש
צריך לרשום את InputRemappingListener
לפני הרישום של
InputMappingProvider
, אחרת המשחק עלול לפספס אירועים חשובים במהלך
שעת ההשקה.
הדוגמה הבאה ממחישה איך לאתחל את ה-API:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (isGooglePlayGamesOnPC()) { val inputMappingClient = Input.getInputMappingClient(this) // Register listener before registering the provider inputMappingClient.registerRemappingListener(InputSDKRemappingListener()) inputMappingClient.setInputMappingProvider( InputSDKProvider()) // Set the context after you have registered the provider. inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext) } }
Java
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (isGooglePlayGamesOnPC()) { InputMappingClient inputMappingClient = Input.getInputMappingClient(this); // Register listener before registering the provider inputMappingClient.registerRemappingListener( new InputSDKRemappingListener()); inputMappingClient.setInputMappingProvider( new InputSDKProvider()); // Set the context after you have registered the provider inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext); } }
C#
#if PLAY_GAMES_PC using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.InputMapping.ExternalType.Android.Content; using Google.LibraryWrapper.Java; #endif public class GameManager : MonoBehaviour { #if PLAY_GAMES_PC private InputSDKMappingProvider _inputMapProvider = new InputSDKMappingProvider(); private InputMappingClient _inputMappingClient; #endif public void Awake() { #if PLAY_GAMES_PC Context context = (Context)Utils.GetUnityActivity().GetRawObject(); _inputMappingClient = Google.Android.Libraries.Play.Games.Inputmapping .Input.GetInputMappingClient(context); // Register listener before registering the provider. _inputMappingClient.RegisterRemappingListener( new InputSDKRemappingListener()); _inputMappingClient.SetInputMappingProvider(_inputMapProvider); // Register context after you have registered the provider. _inputMappingClient.SetInputContext( InputSDKMappingProvider.menuSceneInputContext); #endif } }
אני רוצה לעשות סדר
ביטול הרישום של המופע של InputMappingProvider
ושל כל InputRemappingListener
מקרים שבהם המשחק נסגר, למרות שה-SDK לקלט הוא חכם
מספיק כדי למנוע דליפת משאבים, אם לא:
Kotlin
override fun onDestroy() { if (isGooglePlayGamesOnPC()) { val inputMappingClient = Input.getInputMappingClient(this) inputMappingClient.clearInputMappingProvider() inputMappingClient.clearRemappingListener() } super.onDestroy() }
Java
@Override protected void onDestroy() { if (isGooglePlayGamesOnPC()) { InputMappingClient inputMappingClient = Input.getInputMappingClient(this); inputMappingClient.clearInputMappingProvider(); inputMappingClient.clearRemappingListener(); } super.onDestroy(); }
C#
public class GameManager : MonoBehaviour { private void OnDestroy() { #if PLAY_GAMES_PC _inputMappingClient.ClearInputMappingProvider(); _inputMappingClient.ClearRemappingListener(); #endif } }
בדיקה
כדי לבדוק את ההטמעה של ה-SDK של הקלט, פותחים באופן ידני שכבת-העל כדי להציג את חוויית הנגן, או דרך מעטפת adb לצורך בדיקה ואימות אוטומטיים.
האמולטור 'Google Play Games במחשב' בודק את הנכונות של מפת הקלט שלך נגד שגיאות נפוצות. בתרחישים כמו מזהים ייחודיים כפולים, שימוש להזין מפות או להיכשל בכללי המיפוי מחדש (אם המיפוי מחדש מופעל), שכבת-על מציגה הודעת שגיאה כמו:
אימות ההטמעה של ה-SDK של הקלט באמצעות adb
בשורת הפקודה.
כדי לקבל את מפת הקלט הנוכחית, צריך להשתמש בפקודה הבאה של adb shell
(החלפה
MY.PACKAGE.NAME
בשם המשחק שלך):
adb shell dumpsys input_mapping_service --get MY.PACKAGE.NAME
אם רשמת בהצלחה את
InputMap
:
Getting input map for com.example.inputsample...
Successfully received the following inputmap:
# com.google.android.libraries.play.games.InputMap@d73526e1
input_groups {
group_label: "Basic Movement"
input_actions {
action_label: "Jump"
input_controls {
keycodes: 51
keycodes: 19
}
unique_id: 0
}
input_actions {
action_label: "Left"
input_controls {
keycodes: 29
keycodes: 21
}
unique_id: 1
}
input_actions {
action_label: "Right"
input_controls {
keycodes: 32
keycodes: 22
}
unique_id: 2
}
input_actions {
action_label: "Use"
input_controls {
keycodes: 33
keycodes: 66
mouse_actions: MOUSE_LEFT_CLICK
mouse_actions_value: 0
}
unique_id: 3
}
}
input_groups {
group_label: "Special Input"
input_actions {
action_label: "Jump"
input_controls {
keycodes: 51
keycodes: 19
keycodes: 62
mouse_actions: MOUSE_LEFT_CLICK
mouse_actions_value: 0
}
unique_id: 4
}
input_actions {
action_label: "Duck"
input_controls {
keycodes: 47
keycodes: 20
keycodes: 113
mouse_actions: MOUSE_RIGHT_CLICK
mouse_actions_value: 1
}
unique_id: 5
}
}
mouse_settings {
allow_mouse_sensitivity_adjustment: true
invert_mouse_movement: true
}
התאמה לשוק המקומי
ה-SDK של הקלט לא משתמש במערכת ההתאמה לשוק המקומי של Android. בתור
תוצאה אחת, צריך לספק מחרוזות מותאמות לשוק המקומי כששולחים InputMap
. שלך
יכול להשתמש גם במערכת הלוקליזציה של מנוע המשחק.
הגנה
כשמשתמשים ב-ProGuard להקטנת המשחק, צריך להוסיף את הכללים הבאים קובץ התצורה ProGuard כדי לוודא שה-SDK לא יוסר החבילה הסופית:
-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }
השלב הבא
אחרי שמשלבים את קלט SDK במשחק, אפשר להמשיך עם שאר הדרישות של Google Play Games במחשב. לקבלת מידע נוסף, כדאי לקרוא את המאמר איך מתחילים לעבוד עם Google Play Games במחשב.