يوضّح هذا المستند كيفية إعداد حزمة Input SDK وعرضها في الألعاب المتوافقة مع "ألعاب Google Play على الكمبيوتر". وتشمل المهام إضافة حزمة SDK إلى لعبتك وإنشاء خريطة إدخال تحتوي على عمليات ربط بين إجراءات اللعبة وإدخالات المستخدم.
قبل البدء
قبل إضافة حزمة تطوير البرامج (SDK) الخاصة بأدوات الإدخال إلى لعبتك، يجب أن تتوافق مع لوحة المفاتيح والماوس باستخدام نظام الإدخال في محرك الألعاب.
توفّر حزمة تطوير البرامج (SDK) الخاصة بأدوات الإدخال معلومات إلى برنامج "ألعاب Google Play على الكمبيوتر" حول عناصر التحكّم التي تستخدمها لعبتك، كي يتم عرضها للمستخدم. ويمكنه أيضًا السماح للمستخدمين بإعادة تعيين مفاتيح لوحة المفاتيح.
كل عنصر تحكّم هو InputAction (مثل "J" لـ "القفز")، ويمكنك تنظيم InputActions في InputGroups. قد يمثّل InputGroup وضعًا مختلفًا في لعبتك، مثل "القيادة" أو "المشي" أو "القائمة الرئيسية". يمكنك أيضًا استخدام InputContexts للإشارة إلى المجموعات النشطة في نقاط مختلفة من اللعبة.
يمكنك تفعيل إعادة ربط أزرار لوحة المفاتيح ليتم التعامل معها تلقائيًا، ولكن إذا كنت تفضّل توفير واجهة خاصة لإعادة ربط عناصر التحكّم، يمكنك إيقاف إعادة ربط عناصر التحكّم في حزمة Input SDK.
يوضّح مخطط التسلسل التالي طريقة عمل واجهة برمجة التطبيقات لحزمة تطوير البرامج (SDK) الخاصة بأداة الإدخال:

عندما تستخدم لعبتك حزمة تطوير البرامج (SDK) الخاصة بأدوات الإدخال، ستظهر عناصر التحكّم في التراكب الخاص ببرنامج "ألعاب Google Play على الكمبيوتر".
التراكب في "ألعاب Google Play على الكمبيوتر"
تعرض طبقة التراكب في برنامج "ألعاب Google Play على الكمبيوتر" ("طبقة التراكب") عناصر التحكّم التي تحدّدها لعبتك. يمكن للمستخدمين الوصول إلى التراكب في أي وقت من خلال الضغط على Shift + Tab.

أفضل الممارسات لتصميم اختصارات لوحة المفاتيح
عند تصميم اختصارات لوحة المفاتيح، يُرجى مراعاة أفضل الممارسات التالية:
- قسِّم
InputActionsإلىInputGroupsذات صلة منطقية لتحسين التنقّل وسهولة العثور على عناصر التحكّم أثناء اللعب. - يمكنك ربط كل
InputGroupبـInputContextواحد كحدّ أقصى. يؤدي استخدام قيمة دقيقةInputMapإلى تحسين تجربة التنقّل بين عناصر التحكّم في التراكب. - أنشِئ
InputContextلكل نوع مشهد مختلف في لعبتك. يمكنك عادةً استخدامInputContextواحد لجميع المشاهد التي تشبه القائمة. استخدِمInputContextsلأي ألعاب مصغّرة في لعبتك أو لعناصر تحكّم بديلة لمشهد واحد. - إذا كان الإجراءان مصمَّمَين لاستخدام المفتاح نفسه ضمن
InputContextنفسه، استخدِم سلسلة التصنيف، مثل "التفاعل / الإطلاق". - إذا تم تصميم مفتاحَين للربط بالإجراء
InputActionنفسه، استخدِمInputActionsمختلفَين ينفّذان الإجراء نفسه في لعبتك. يمكنك استخدام سلسلة التصنيف نفسها لكلتا السمتَينInputActions، ولكن يجب أن يكون رقم التعريف مختلفًا. - إذا تم تطبيق مفتاح تعديل على مجموعة من المفاتيح، ننصحك باستخدام
InputActionواحد مع مفتاح التعديل بدلاً من استخدام عدةInputActionsتجمع مفتاح التعديل (مثال: استخدام Shift وW وA وS وD بدلاً من Shift + W وShift + A وShift + S وShift + D). - يتم إيقاف إعادة تعيين الإدخال تلقائيًا عندما يكتب المستخدم في حقول النص. اتّبِع أفضل الممارسات لتنفيذ حقول النص في Android لضمان قدرة Android على رصد حقول النص في لعبتك ومنع المفاتيح التي تمت إعادة تعيينها من التداخل معها. إذا كانت لعبتك تستخدم حقول نصية غير تقليدية، يمكنك استخدام
setInputContext()معInputContextتحتوي على قائمة فارغة منInputGroupsلإيقاف إعادة الربط يدويًا. - إذا كانت لعبتك تتيح إعادة تعيين المفاتيح، ننصحك بتعديل عمليات ربط المفاتيح، لأنّها عملية حساسة يمكن أن تتعارض مع الإصدارات المحفوظة من قِبل المستخدم. تجنَّب تغيير أرقام تعريف عناصر التحكّم الحالية متى أمكن ذلك.
ميزة إعادة الربط
يتيح برنامج "ألعاب Google Play على الكمبيوتر" إعادة ربط عناصر التحكّم في لوحة المفاتيح استنادًا إلى عمليات ربط المفاتيح التي توفّرها لعبتك باستخدام حزمة تطوير البرامج (SDK) الخاصة بأدوات الإدخال. هذه الخطوة اختيارية ويمكن إيقافها نهائيًا. على سبيل المثال، قد ترغب في توفير واجهة خاصة بك لإعادة ربط مفاتيح لوحة المفاتيح. لإيقاف إعادة الربط في لعبتك، ما عليك سوى تحديد خيار إعادة الربط على أنّه غير مفعّل في InputMap (راجِع إنشاء InputMap لمزيد من المعلومات).
للوصول إلى هذه الميزة، على المستخدمين فتح المحتوى المركّب ثم النقر على الإجراء الذي يريدون إعادة تعيينه. بعد كل عملية إعادة ربط، يربط برنامج "ألعاب Google Play على الكمبيوتر" كل عنصر تحكّم أعاد المستخدم ربطه بعناصر التحكّم التلقائية التي تتوقّع لعبتك تلقّيها، وبالتالي لا تحتاج لعبتك إلى معرفة عملية إعادة الربط التي أجراها اللاعب. يمكنك اختياريًا تعديل مواد العرض المستخدَمة لعرض عناصر التحكّم في لوحة المفاتيح في لعبتك من خلال إضافة دالة ردّ لإعادة ربط الأحداث.

يخزِّن برنامج "ألعاب Google Play على الكمبيوتر" عناصر التحكّم التي تم إعادة تعيينها محليًا لكل مستخدم، ما يتيح استمرار عناصر التحكّم في جميع جلسات الألعاب. يتم تخزين هذه المعلومات على القرص فقط لمنصة الكمبيوتر الشخصي ولا تؤثر في تجربة الأجهزة الجوّالة. يتم حذف بيانات التحكّم عندما يلغي المستخدم تثبيت تطبيق "ألعاب Google Play على الكمبيوتر" أو يعيد تثبيته. ولا يتم الاحتفاظ بهذه البيانات على أجهزة كمبيوتر متعددة.
لإتاحة ميزة إعادة تعيين المفاتيح في لعبتك، تجنَّب القيود التالية:
قيود إعادة الربط
يمكن إيقاف ميزات إعادة تعيين المفاتيح في لعبتك إذا كانت عمليات ربط المفاتيح تتضمّن أيًا من الحالات التالية:
- مفاتيح
InputActionsمتعددة لا تتألف من مفتاح تعديل + مفتاح غير معدِّل. على سبيل المثال، Shift + A هو اختصار صالح، ولكن A + B أو Ctrl + Alt أو Shift + A + Tab ليس اختصارًا صالحًا. - تحتوي السمة
InputMapعلىInputActionsأوInputGroupsأوInputContextsمع معرّفات فريدة مكرّرة.
قيود إعادة الربط
عند تصميم مفاتيحك الرئيسية لإعادة تعيينها، يجب مراعاة القيود التالية:
- لا يمكن إعادة تعيين المفاتيح إلى مجموعات مفاتيح. على سبيل المثال، لا يمكن للمستخدمين إعادة تعيين Shift + A إلى Ctrl + B أو A إلى Shift + A.
- لا يمكن إعادة تعيين
InputActionsباستخدام أزرار الماوس. على سبيل المثال، لا يمكن إعادة تعيين Shift + النقر بزر الماوس الأيمن.
اختبار إعادة تعيين مفاتيح لوحة المفاتيح في محاكي برنامج "ألعاب Google Play على الكمبيوتر"
يمكنك تفعيل ميزة إعادة تعيين المفاتيح في "محاكي ألعاب Google Play على الكمبيوتر" في أي وقت من خلال تنفيذ أمر adb التالي:
adb shell dumpsys input_mapping_service --set RemappingFlagValue true
تغيير الطبقة الخارجية كما في الصورة التالية:

إضافة حزمة تطوير البرامج (SDK)
ثبِّت حزمة تطوير البرامج (SDK) الخاصة بأداة Input وفقًا لنظام التطوير الأساسي الذي تستخدمه.
Java وKotlin
يمكنك الحصول على حزمة تطوير البرامج (SDK) الخاصة بأداة Input API للغة Java أو Kotlin من خلال إضافة مصدر اعتمادية إلى ملف build.gradle على مستوى الوحدة:
dependencies {
implementation 'com.google.android.libraries.play.games:inputmapping:1.1.1-beta'
...
}
Unity
Input SDK هي حزمة Unity عادية تتضمّن العديد من العناصر التابعة.
يجب تثبيت الحزمة مع جميع العناصر التابعة. هناك عدة طرق لتثبيت الحِزم.
تثبيت .unitypackage
نزِّل ملف Input SDK unitypackage
مع جميع التبعيات. يمكنك تثبيت .unitypackage من خلال اختيار
مواد العرض > استيراد حزمة > حزمة مخصّصة والعثور على الملف الذي نزّلته.
التثبيت باستخدام UPM
يمكنك بدلاً من ذلك تثبيت الحزمة باستخدام مدير حِزم 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.1-beta (أو اختيار ملف tgz من هذا الأرشيف)
التثبيت باستخدام OpenUPM
يمكنك تثبيت الحزمة باستخدام OpenUPM.
$ openupm add com.google.android.libraries.play.games.inputmapping
ألعاب تجريبية
للاطّلاع على أمثلة حول كيفية الدمج مع Input SDK، راجِع AGDK Tunnel لألعاب Kotlin أو Java وTrivial Kart لألعاب Unity.
إنشاء ربط المفاتيح
سجِّل ربط المفاتيح من خلال إنشاء InputMap وعرضه مع InputMappingProvider. يوضّح المثال التالي InputMappingProvider:
Kotlin
class InputSDKProvider : InputMappingProvider { override fun onProvideInputMap(): InputMap { TODO("Not yet implemented") } }
Java
public class InputSDKProvider implements InputMappingProvider { private static final String INPUTMAP_VERSION = "1.0.0"; @Override @NonNull public InputMap onProvideInputMap() { // TODO: return an InputMap } }
#C
#if PLAY_GAMES_PC using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; public class InputSDKProvider : InputMappingProviderCallbackHelper { public static readonly string INPUT_MAP_VERSION = "1.0.0"; public override InputMap OnProvideInputMap() { // TODO: return an InputMap } } #endif
تحديد إجراءات الإدخال
يتم استخدام الفئة InputAction لربط مفتاح أو مجموعة مفاتيح بإجراء في اللعبة. يجب أن تتضمّن InputActions معرّفات فريدة في جميع InputActions.
إذا كنت تتيح إعادة ربط الأزرار، يمكنك تحديد الأزرار التي يمكن إعادة ربطها.InputActions إذا كانت لعبتك لا تتيح إعادة ربط الأزرار، عليك إيقاف خيار إعادة الربط لجميع InputActions، ولكن حزمة تطوير البرامج (SDK) الخاصة بأدوات الإدخال ذكية بما يكفي لإيقاف إعادة الربط إذا لم تكن لعبتك تتيحها في InputMap.
يربط هذا المثال مفتاح
Kotlin
companion object { private val driveInputAction = InputAction.create( "Drive", InputActionsIds.DRIVE.ordinal.toLong(), InputControls.create(listOf(KeyEvent.KEYCODE_SPACE), emptyList()), InputEnums.REMAP_OPTION_ENABLED) }
Java
private static final InputAction driveInputAction = InputAction.create( "Drive", InputEventIds.DRIVE.ordinal(), InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_SPACE), Collections.emptyList()), InputEnums.REMAP_OPTION_ENABLED );
#C
private static readonly InputAction driveInputAction = InputAction.Create( "Drive", (long)InputEventIds.DRIVE, InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(), new ArrayList<Integer>()), InputEnums.REMAP_OPTION_ENABLED );

يمكن أن تمثّل الإجراءات أيضًا إدخالات الماوس. يضبط هذا المثال النقر بزر الماوس الأيسر على الإجراء نقل:
Kotlin
companion object { private val mouseInputAction = InputAction.create( "Move", InputActionsIds.MOUSE_MOVEMENT.ordinal.toLong(), InputControls.create(emptyList(), listOf(InputControls.MOUSE_LEFT_CLICK)), InputEnums.REMAP_OPTION_DISABLED) }
Java
private static final InputAction mouseInputAction = InputAction.create( "Move", InputActionsIds.MOUSE_MOVEMENT.ordinal(), InputControls.create( Collections.emptyList(), Collections.singletonList(InputControls.MOUSE_LEFT_CLICK) ), InputEnums.REMAP_OPTION_DISABLED );
#C
private static readonly InputAction mouseInputAction = InputAction.Create( "Move", (long)InputEventIds.MOUSE_MOVEMENT, InputControls.Create( new ArrayList<Integer>(), new[] { new Integer((int)PlayMouseAction.MouseLeftClick) }.ToJavaList() ), InputEnums.REMAP_OPTION_DISABLED );

يتم تحديد مجموعات المفاتيح من خلال تمرير رموز مفاتيح متعددة إلى InputAction. في هذا المثال، يتم ربط
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 );

يحتوي InputAction على الحقول التالية:
-
ActionLabel: السلسلة المعروضة في واجهة المستخدم لتمثيل هذا الإجراء. لا تتم عملية الترجمة تلقائيًا، لذا عليك تنفيذها مسبقًا. -
InputControls: تحدّد عناصر التحكّم في الإدخال التي يستخدمها هذا الإجراء. يتم ربط عناصر التحكّم برموز رسومية متسقة في التراكب. -
InputActionId: عنصرInputIdentifierيخزّن رقم التعريف والإصدار الخاصين بـInputAction(راجِع معرّفات مفاتيح التتبُّع لمزيد من المعلومات). -
InputRemappingOption: إحدى القيمتينInputEnums.REMAP_OPTION_ENABLEDأوInputEnums.REMAP_OPTION_DISABLEDتحدِّد هذه السمة ما إذا كان الإجراء مفعّلاً لإعادة التعيين. إذا كانت لعبتك لا تتيح إعادة الربط، يمكنك تخطّي هذا الحقل أو ضبطه على "غير مفعّل". RemappedInputControls: كائنInputControlsللقراءة فقط يُستخدَم لقراءة مجموعة المفاتيح التي أعاد المستخدم تعيينها عند وقوع أحداث إعادة التعيين (يُستخدَم لتلقّي إشعارات بشأن أحداث إعادة التعيين).
يمثّل InputControls المدخلات المرتبطة بأحد الإجراءات ويتضمّن الحقول التالية:
-
AndroidKeycodes: هي قائمة بأعداد صحيحة تمثّل إدخالات لوحة المفاتيح المرتبطة بأحد الإجراءات. يتم تحديدها في فئة KeyEvent أو فئة AndroidKeycode في Unity. -
MouseActions: هي قائمة بقيمMouseActionتمثّل إدخالات الماوس المرتبطة بهذا الإجراء.
تحديد مجموعات الإدخال
يتم تجميع InputActions مع الإجراءات ذات الصلة منطقيًا باستخدام InputGroups لتحسين التنقّل وإمكانية العثور على عناصر التحكّم في التراكب. يجب أن يكون كل معرّف InputGroup فريدًا في جميع InputGroups داخل لعبتك.
من خلال تنظيم إجراءات الإدخال في مجموعات، يمكنك تسهيل عثور اللاعب على ربط المفاتيح الصحيح للسياق الحالي.
إذا كنت تتيح إعادة ربط الأزرار، يمكنك تحديد الأزرار التي يمكن إعادة ربطها.InputGroups إذا كانت لعبتك لا تتيح إعادة ربط الأزرار، عليك إيقاف خيار إعادة الربط لجميع InputGroups، ولكن حزمة تطوير البرامج (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: هي 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، وإلا قد تفوت لعبتك أحداث مهمة أثناء وقت التشغيل.
يوضّح المثال التالي كيفية إعداد واجهة برمجة التطبيقات:
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) الخاصة بأداة Input ذكية بما يكفي لتجنُّب تسريب الموارد في حال عدم إلغاء التسجيل:
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) الخاصة بأداة Input من خلال فتح التراكب يدويًا لعرض تجربة المشغّل، أو من خلال adb shell لإجراء الاختبار والتحقّق بشكل آلي.
يتحقّق محاكي برنامج "ألعاب Google Play على الكمبيوتر" من صحة خريطة الإدخال الخاصة بك
مقارنةً بالأخطاء الشائعة. في حالات مثل تكرار المعرّفات الفريدة أو استخدام خرائط إدخال مختلفة أو عدم استيفاء قواعد إعادة الربط (في حال تفعيل إعادة الربط)، تعرض الطبقة المتراكبة رسالة خطأ كما يلي:

تحقَّق من صحة تنفيذ حزمة Input SDK باستخدام adb في سطر الأوامر.
للحصول على خريطة الإدخال الحالية، استخدِم الأمر adb shell التالي (استبدِل MY.PACKAGE.NAME باسم لعبتك):
adb shell dumpsys input_mapping_service --get MY.PACKAGE.NAME
ستظهر لك نتيجة مشابهة لما يلي في حال تم تسجيل InputMap بنجاح:
Getting input map for com.example.inputsample...
Successfully received the following inputmap:
# com.google.android.libraries.play.games.InputMap@d73526e1
input_groups {
group_label: "Basic Movement"
input_actions {
action_label: "Jump"
input_controls {
keycodes: 51
keycodes: 19
}
unique_id: 0
}
input_actions {
action_label: "Left"
input_controls {
keycodes: 29
keycodes: 21
}
unique_id: 1
}
input_actions {
action_label: "Right"
input_controls {
keycodes: 32
keycodes: 22
}
unique_id: 2
}
input_actions {
action_label: "Use"
input_controls {
keycodes: 33
keycodes: 66
mouse_actions: MOUSE_LEFT_CLICK
mouse_actions_value: 0
}
unique_id: 3
}
}
input_groups {
group_label: "Special Input"
input_actions {
action_label: "Jump"
input_controls {
keycodes: 51
keycodes: 19
keycodes: 62
mouse_actions: MOUSE_LEFT_CLICK
mouse_actions_value: 0
}
unique_id: 4
}
input_actions {
action_label: "Duck"
input_controls {
keycodes: 47
keycodes: 20
keycodes: 113
mouse_actions: MOUSE_RIGHT_CLICK
mouse_actions_value: 1
}
unique_id: 5
}
}
mouse_settings {
allow_mouse_sensitivity_adjustment: true
invert_mouse_movement: true
}
Localization
لا تستخدم حزمة تطوير البرامج (SDK) الخاصة بأداة الإدخال نظام تحديد الموقع الجغرافي في Android. نتيجةً لذلك، يجب تقديم سلاسل مترجمة عند إرسال InputMap. يمكنك أيضًا استخدام نظام الترجمة في محرّك الألعاب.
Proguard
عند استخدام Proguard لتصغير حجم لعبتك، أضِف القواعد التالية إلى ملف إعدادات Proguard للتأكّد من عدم إزالة حزمة SDK من الحزمة النهائية:
-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }
الخطوات التالية
بعد دمج حزمة تطوير البرامج (SDK) الخاصة بأدوات التحكّم في لعبتك، يمكنك مواصلة استيفاء أي متطلبات متبقية من متطلبات "ألعاب Google Play على الكمبيوتر". لمزيد من المعلومات، يُرجى الاطّلاع على بدء استخدام "ألعاب Google Play على الكمبيوتر".