इनपुट SDK टूल का इस्तेमाल शुरू करें

इस दस्तावेज़ में, पीसी पर Google Play Games के साथ काम करने वाले गेम में इनपुट SDK टूल को सेट अप और दिखाने का तरीका बताया गया है. इन टास्क में, अपने गेम में SDK टूल जोड़ना और इनपुट मैप जनरेट करना शामिल है. इस मैप में, गेम ऐक्शन से उपयोगकर्ता इनपुट असाइनमेंट जुड़े होते हैं.

शुरू करने से पहले

अपने गेम में Input SDK टूल जोड़ने से पहले, आपको अपने गेम इंजन के इनपुट सिस्टम का इस्तेमाल करके, कीबोर्ड और माउस इनपुट की सुविधा देनी होगी.

Input SDK टूल, पीसी पर Google Play Games को यह जानकारी देता है कि आपके गेम में किन कंट्रोल का इस्तेमाल किया जाता है, ताकि उन्हें उपयोगकर्ता को दिखाया जा सके. इसके अलावा, उपयोगकर्ताओं को कीबोर्ड को रीमैप करने की अनुमति भी दी जा सकती है.

हर कंट्रोल एक InputAction होता है, जैसे कि "कूदें" के लिए "J". साथ ही, InputActions को InputGroups में व्यवस्थित किया जाता है. InputGroup, आपके गेम में किसी अलग मोड को दिखा सकता है. जैसे, "ड्राइविंग" या "चलना" या "मुख्य मेन्यू". InputContexts का इस्तेमाल करके यह भी दिखाया जा सकता है कि गेम के अलग-अलग हिस्सों में कौनसे ग्रुप सक्रिय हैं.

कीबोर्ड को अपने-आप रीमैप करने की सुविधा चालू की जा सकती है. हालांकि, अगर आपको खुद कंट्रोल रीमैप करने का इंटरफ़ेस देना है, तो इनपुट एसडीके टूल को रीमैप करने की सुविधा बंद की जा सकती है.

नीचे दिए गए क्रम के डायग्राम में बताया गया है कि Input SDK का एपीआई कैसे काम करता है:

किसी गेम को लागू करने का सिलसिलेवार डायग्राम, जो Input SDK टूल के एपीआई को कॉल करता है और Android डिवाइस के साथ इंटरैक्ट करता है.

जब आपके गेम में Input SDK टूल लागू होता है, तो आपके कंट्रोल, Google Play Games on PC के ओवरले में दिखते हैं.

Google Play Games on PC का ओवरले

Google Play Games on PC ओवरले ("ओवरले"), आपके गेम में तय किए गए कंट्रोल दिखाता है. उपयोगकर्ता Shift + Tab दबाकर, किसी भी समय ओवरले को ऐक्सेस कर सकते हैं.

Google Play Games on PC का ओवरले.

बटन बाइंडिंग डिज़ाइन करने के सबसे सही तरीके

बटन बाइंडिंग डिज़ाइन करते समय, इन सबसे सही तरीकों को ध्यान में रखें:

  • गेमप्ले के दौरान, नेविगेशन और कंट्रोल को खोजने की सुविधा को बेहतर बनाने के लिए, अपने InputActions को एक जैसे InputGroups में ग्रुप करें.
  • हर InputGroup को ज़्यादा से ज़्यादा एक InputContext को असाइन करें. InputMap के छोटे ग्रैन्यूल होने पर, ओवरले में अपने कंट्रोल पर नेविगेट करने का अनुभव बेहतर होता है.
  • अपने गेम के हर अलग-अलग टाइप के सीन के लिए एक InputContext बनाएं. आम तौर पर, अपने सभी "मेन्यू जैसे" सेन्स के लिए, एक ही InputContext का इस्तेमाल किया जा सकता है. अपने गेम में किसी भी मिनीगेम के लिए या किसी एक सीन के लिए, अलग-अलग InputContexts का इस्तेमाल करें.
  • अगर दो कार्रवाइयों को एक ही InputContext के तहत एक ही कुंजी का इस्तेमाल करने के लिए डिज़ाइन किया गया है, तो "इंटरैक्ट / फ़ायर" जैसी लेबल स्ट्रिंग का इस्तेमाल करें.
  • अगर दो बटन को एक ही InputAction से बांधने के लिए डिज़ाइन किया गया है, तो दो अलग-अलग InputActions का इस्तेमाल करें. ये दोनों बटन आपके गेम में एक ही कार्रवाई करते हैं. दोनों InputActions के लिए एक ही लेबल स्ट्रिंग का इस्तेमाल किया जा सकता है, लेकिन उसका आईडी अलग होना चाहिए.
  • अगर मॉडिफ़ायर बटन को बटन के किसी सेट पर लागू किया जाता है, तो मॉडिफ़ायर बटन के साथ एक InputAction का इस्तेमाल करें. इसके बजाय, मॉडिफ़ायर बटन के साथ कई InputActions का इस्तेमाल न करें. उदाहरण के लिए, Shift + W, Shift + A, Shift + S, Shift + D के बजाय, Shift और W, A, S, D का इस्तेमाल करें.
  • जब उपयोगकर्ता टेक्स्ट फ़ील्ड में लिखता है, तो इनपुट रीमैपिंग अपने-आप बंद हो जाती है. Android टेक्स्ट फ़ील्ड लागू करने के सबसे सही तरीकों का पालन करें, ताकि यह पक्का किया जा सके कि Android आपके गेम में टेक्स्ट फ़ील्ड का पता लगा सके और फिर से मैप की गई कुंजियों से उनमें रुकावट न आए. अगर आपके गेम में ग़ैर-सामान्य टेक्स्ट फ़ील्ड का इस्तेमाल करना है, तो मैन्युअल तरीके से रीमैपिंग बंद करने के लिए, setInputContext() के साथ InputContext का इस्तेमाल किया जा सकता है. इसमें InputGroups की खाली सूची शामिल होती है.
  • अगर आपका गेम, बटनों को फिर से मैप करने की सुविधा देता है, तो अपनी की बाइंडिंग को अपडेट करें. ऐसा करना, संवेदनशील कार्रवाई के लिए ज़रूरी है, जो उपयोगकर्ता के सेव किए गए वर्शन से मेल नहीं खा सकती. अगर हो सके, तो मौजूदा कंट्रोल के आईडी बदलने से बचें.

रीमैपिंग की सुविधा

Google Play Games on PC में, कीबोर्ड कंट्रोल को फिर से मैप करने की सुविधा उपलब्ध है. यह सुविधा, इनपुट SDK टूल का इस्तेमाल करके, आपके गेम में उपलब्ध की बाइंडिंग के आधार पर काम करती है. हालांकि, ऐसा करना ज़रूरी नहीं है और इसे पूरी तरह से बंद किया जा सकता है. उदाहरण के लिए, हो सकता है कि आप अपने कीबोर्ड के बटनों को फिर से मैप करने का इंटरफ़ेस खुद उपलब्ध कराना चाहें. अपने गेम के लिए, बटन बदलने की सुविधा बंद करने के लिए, आपको बस यह बताना होगा कि InputMap के लिए बटन बदलने की सुविधा बंद है. ज़्यादा जानकारी के लिए, InputMap बनाएं लेख पढ़ें.

इस सुविधा को ऐक्सेस करने के लिए, उपयोगकर्ताओं को ओवरले खोलना होगा. इसके बाद, उस ऐक्शन पर क्लिक करना होगा जिसे उन्हें रीमैप करना है. हर रीमैपिंग इवेंट के बाद, Google Play Games on PC, उपयोगकर्ता के रीमैप किए गए हर कंट्रोल को उन डिफ़ॉल्ट कंट्रोल से मैप करता है जो आपके गेम को मिलने चाहिए. इससे आपके गेम को यह जानने की ज़रूरत नहीं पड़ती कि खिलाड़ी ने कंट्रोल को रीमैप किया है. आपके पास अपने गेम में कीबोर्ड कंट्रोल दिखाने के लिए इस्तेमाल की गई ऐसेट को अपडेट करने का विकल्प है. इसके लिए, इवेंट को फिर से मैप करने के लिए कॉलबैक जोड़ें.

बटन को रीमैप करने की कोशिश करना

'पीसी के लिए Google Play Games', हर उपयोगकर्ता के लिए कंट्रोल को स्थानीय तौर पर सेव करता है. इससे गेमिंग सेशन के दौरान, कंट्रोल को लगातार इस्तेमाल किया जा सकता है. यह जानकारी सिर्फ़ पीसी प्लैटफ़ॉर्म के लिए डिस्क पर सेव की जाती है. इससे मोबाइल पर इस्तेमाल करने पर कोई असर नहीं पड़ता. जब उपयोगकर्ता पीसी पर Google Play Games को अनइंस्टॉल या फिर से इंस्टॉल करता है, तो कंट्रोल डेटा मिट जाता है. यह डेटा, एक से ज़्यादा पीसी डिवाइसों पर सेव नहीं रहता.

अपने गेम में बटनों को फिर से मैप करने की सुविधा इस्तेमाल करने के लिए, इन पाबंदियों से बचें:

रीमैप करने से जुड़ी पाबंदियां

अगर बटन बाइंडिंग में इनमें से कोई भी मामला शामिल है, तो आपके गेम में बटन फिर से मैप करने की सुविधाएं बंद की जा सकती हैं:

  • एक से ज़्यादा बटन वाला 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 Games' के एम्युलेटर पर, बटन को फिर से मैप करने की सुविधा को टेस्ट करना

Google Play Games on PC के इम्यूलेटर में, रीमैपिंग की सुविधा को कभी भी चालू किया जा सकता है. इसके लिए, adb कमांड का इस्तेमाल करके यह तरीका अपनाएं:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

ओवरले में यह बदलाव होता है, जैसा कि इस इमेज में दिखाया गया है:

बटन को फिर से मैप करने की सुविधा चालू होने पर ओवरले.

SDK टूल जोड़ना

अपने डेवलपमेंट प्लैटफ़ॉर्म के हिसाब से, Input SDK टूल इंस्टॉल करें.

Java और Kotlin

अपने मॉड्यूल-लेवल की build.gradle फ़ाइल में डिपेंडेंसी जोड़कर, Java या Kotlin के लिए इनपुट SDK टूल पाएं:

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

Unity

Input SDK टूल, Unity का एक स्टैंडर्ड पैकेज है. इसमें कई डिपेंडेंसी शामिल हैं.

पैकेज को सभी डिपेंडेंसी के साथ इंस्टॉल करना ज़रूरी है. पैकेज इंस्टॉल करने के कई तरीके हैं.

.unitypackage इंस्टॉल करना

Input SDK टूल की unitypackage फ़ाइल और उसकी सभी डिपेंडेंसी डाउनलोड करें. .unitypackage को इंस्टॉल करने के लिए, ऐसेट > पैकेज इंपोर्ट करें > कस्टम पैकेज को चुनें और डाउनलोड की गई फ़ाइल ढूंढें.

UPM का इस्तेमाल करके इंस्टॉल करना

इसके अलावा, .tgz को डाउनलोड करके और उसकी डिपेंडेंसी इंस्टॉल करके, Unity Package Manager का इस्तेमाल करके भी पैकेज इंस्टॉल किया जा सकता है:

OpenUPM का इस्तेमाल करके इंस्टॉल करना

OpenUPM का इस्तेमाल करके पैकेज इंस्टॉल किया जा सकता है.

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

गेम के सैंपल

Input SDK टूल के साथ इंटिग्रेट करने के उदाहरणों के लिए, Kotlin या Java गेम के लिए AGDK टनल और Unity गेम के लिए Trivial Kart देखें.

अपनी की बाइंडिंग जनरेट करना

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 के लिए, बटन बदलने की सुविधा को बंद करना चाहिए. हालांकि, अगर आपके InputMap में बटन बदलने की सुविधा काम नहीं करती है, तो Input SDK टूल अपने-आप बटन बदलने की सुविधा बंद कर देगा.

इस उदाहरण में, space बटन को 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
);

ओवरले में दिखने वाला एक बटन वाला InputAction.

कार्रवाइयां, माउस इनपुट को भी दिखा सकती हैं. इस उदाहरण में, लेफ़्ट क्लिक को ले जाएं ऐक्शन पर सेट किया गया है:

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 को कई बटन कोड भेजे जाते हैं. इस उदाहरण में, space + shift को Turbo ऐक्शन पर मैप किया गया है. यह तब भी काम करता है, जब Space को 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
);

ओवरले में दिखाया गया मल्टी-की InputAction.

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

ओवरले में दिखाया गया, बटन + माउस InputAction का कॉम्बिनेशन.

InputAction में ये फ़ील्ड होते हैं:

  • ActionLabel: इस ऐक्शन को दिखाने के लिए, यूज़र इंटरफ़ेस (यूआई) में दिखाई गई स्ट्रिंग. स्थानीय भाषा में अनुवाद करने की सुविधा अपने-आप काम नहीं करती. इसलिए, स्थानीय भाषा में अनुवाद करने की प्रोसेस शुरू से ही शुरू कर दें.
  • InputControls: इस कार्रवाई में इस्तेमाल होने वाले इनपुट कंट्रोल के बारे में बताता है. यह कंट्रोल, ओवरले में मैप को एक जैसे ग्लिफ़ पर ले जाता है.
  • InputActionId: InputIdentifier ऑब्जेक्ट, जो InputAction का नंबर आईडी और वर्शन सेव करता है. ज़्यादा जानकारी के लिए, ट्रैकिंग के लिए इस्तेमाल होने वाले मुख्य आईडी देखें.
  • InputRemappingOption: InputEnums.REMAP_OPTION_ENABLED या InputEnums.REMAP_OPTION_DISABLED में से कोई एक. इससे यह तय होता है कि कार्रवाई को फिर से मैप करने के लिए चालू किया गया है या नहीं. अगर आपका गेम, बटन को फिर से मैप करने की सुविधा के साथ काम नहीं करता है, तो इस फ़ील्ड को छोड़ा जा सकता है या इसे बंद किया जा सकता है.
  • RemappedInputControls: रीड-ओनली InputControls ऑब्जेक्ट, जिसका इस्तेमाल उपयोगकर्ता के रीमैप किए गए इवेंट पर सेट की गई रीमैप की गई कुंजी को पढ़ने के लिए किया जाता है. इसका इस्तेमाल, रीमैप किए गए इवेंट के बारे में सूचना पाने के लिए किया जाता है.

InputControls किसी कार्रवाई से जुड़े इनपुट दिखाता है. इसमें ये फ़ील्ड होते हैं:

  • AndroidKeycodes: यह किसी कार्रवाई से जुड़े कीबोर्ड इनपुट को दिखाने वाली पूर्णांकों की सूची होती है. इन्हें Unity के लिए, KeyEvent क्लास या AndroidKeycode क्लास में तय किया जाता है.
  • MouseActions: यह MouseAction वैल्यू की सूची होती है, जिसमें इस कार्रवाई से जुड़े माउस इनपुट की जानकारी होती है.

इनपुट ग्रुप तय करना

InputActions को InputGroups का इस्तेमाल करके, लॉजिक के हिसाब से मिलती-जुलती कार्रवाइयों के साथ ग्रुप किया जाता है. इससे ओवरले में नेविगेशन को बेहतर बनाने और उसे खोजने की सुविधा को कंट्रोल करने में मदद मिलती है. आपके गेम में हर InputGroup आईडी, सभी InputGroups के लिए यूनीक होना चाहिए.

इनपुट ऐक्शन को ग्रुप में व्यवस्थित करने से, खिलाड़ी को अपने मौजूदा कॉन्टेक्स्ट के लिए सही की बाइंडिंग ढूंढने में आसानी होती है.

अगर आपने रीमैपिंग की सुविधा उपलब्ध कराई है, तो यह तय किया जा सकता है कि InputGroups को किस पर रीमैप किया जा सकता है. अगर आपका गेम, बटन बदलने की सुविधा के साथ काम नहीं करता है, तो आपको अपने सभी InputGroups के लिए, बटन बदलने की सुविधा को बंद करना चाहिए. हालांकि, अगर आपके InputMap में बटन बदलने की सुविधा काम नहीं करती है, तो Input SDK टूल अपने-आप बटन बदलने की सुविधा बंद कर देगा.

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

इस उदाहरण में, ओवरले में सड़क के कंट्रोल और मेन्यू कंट्रोल के इनपुट ग्रुप दिखाए गए हैं:

ओवरले में एक InputMap दिखाया गया है, जिसमें सड़क के कंट्रोल और मेन्यू कंट्रोल इनपुट ग्रुप शामिल हैं.

InputGroup में ये फ़ील्ड होते हैं:

  • GroupLabel: ओवरले में दिखने वाली स्ट्रिंग, जिसका इस्तेमाल कार्रवाइयों के ग्रुप को व्यवस्थित तरीके से ग्रुप करने के लिए किया जा सकता है. यह स्ट्रिंग अपने-आप स्थानीय भाषा में नहीं बदलती.
  • InputActions: पिछले चरण में तय किए गए InputAction ऑब्जेक्ट की सूची. ये सभी कार्रवाइयां, ग्रुप हेडिंग के नीचे विज़ुअल तौर पर दिखाई जाती हैं.
  • InputGroupId: InputIdentifier ऑब्जेक्ट, जो InputGroup का नंबर आईडी और वर्शन सेव करता है. ज़्यादा जानकारी के लिए, ट्रैकिंग पासकोड देखें.
  • InputRemappingOption: InputEnums.REMAP_OPTION_ENABLED या InputEnums.REMAP_OPTION_DISABLED में से कोई एक. अगर यह विकल्प बंद है, तो इस ग्रुप के सभी InputAction ऑब्जेक्ट के लिए, रीमैपिंग की सुविधा बंद हो जाएगी. भले ही, उनके लिए रीमैपिंग की सुविधा चालू करने का विकल्प चुना गया हो. अगर यह सुविधा चालू है, तो इस ग्रुप से जुड़ी सभी कार्रवाइयों को फिर से मैप किया जा सकता है. हालांकि, ऐसा तब तक नहीं किया जा सकता, जब तक कि अलग-अलग कार्रवाइयों के लिए, 'बंद है' के तौर पर सेट न किया गया हो.

इनपुट के संदर्भ तय करना

InputContexts की मदद से, गेम के अलग-अलग सीन के लिए, कीबोर्ड कंट्रोल के अलग-अलग सेट का इस्तेमाल किया जा सकता है. उदाहरण के लिए:

  • गेम में आगे बढ़ने के बजाय, मेन्यू पर जाने के लिए इनपुट के अलग-अलग सेट तय किए जा सकते हैं.
  • अपने गेम में, गेमप्ले के मोड के आधार पर इनपुट के अलग-अलग सेट तय किए जा सकते हैं. जैसे, ड्राइविंग बनाम पैदल चलना.
  • गेम की मौजूदा स्थिति के आधार पर, इनपुट के अलग-अलग सेट तय किए जा सकते हैं. जैसे, किसी ओवरवर्ल्ड में नेविगेट करना बनाम किसी लेवल को खेलना.

InputContexts का इस्तेमाल करने पर, ओवरले में सबसे पहले इस्तेमाल किए जा रहे कॉन्टेक्स्ट के ग्रुप दिखते हैं. इस सुविधा को चालू करने के लिए, जब भी आपका गेम किसी दूसरे सीन में जाए, तो कॉन्टेक्स्ट सेट करने के लिए setInputContext() को कॉल करें. इस इमेज में इस व्यवहार के बारे में बताया गया है: "ड्राइविंग" सीन में, सड़क के कंट्रोल ऐक्शन, ओवरले में सबसे ऊपर दिखाए जाते हैं. "स्टोर" मेन्यू खोलने पर, ओवरले में सबसे ऊपर "मेन्यू कंट्रोल" ऐक्शन दिखते हैं.

ओवरले में ग्रुप को क्रम से लगाने वाले InputContexts.

ये ओवरले अपडेट, आपके गेम के अलग-अलग पॉइंट पर अलग-अलग InputContext सेट करके किए जाते हैं. ऐसा करने के लिए:

  1. InputGroups का इस्तेमाल करके, अपने InputActions को लॉजिक के हिसाब से मिलती-जुलती कार्रवाइयों के साथ ग्रुप करें
  2. अपने गेम के अलग-अलग हिस्सों के लिए, इन InputGroups को किसी InputContext को असाइन करें

एक हीInputContext से जुड़े InputGroups में, एक ही कुंजी का इस्तेमाल करने पर, एक-दूसरे से मेल न खाने वाले 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 ऑब्जेक्ट शामिल होते हैं जिनका इस्तेमाल खिलाड़ी कर सकता है.

अपनी की बाइंडिंग की रिपोर्ट करते समय, अपने गेम में इस्तेमाल किए गए सभी InputGroups के साथ एक InputMap बनाया जाता है.

अगर आपका गेम, बटन बदलने की सुविधा के साथ काम नहीं करता है, तो बटन बदलने की सुविधा को बंद करें और रिज़र्व की गई बटन को खाली छोड़ दें.

नीचे दिए गए उदाहरण में, InputMap बनाया गया है. इसका इस्तेमाल, InputGroups के कलेक्शन की रिपोर्ट करने के लिए किया जाता है.

Kotlin

companion object {
  val gameInputMap = InputMap.create(
    listOf(
      basicMenuNavigationInputGroup,
      menuActionKeysInputGroup,
      movementInputGroup,
      mouseMovementInputGroup,
      pauseMenuInputGroup),
    MouseSettings.create(true, false),
    InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID.toLong()),
    InputEnums.REMAP_OPTION_ENABLED,
    // Use ESCAPE as reserved remapping key
    listof(InputControls.create(listOf(KeyEvent.KEYCODE_ESCAPE), emptyList()))
  )
}

Java

public static final InputMap gameInputMap = InputMap.create(
        Arrays.asList(
                basicMenuNavigationInputGroup,
                menuActionKeysInputGroup,
                movementInputGroup,
                mouseMovementInputGroup,
                pauseMenuInputGroup),
        MouseSettings.create(true, false),
        InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID),
        REMAP_OPTION_ENABLED,
        // Use ESCAPE as reserved remapping key
        Arrays.asList(
                InputControls.create(
                        Collections.singletonList(KeyEvent.KEYCODE_ESCAPE),
                        Collections.emptyList()
                )
        )
);

C#

public static readonly InputMap gameInputMap = InputMap.Create(
    new[]
    {
        basicMenuNavigationInputGroup,
        menuActionKeysInputGroup,
        movementInputGroup,
        mouseMovementInputGroup,
        pauseMenuInputGroup,
    }.ToJavaList(),
    MouseSettings.Create(true, false),
    InputIdentifier.Create(INPUT_MAP_VERSION, INPUT_MAP_ID),
    InputEnums.REMAP_OPTION_ENABLED,
    // Use ESCAPE as reserved remapping key
    new[]
    {
        InputControls.Create(
            New[] {
            new Integer(AndroidKeyCode.KEYCODE_ESCAPE)
        }.ToJavaList(),
        new ArrayList<Integer>())
    }.ToJavaList()
);

InputMap में ये फ़ील्ड होते हैं:

  • InputGroups: आपके गेम से रिपोर्ट किए गए InputGroups. ग्रुप, ओवरले में क्रम से दिखाए जाते हैं. हालांकि, अगर setInputContext() कॉल का इस्तेमाल करने वाले मौजूदा ग्रुप तय किए जाते हैं, तो ऐसा नहीं होता.
  • MouseSettings: MouseSettings ऑब्जेक्ट से पता चलता है कि माउस की संवेदनशीलता को अडजस्ट किया जा सकता है और माउस को Y ऐक्सिस पर उलटा किया गया है.
  • InputMapId: InputIdentifier ऑब्जेक्ट, जो InputMap का नंबर आईडी और वर्शन सेव करता है. ज़्यादा जानकारी के लिए, ट्रैकिंग पासकोड आईडी देखें.
  • InputRemappingOption: InputEnums.REMAP_OPTION_ENABLED या InputEnums.REMAP_OPTION_DISABLED में से कोई एक. इससे पता चलता है कि रीमैप करने की सुविधा चालू है या नहीं.
  • ReservedControls: InputControls की ऐसी सूची जिसे उपयोगकर्ताओं को फिर से मैप करने की अनुमति नहीं दी जाएगी.

ट्रैकिंग कुंजी के आईडी

InputAction, InputGroup, InputContext, और InputMap ऑब्जेक्ट में एक InputIdentifier ऑब्जेक्ट होता है, जो यूनीक नंबर आईडी और स्ट्रिंग वर्शन आईडी को सेव करता है. अपने ऑब्जेक्ट के स्ट्रिंग वर्शन को ट्रैक करना ज़रूरी नहीं है. हालांकि, InputMap के वर्शन को ट्रैक करने के लिए, ऐसा करने का सुझाव दिया जाता है. अगर स्ट्रिंग वर्शन नहीं दिया जाता है, तो स्ट्रिंग खाली होती है. InputMap ऑब्जेक्ट के लिए, स्ट्रिंग वर्शन की ज़रूरत होती है.

यहां दिए गए उदाहरण में, InputActions या InputGroups को स्ट्रिंग वर्शन असाइन किया गया है:

Kotlin

class InputSDKProviderKotlin : InputMappingProvider {
  companion object {
    const val INPUTMAP_VERSION = "1.0.0"
    private val enterMenuInputAction = InputAction.create(
      "Enter menu",
      InputControls.create(listOf(KeyEvent.KEYCODE_ENTER), emptyList()),
      InputIdentifier.create(
        INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal.toLong()),
      InputEnums.REMAP_OPTION_ENABLED
    )

    private val movementInputGroup  = InputGroup.create(
      "Basic movement",
      listOf(
        moveUpInputAction,
        moveLeftInputAction,
        moveDownInputAction,
        mouseGameInputAction),
      InputIdentifier.create(
        INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal.toLong()),
      InputEnums.REMAP_OPTION_ENABLED)
  }
}

Java

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

    private static final InputAction enterMenuInputAction = InputAction.create(
            "Enter menu",
            InputControls.create(
                    Collections.singletonList(KeyEvent.KEYCODE_ENTER),
                    Collections.emptyList()),
            InputIdentifier.create(
                    INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal()),
            InputEnums.REMAP_OPTION_ENABLED
    );

    private static final InputGroup movementInputGroup = InputGroup.create(
            "Basic movement",
            Arrays.asList(
                    moveUpInputAction,
                    moveLeftInputAction,
                    moveDownInputAction,
                    moveRightInputAction,
                    mouseGameInputAction
            ),
            InputIdentifier.create(
                    INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal()),
            InputEnums.REMAP_OPTION_ENABLED
    );
}

C#

#if PLAY_GAMES_PC

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

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

    private static readonly InputAction enterMenuInputAction =
        InputAction.Create(
            "Enter menu",
            InputControls.Create(
                new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE)}.ToJavaList(),
                new ArrayList<Integer>()),
            InputIdentifier.Create(
                INPUT_MAP_VERSION,
                (long)InputEventIds.ENTER_MENU),
            InputEnums.REMAP_OPTION_ENABLED
        );

    private static readonly InputGroup movementInputGroup = InputGroup.Create(
        "Basic movement",
        new[]
        {
            moveUpInputAction,
            moveLeftInputAction,
            moveDownInputAction,
            moveRightInputAction,
            mouseGameInputAction
        }.ToJavaList(),
        InputIdentifier.Create(
            INPUT_MAP_VERSION,
            (long)InputGroupsIds.BASIC_MOVEMENT),
        InputEnums.REMAP_OPTION_ENABLED
    );
}
#endif

InputAction ऑब्जेक्ट के नंबर आईडी, आपके InputMap में मौजूद सभी InputActions के लिए यूनीक होने चाहिए. इसी तरह, InputMap में मौजूद सभी InputGroup के लिए, InputGroup ऑब्जेक्ट आईडी यूनीक होने चाहिए.InputGroups नीचे दिए गए सैंपल में, अपने ऑब्जेक्ट के यूनीक आईडी को ट्रैक करने के लिए, 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 पर रीमैप करने के बाद, गेम के यूज़र इंटरफ़ेस (यूआई) एलिमेंट अपडेट हो जाते हैं, ताकि उपयोगकर्ता की ओर से सेट किए गए बटन दिखाए जा सकें.

InputRemappingListener कॉलबैक का इस्तेमाल करके, रीमैपिंग इवेंट पर प्रतिक्रिया देने वाला यूज़र इंटरफ़ेस (यूआई).

यह सुविधा, 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 का इस्तेमाल किया जा रहा है, तो हर ट्रांज़िशन पर कॉन्टेक्स्ट को नए सीन पर सेट करें. इसमें शुरुआती सीन के लिए इस्तेमाल किया गया पहला कॉन्टेक्स्ट भी शामिल है. InputMap रजिस्टर करने के बाद, आपको InputContext सेट करना होगा.

अगर इवेंट को फिर से मैप करने पर सूचना पाने के लिए InputRemappingListeners का इस्तेमाल किया जा रहा है, तो InputMappingProvider को रजिस्टर करने से पहले InputRemappingListener को रजिस्टर करें. ऐसा न करने पर, लॉन्च के समय आपके गेम में अहम इवेंट शामिल नहीं हो सकते.

यहां दिए गए सैंपल में, एपीआई को शुरू करने का तरीका बताया गया है:

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 इंस्टेंस को अनरजिस्टर करें. हालांकि, अगर ऐसा नहीं किया जाता है, तो इनपुट एसडीके टूल, संसाधनों को लीक होने से बचाने के लिए स्मार्ट तरीके से काम करता है:

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
    }
}

टेस्ट

प्लेयर के अनुभव को देखने के लिए, ओवरले को मैन्युअल तरीके से खोलकर, Input SDK के लागू होने की जांच की जा सकती है. इसके अलावा, अपने-आप होने वाली जांच और पुष्टि के लिए, adb shell का इस्तेमाल किया जा सकता है.

'पीसी के लिए Google Play Games' एम्युलेटर, सामान्य गड़बड़ियों के हिसाब से आपके इनपुट मैप की जांच करता है. डुप्लीकेट यूनीक आईडी, अलग-अलग इनपुट मैप का इस्तेमाल करने या रीमैपिंग के नियमों के लागू न होने (अगर रीमैपिंग चालू है) जैसी स्थितियों में, ओवरले पर गड़बड़ी का यह मैसेज दिखता है: इनपुट SDK टूल का ओवरले.

कमांड लाइन पर adb का इस्तेमाल करके, इनपुट SDK टूल के लागू होने की पुष्टि करें. मौजूदा इनपुट मैप देखने के लिए, यहां दिए गए 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
}

स्थानीय भाषा के अनुसार

Input SDK, Android के लोकलाइज़ेशन सिस्टम का इस्तेमाल नहीं करता. इसलिए, InputMap सबमिट करते समय, आपको स्थानीय भाषा में स्ट्रिंग देनी होंगी. इसके अलावा, गेम इंजन के स्थानीय भाषा में अनुवाद करने वाले सिस्टम का भी इस्तेमाल किया जा सकता है.

Proguard

अपने गेम को छोटा करने के लिए Proguard का इस्तेमाल करते समय, अपनी Proguard कॉन्फ़िगरेशन फ़ाइल में ये नियम जोड़ें. इससे यह पक्का किया जा सकेगा कि आपके फ़ाइनल पैकेज से SDK टूल न हटाया जाए:

-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }

अगला कदम क्या है

अपने गेम में इनपुट एसडीके को इंटिग्रेट करने के बाद, Google Play Games on PC की बाकी ज़रूरी शर्तों को पूरा किया जा सकता है. ज़्यादा जानकारी के लिए, पीसी के लिए Google Play Games का इस्तेमाल शुरू करना लेख पढ़ें.