يوضّح هذا المستند كيفية إعداد حزمة تطوير البرامج (SDK) لنظام الإدخال وعرضها في الألعاب المتوافقة مع "ألعاب Google Play على الكمبيوتر". تشمل المهام إضافة حزمة SDK إلى لعبتك وإنشاء خريطة إدخال تحتوي على assignments game‑actions‑to‑user‑input.
قبل البدء
قبل إضافة حزمة تطوير البرامج (SDK) الخاصة بإدخال البيانات إلى لعبتك، يجب أن تتيح استخدام البيانات من لوحة المفاتيح والماوس باستخدام نظام إدخال البيانات في محرّك اللعبة.
توفِّر حزمة تطوير البرامج (SDK) الخاصة بإدخال البيانات معلومات إلى تطبيق "ألعاب Google Play على الكمبيوتر" عن عناصر التحكّم التي تستخدمها لعبتك، حتى يمكن عرضها للمستخدم. ويمكنه أيضًا السماح للمستخدمين بإعادة ربط مفاتيح لوحة المفاتيح اختياريًا.
كل عنصر تحكّم هو InputAction
(مثلاً "J" للقفزة) ويمكنك تنظيم
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
واحد مع مفتاح التعديل بدلاً من استخدامInputAction
متعدّد يجمع مفتاح التعديل (على سبيل المثال، استخدِم Shift وW وA وS وD بدلاً من Shift + W وShift + A وShift + S وShift + D).InputActions
- يتم إيقاف إعادة تعيين الإدخال تلقائيًا عندما يكتب المستخدم في حقول
النص. اتّبِع أفضل الممارسات لتنفيذ حقول النصوص في Android لضمان
أنّه يمكن لنظام Android رصد حقول النصوص في لعبتك ومنع مفاتيح إعادة الربط
من التدخل فيها. إذا كانت لعبتك تستخدم حقل
setInputContext()
غير تقليدي، يمكنك استخدامInputContext
يحتوي على قائمة فارغة منInputGroups
لإيقاف إعادة الربط يدويًا. - إذا كانت لعبتك تتيح إعادة الربط، ننصحك بتعديل عمليات ربط المفاتيح، وهي عملية حساسة يمكن أن تتعارض مع الإصدارات التي حفظها المستخدم. تجنَّب تغيير أرقام تعريف عناصر التحكّم الحالية متى أمكن ذلك.
ميزة إعادة الربط
يتيح تطبيق "ألعاب Google Play على الكمبيوتر" إعادة ربط عناصر التحكّم في لوحة المفاتيح استنادًا إلى ربطات المفاتيح التي تقدّمها لعبتك باستخدام حزمة تطوير البرامج (SDK) Input. هذه الميزة اختيارية ويمكن إيقافها بالكامل. على سبيل المثال، قد تريد توفير واجهة خاصة بك لإعادة ربط مفاتيح لوحة المفاتيح. لإيقاف إعادة الربط في لعبتك، ما عليك سوى تحديد
خيار إيقاف إعادة الربط لجهاز InputMap
(اطّلِع على إنشاء InputMap للحصول على مزيد من المعلومات).
للوصول إلى هذه الميزة، على المستخدمين فتح المحتوى المركّب ثم النقر على الإجراء الذي يريدون إعادة تعيينه. بعد كل حدث إعادة تعيين، تُعيد "ألعاب Google Play على الكمبيوتر" تعيين كل عنصر تحكّم أعاد المستخدم تعيينه إلى عناصر التحكّم التلقائية التي تتوقّع لعبتك تلقّيها، وبالتالي لا تحتاج لعبتك إلى معرفة أنّ اللاعب أعاد تعيين عناصر التحكّم. يمكنك اختياريًا تعديل مواد العرض المستخدَمة لعرض عناصر التحكّم في لوحة المفاتيح في لعبتك من خلال إضافة دالة استدعاء لإعادة ربط الأحداث.
تُخزِّن ميزة "ألعاب Google Play على الكمبيوتر" عناصر التحكّم التي تمت إعادة تعيينها على الجهاز لكل مستخدم، ما يتيح الاحتفاظ بعناصر التحكّم على مدار جلسات اللعب. يتم تخزين هذه المعلومات على القرص لنظام التشغيل PC فقط، ولا تؤثّر في تجربة استخدام الأجهزة الجوّالة. يتم حذف بيانات التحكّم عند إلغاء تثبيت المستخدم لتطبيق "ألعاب 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 لـ Java أو Kotlin من خلال إضافة ملف build.gradle
تابع لمستوى الوحدة:
dependencies {
implementation 'com.google.android.libraries.play.games:inputmapping:1.1.1-beta'
...
}
الوحدة
حزمة Input SDK هي حزمة عادية في Unity تحتوي على عدة عناصر تابعة.
يجب تثبيت الحزمة مع جميع الملحقات. هناك عدة طرق لتثبيت الحِزم.
تثبيت .unitypackage
نزِّل ملف unitypackage لحزمة SDK الخاصة بإدخال البيانات
مع جميع ملحقاته. يمكنك تثبيت .unitypackage
من خلال اختيار
مواد العرض > استيراد حزمة > حزمة مخصّصة وتحديد مكان الملف الذي نزّلته.
التثبيت باستخدام أداة UPM
بدلاً من ذلك، يمكنك تثبيت الحزمة باستخدام
Unity Package Manager من خلال
تنزيل .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
أمثلة على الألعاب
للحصول على أمثلة على كيفية الدمج مع حزمة تطوير البرامج (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
: سلسلة يتم عرضها في التراكب ويمكن استخدامها لgrouped مجموعة من الإجراءات بشكل منطقي لا تتم ترجمة هذه السلسلة تلقائيًا. -
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 Input في لعبتك، يمكنك المتابعة مع استيفاء أي متطلبات متبقية من متطلبات "ألعاب Google Play على الكمبيوتر". لمزيد من المعلومات، يُرجى الاطّلاع على مقالة بدء استخدام تطبيق "ألعاب Google Play" على الكمبيوتر الشخصي.