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

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

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

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

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

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

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

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

गेम में Input SDK API को कॉल करने और 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, A, S, D का इस्तेमाल करें. इसके बजाय, Shift + W, Shift + A, Shift + S, Shift + D का इस्तेमाल न करें.
  • जब उपयोगकर्ता टेक्स्ट फ़ील्ड में लिखता है, तो इनपुट रीमैपिंग की सुविधा अपने-आप बंद हो जाती है. Android टेक्स्ट फ़ील्ड लागू करने के सबसे सही तरीके अपनाएं. इससे यह पक्का किया जा सकेगा कि Android आपके गेम में टेक्स्ट फ़ील्ड का पता लगा सके और रीमैप की गई कुंजियों को उनसे इंटरफ़ेयर करने से रोक सके. अगर आपके गेम को गैर-पारंपरिक टेक्स्ट फ़ील्ड का इस्तेमाल करना है, तो मैन्युअल तरीके से रीमैपिंग बंद करने के लिए, setInputContext() का इस्तेमाल किया जा सकता है. इसके साथ ही, InputContext में InputGroups की खाली सूची शामिल होनी चाहिए.
  • अगर आपके गेम में रीमैपिंग की सुविधा काम करती है, तो की-बाइंडिंग को अपडेट करने पर विचार करें. यह एक संवेदनशील कार्रवाई है, जिससे उपयोगकर्ता के सेव किए गए वर्शन के साथ टकराव हो सकता है. जब मुमकिन हो, तब मौजूदा कंट्रोल के आईडी बदलने से बचें.

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

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

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

कुंजी को रीमैप करने की कोशिश करें

Google Play Games on PC, हर उपयोगकर्ता के लिए रीमैप किए गए कंट्रोल को स्थानीय तौर पर सेव करता है. इससे गेमिंग सेशन के दौरान कंट्रोल की सेटिंग बनी रहती है. यह जानकारी सिर्फ़ पीसी प्लैटफ़ॉर्म के लिए डिस्क पर सेव की जाती है. इससे मोबाइल पर गेम खेलने के अनुभव पर कोई असर नहीं पड़ता. जब उपयोगकर्ता, पीसी पर 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 Emulator में, रीमैपिंग की सुविधा को किसी भी समय चालू किया जा सकता है. इसके लिए, आपको यह adb कमांड देनी होगी:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

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

कीबोर्ड शॉर्टकट को फिर से मैप करने की सुविधा वाला ओवरले.

एसडीके टूल जोड़ना

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

Java और Kotlin

अपने मॉड्यूल-लेवल की build.gradle फ़ाइल में डिपेंडेंसी जोड़कर, Java या Kotlin के लिए Input 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 गेम के लिए ट्रिवियल कार्ट देखें.

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

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

इस उदाहरण में, 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
);

ओवरले में दिखाया गया MouseInputAction.

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

ओवरले में दिखाया गया मल्टी-की इनपुट ऐक्शन.

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 में ये फ़ील्ड होते हैं:

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

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

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

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

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

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

रीमैपिंग की सुविधा देने पर, यह तय किया जा सकता है कि InputGroups को रीमैप किया जा सकता है. अगर आपका गेम रीमैपिंग की सुविधा के साथ काम नहीं करता है, तो आपको अपने सभी InputGroups के लिए रीमैपिंग के विकल्प को बंद करना चाहिए. हालांकि, Input 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() को कॉल करके कॉन्टेक्स्ट सेट करें. इस इमेज में, इस सुविधा के काम करने का तरीका दिखाया गया है: "ड्राइविंग" सीन में, सड़क के कंट्रोल से जुड़ी कार्रवाइयां, ओवरले में सबसे ऊपर दिखती हैं. "स्टोर" मेन्यू खोलने पर, "मेन्यू कंट्रोल" कार्रवाइयां ओवरले में सबसे ऊपर दिखती हैं.

InputContexts, ओवरले में ग्रुप को क्रम से लगाने की सुविधा देता है.

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

  1. InputGroups का इस्तेमाल करके, अपने InputActions को लॉजिक के हिसाब से मिलती-जुलती कार्रवाइयों के साथ ग्रुप करना
  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 ऑब्जेक्ट शामिल होते हैं जिन्हें खिलाड़ी इस्तेमाल कर सकते हैं.

कीबोर्ड के बटन असाइन करने की जानकारी देते समय, आपको अपने गेम में इस्तेमाल किए गए सभी 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 के लिए यूनीक होने चाहिए. इसी तरह, InputGroup ऑब्जेक्ट आईडी, InputMap में मौजूद सभी 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 को रजिस्टर करने से पहले InputRemappingListeners को रजिस्टर करें. ऐसा न करने पर, लॉन्च के समय आपका गेम ज़रूरी इवेंट को ट्रैक नहीं कर पाएगा.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 इंस्टेंस को अनरजिस्टर करें. हालांकि, अगर ऐसा नहीं किया जाता है, तो Input 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
    }
}

टेस्ट

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

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

कमांड लाइन पर adb का इस्तेमाल करके, Input SDK टूल लागू करने की पुष्टि करें. मौजूदा इनपुट मैप पाने के लिए, यहां दी गई adb shell कमांड का इस्तेमाल करें (adb shell को अपने गेम के नाम से बदलें):MY.PACKAGE.NAME

adb shell dumpsys input_mapping_service --get MY.PACKAGE.NAME

InputMap को रजिस्टर करने पर, आपको इससे मिलता-जुलता आउटपुट दिखेगा:

Getting input map for com.example.inputsample...
Successfully received the following inputmap:
# com.google.android.libraries.play.games.InputMap@d73526e1
input_groups {
  group_label: "Basic Movement"
  input_actions {
    action_label: "Jump"
    input_controls {
      keycodes: 51
      keycodes: 19
    }
    unique_id: 0
  }
  input_actions {
    action_label: "Left"
    input_controls {
      keycodes: 29
      keycodes: 21
    }
    unique_id: 1
  }
  input_actions {
    action_label: "Right"
    input_controls {
      keycodes: 32
      keycodes: 22
    }
    unique_id: 2
  }
  input_actions {
    action_label: "Use"
    input_controls {
      keycodes: 33
      keycodes: 66
      mouse_actions: MOUSE_LEFT_CLICK
      mouse_actions_value: 0
    }
    unique_id: 3
  }
}
input_groups {
  group_label: "Special Input"
  input_actions {
    action_label: "Jump"
    input_controls {
      keycodes: 51
      keycodes: 19
      keycodes: 62
      mouse_actions: MOUSE_LEFT_CLICK
      mouse_actions_value: 0
    }
    unique_id: 4
  }
  input_actions {
    action_label: "Duck"
    input_controls {
      keycodes: 47
      keycodes: 20
      keycodes: 113
      mouse_actions: MOUSE_RIGHT_CLICK
      mouse_actions_value: 1
    }
    unique_id: 5
  }
}
mouse_settings {
  allow_mouse_sensitivity_adjustment: true
  invert_mouse_movement: true
}

Localization

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

Proguard

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

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

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

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