بدء استخدام حزمة تطوير البرامج (SDK) للإدخال

يصف هذا المستند كيفية إعداد وعرض SDK للإدخال في الألعاب المتوافقة مع برنامج "ألعاب Google Play على الكمبيوتر". تتضمن المهام إضافة حزمة SDK للعبتك وإنشاء خريطة إدخال تحتوي على مهام ألعاب-إجراءات-إدخال-المستخدمين.

قبل البدء

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

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

يُعد كل عنصر تحكم InputAction (على سبيل المثال، "J" لعبارة "Jump") كما تنظم InputActions إلى InputGroups. قد يمثل InputGroup قيمة مختلفة الوضع في لعبتك، مثل "القيادة" أو "المشي" أو "القائمة الرئيسية". يمكنك أيضًا استخدِم InputContexts للإشارة إلى المجموعات النشطة في نقاط مختلفة من باللعبة.

يمكنك تفعيل إعادة تخصيص لوحة المفاتيح ليتم التعامل معها تلقائيًا، ولكن إذا وكنت تفضل توفير واجهة لإعادة تخصيص التحكم الخاصة بك، فيمكنك بعد ذلك تعطيل إعادة تخصيص حزمة تطوير البرامج (SDK) للإدخال.

يوضّح الرسم البياني للتسلسل التالي طريقة عمل واجهة برمجة التطبيقات لحزمة تطوير البرامج (SDK) للإدخال:

الرسم البياني لتسلسل تنفيذ لعبة تستدعي واجهة برمجة تطبيقات حِزمة تطوير البرامج (SDK) للإدخال
وتفاعله مع Android
الخاص بك.

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

إعلان يظهر على سطح الفيديو في برنامج "ألعاب Google Play على الكمبيوتر"

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

يظهر على سطح الصفحة برنامج "ألعاب Google Play على الكمبيوتر".

أفضل الممارسات لتصميم روابط المفاتيح

عند تصميم روابط المفاتيح، ضع في اعتبارك أفضل الممارسات التالية:

  • تجميع InputActions في InputGroups مرتبط منطقيًا لتحسينه التنقل وقابلية اكتشاف عناصر التحكم أثناء اللعب.
  • عليك تخصيص كل InputGroup إلى InputContext واحد على الأكثر. حبيبات دقيقة تقدّم ميزة InputMap تجربة أفضل للتنقل بين عناصر التحكّم من خلال التراكب.
  • أنشِئ InputContext لكل نوع مشهد مختلف في لعبتك. يمكنك عادةً استخدام InputContext واحدة لكل "ما يشبه قائمة الطعام". المشاهد. استخدِم InputContexts مختلفة لأي ألعاب مصغّرة في لعبتك أو في عناصر تحكم بديلة لمشهد واحد.
  • إذا تم تصميم إجراءين لاستخدام نفس المفتاح تحت InputContext، استخدِم سلسلة التصنيف مثل "تفاعل أو إطلاق النار".
  • إذا كان هناك مفتاحان مصمّمان لربطهما بجهاز InputAction نفسه، استخدِم المفتاح 2 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 على الكمبيوتر" عناصر التحكّم المُعاد تخصيصها محليًا لكل مستخدم. مما يتيح القدرة على التحكم في جلسات الألعاب. هذه المعلومات محفوظة على القرص لنظام التشغيل PC فقط ولا تؤثر على تجربة الهاتف المحمول. يتم حذف بيانات عنصر التحكّم عندما يلغي المستخدم تثبيت برنامج "ألعاب Google Play على الكمبيوتر" أو يعيد تثبيته. ولا تكون هذه البيانات مستمرة على عدة أجهزة كمبيوتر.

لإتاحة ميزة إعادة التخصيص في لعبتك، تجنَّب القيود التالية:

قيود إعادة التخصيص

يمكن إيقاف ميزات إعادة تخصيص المفاتيح في لعبتك إذا كانت عمليات ربط المفاتيح تحتوي على أي مما يلي: في الحالات التالية:

  • InputActions مفاتيح متعددة لا تتألف من مفتاح تعديل + a مفتاح غير معدل. على سبيل المثال، يكون Shift + A صالحًا ولكن A + B، Ctrl + Alt أو Shift + A + Tab غير متاح.
  • يتضمّن InputMap InputActions أو InputGroups أو InputContexts. بمعرّفات فريدة متكررة.

حدود إعادة التخصيص

عند تصميم روابط المفاتيح لإعادة التعيين، ضع في اعتبارك ما يلي: القيود:

  • لا يمكن إعادة التخصيص إلى مجموعات المفاتيح. على سبيل المثال، لا يستطيع المستخدمون أعِد ضبط Shift + A على Ctrl + B أو A إلى Shift + A.
  • لا يمكن إعادة تخصيص "InputActions" باستخدام أزرار الماوس. بالنسبة على سبيل المثال، لا يمكن إعادة تخصيص Shift + النقر بزر الماوس الأيمن.

اختبار إعادة تخصيص المفاتيح في محاكي برنامج "ألعاب Google Play على الكمبيوتر"

يمكنك في أي وقت تفعيل ميزة إعادة التخصيص في محاكي "ألعاب Google Play على الكمبيوتر" من خلال إصدار أمر adb التالي:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

يتغير التراكب كما في الصورة التالية:

يظهر الإعلان المركّب مع تفعيل إعادة تخصيص المفاتيح.

إضافة حزمة SDK

ثبِّت "حزمة تطوير البرامج (SDK) للإدخال" وفقًا لمنصّة التطوير التي تستخدمها.

Java وKotlin

احصل على حزمة SDK للإدخال لـ Java أو Kotlin عن طريق إضافة تبعية إلى ملف build.gradle على مستوى الوحدة:

dependencies {
  implementation 'com.google.android.libraries.play.games:inputmapping:1.1.0-beta'
  ...
}

الانسجام

حزمة تطوير البرامج (SDK) للإدخال هي حزمة Unity عادية تتضمّن العديد من التبعيات.

مطلوب تثبيت الحزمة التي تحتوي على جميع التبعيات. تتوفر عدة طرق لتثبيت الحزم.

تثبيت ".unitypackage"

تنزيل ملف unitypackage لحزمة تطوير البرامج (SDK) مع كل تبعياته. يمكنك تثبيت ".unitypackage" من خلال النقر على مواد العرض > استيراد الحزمة > الحزمة المخصّصة وتحديد موقع الملف الذي نزّلته

التثبيت باستخدام UPM

وبدلاً من ذلك، يمكنك تثبيت الحزمة باستخدام مدير حزم Unity من خلال جارٍ تنزيل .tgz وتثبيت ملحقاته:

التثبيت باستخدام OpenUPM

يمكنك تثبيت الحزمة باستخدام OpenUPM.

$ openupm add com.google.android.libraries.play.games.inputmapping

نماذج ألعاب

للحصول على أمثلة حول كيفية الدمج مع حزمة أدوات تطوير البرامج (SDK) للإدخال، يُرجى الاطّلاع على نفق AGDK لألعاب Kotlin أو Java Trivial Kart من ألعاب Unity.

إنشاء روابط المفاتيح

يمكنك تسجيل عمليات ربط المفاتيح من خلال إنشاء InputMap وعرضها باستخدام InputMappingProvider يوضح المثال التالي InputMappingProvider:

Kotlin

class InputSDKProvider : InputMappingProvider {
  override fun onProvideInputMap(): InputMap {
    TODO("Not yet implemented")
  }
}

Java

public class InputSDKProvider implements InputMappingProvider {
    private static final String INPUTMAP_VERSION = "1.0.0";

    @Override
    @NonNull
    public InputMap onProvideInputMap() {
        // TODO: return an InputMap
    }
}

#C

#if PLAY_GAMES_PC
using Java.Lang;
using Java.Util;
using Google.Android.Libraries.Play.Games.Inputmapping;
using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel;

public class InputSDKProvider : InputMappingProviderCallbackHelper
{
    public static readonly string INPUT_MAP_VERSION = "1.0.0";

    public override InputMap OnProvideInputMap()
    {
        // TODO: return an InputMap
    }
}
#endif

تحديد إجراءات الإدخال

تُستخدَم الفئة InputAction لربط مفتاح أو مجموعة مفاتيح بلعبة معيّنة. اتخاذ القرار. يجب أن يكون لدى InputActions معرّفات فريدة في جميع InputActions.

إذا كنت تدعم إعادة التخصيص، يمكنك تحديد InputActions. وإعادة تخصيصه. إذا كانت لعبتك لا تتيح إعادة التخصيص، عليك ضبط إعدادات إعادة التخصيص. تم إيقاف الخيار لجميع InputActions، ولكن حزمة تطوير البرامج (SDK) للإدخال وذكاء بما يكفي لإيقاف إعادة التخصيص إذا لم تكن تدعمها في InputMap

يربط هذا المثال مفتاح المسافة بالإجراء Drive.

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
);

يتم عرض enterAction بمفتاح واحد في التراكب.

ويمكن أن تمثل الإجراءات إدخالات الماوس أيضًا. يضبط هذا المثال خيار النقر بزر الماوس الأيسر على إجراء نقل:

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
);

MouseionAction معروض في التراكب

يتم تحديد مجموعات المفاتيح من خلال تمرير رموز مفاتيح متعددة إلى InputAction في هذا المثال، تمّ تعيين space + shift إلى إجراء Turbo، الذي يعمل حتى عند ربط المساحة بـ Drive.

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) للإدخال مزج أزرار الماوس والمفاتيح معًا إجراء واحد. يشير هذا المثال إلى أنّ المفتاحَين Shift والنقر بزر الماوس الأيمن الضغط معًا على نقطة وسيطة في نموذج اللعبة هذه:

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
);

مجموعة من المفاتيح والماوس enterAction المعروضة في الإعلان على سطح الصفحة.

يحتوي الإدخالAction على الحقول التالية:

  • 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() لضبط سياقًا كلما انتقلت لعبتك إلى مشهد مختلف الصورة التالية هذا السلوك: في نموذج "القيادة" المشهد، وعناصر التحكم في الطريق يتم عرض الإجراءات أعلى التراكب. عند فتح "المتجر" القائمة، "عناصر التحكّم في القائمة" يتم عرض الإجراءات أعلى التراكب.

EnterContexts ترتب المجموعات في التراكب.

يتم تطبيق هذه التعديلات على التراكب من خلال ضبط InputContext مختلف على النقاط المختلفة في لعبتك. ولإجراء ذلك:

  1. تجميع InputActions من خلال إجراءات ذات صلة منطقيًا باستخدام InputGroups
  2. يمكنك تعيين قيمة 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 إلى حساسية الماوس. وأن يتم قلب الماوس على المحور ص.
  • 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: سلسلة نسخة يمكن لشخص عادي قراءتها لتحديد إصدار معيّن من بيانات الإدخال بين نسختين من تغييرات بيانات الإدخال.

تلقّي إشعارات بشأن إعادة تخصيص الأحداث (اختياري)

تلقّي إشعارات حول أحداث إعادة تخصيص الأحداث للإعلام بالمفاتيح التي يتم استخدامها في لعبتك. يتيح هذا الإجراء للعبتك تحديث مواد العرض التي تظهر على شاشة اللعبة. المستخدم لعرض عناصر التحكم في الإجراءات.

توضح الصورة التالية مثالاً على هذا السلوك حيث بعد إعادة تخصيص المفاتيح G وP وS إلى J وX T على التوالي، يتمّ تحديث عناصر واجهة المستخدم الخاصة باللعبة لتصبح لعرض المفاتيح التي يحددها المستخدم.

واجهة مستخدم تتفاعل مع إعادة تخصيص الأحداث باستخدام استدعاء enterRemappingListener.

ويتم تحقيق هذه الوظيفة من خلال تسجيل 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 للاختبار التلقائي والتحقق.

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

يمكنك التحقُّق من تنفيذ حزمة تطوير البرامج (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 على الكمبيوتر".