يوضِّح هذا المستند طريقة إعداد وعرض حزمة SDK للإدخال في الألعاب المتوافقة مع "ألعاب Google Play على الكمبيوتر". تشمل المهام إضافة حزمة تطوير البرامج (SDK) إلى لعبتك وإنشاء خريطة إدخال تحتوي على مهام game‐actions‐to‐user‐input.
قبل البدء
قبل إضافة حزمة تطوير البرامج (SDK) للإدخال إلى لعبتك، يجب إتاحة إدخال لوحة المفاتيح والماوس باستخدام نظام الإدخال في محرّك اللعبة.
توفّر حِزم تطوير البرامج (SDK) للإدخال معلومات إلى برنامج "ألعاب Google Play على الكمبيوتر" حول عناصر التحكّم في لعبتك ويمكن عرضها للمستخدم. يمكن أن يسمح أيضًا اختياريًا بإعادة تخصيص لوحة المفاتيح للمستخدمين.
كل عنصر تحكّم هو InputAction
(على سبيل المثال، "J" للإشارة إلى "Jump") ويمكنك تنظيم
InputActions
في InputGroups
. قد يمثل InputGroup
وضعًا مختلفًا في لعبتك، مثل "القيادة" أو "المشي" أو "القائمة الرئيسية". يمكنك أيضًا
استخدام InputContexts
للإشارة إلى المجموعات النشطة في مراحل مختلفة من
اللعبة.
يمكنك تفعيل عملية إعادة تخصيص لوحة المفاتيح ليتمّ ضبطها تلقائيًا، ولكن إذا كنت تفضّل تقديم واجهة إعادة تخصيص التحكّم الخاصة بك، يمكنك عندئذٍ إيقاف عملية إعادة ضبط حزمة تطوير البرامج (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
(راجع إنشاء مخطط الإدخال للحصول على مزيد من المعلومات).
للوصول إلى هذه الميزة، يحتاج المستخدمون إلى فتح التراكب ثم النقر على الإجراء الذي يريدون إعادة تعيينه. وبعد كل حدث يُعاد تخصيصه لبرنامج "ألعاب 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 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
بدلاً من ذلك، يمكنك تثبيت الحزمة باستخدام Unity's Package Manager
من خلال تنزيل .tgz
وتثبيت تبعياته:
- com.google.external-expertency-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
نماذج الألعاب
للحصول على أمثلة حول كيفية الدمج مع Invation 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 );
ويمكن أن تمثل الإجراءات مدخلات الماوس أيضًا. يحدد هذا المثال النقر الأيسر على إجراء نقل:
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 );
يحتوي InAction على الحقول التالية:
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
: مجموعات الإدخال التي تم الإبلاغ عنها من خلال لعبتك يتم عرض المجموعات بالترتيب في التراكب ما لم يتم تحديد المجموعات الحالية التي يتم استخدامها استدعاء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) للإدخال ذكية بما يكفي لتجنُّب تسرُّب الموارد في حال عدم إجراء ما يلي:
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 Shell للاختبار والتحقق الآلي.
يتحقّق محاكي برنامج "ألعاب Google Play على الكمبيوتر" من صحة خريطة الإدخال من خلال رصد الأخطاء الشائعة. بالنسبة إلى سيناريوهات مثل تكرار المعرّفات الفريدة أو استخدام خرائط إدخال مختلفة أو الإخفاق في قواعد إعادة التعيين (في حال تفعيل إعادة التعيين)، يعرض العنصر الذي يظهر على سطح الفيديو رسالة خطأ على النحو التالي:
تحقَّق من تنفيذ حزمة تطوير البرامج (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 لتصغير لعبتك، أضف القواعد التالية إلى ملف إعداد Proguard لضمان عدم إزالة حزمة SDK من الحزمة النهائية:
-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }
الخطوات التالية
بعد دمج حزمة SDK للإدخال في لعبتك، يمكنك مواصلة استيفاء أي متطلبات متبقّية ضمن برنامج "ألعاب Google Play على الكمبيوتر". لمعرفة مزيد من المعلومات، يُرجى الاطّلاع على بدء استخدام برنامج "ألعاب Google Play على الكمبيوتر".