Input SDK ব্যবহার করা শুরু করা

পিসি (PC)-তে Google Play Games কাজ করে এমন গেমগুলিতে Input SDK কীভাবে সেট-আপ ও ডিসপ্লে করতে হয় তা এই ডকুমেন্টে বর্ণনা করা হয়েছে। এইসব টাস্কের মধ্যে আপনার গেমে SDK যোগ করা এবং ইনপুট ম্যাপ তৈরি করা অন্তর্ভুক্ত, যার মধ্যে গেম‑অ্যাকশন‑টু‑ইউজার‑ইনপুট অ্যাসাইনমেন্ট থাকে।

শুরু করার আগে

আপনার গেমে Input SDK যোগ করার আগে, আপনাকে অবশ্যই কীবোর্ড ও মাউস ইনপুট আপনার গেম ইঞ্জিনের ইনপুট সিস্টেম ব্যবহার করে কাজ করাতে হবে।

Input SDK, পিসি (PC)-তে Google Play Games-কে এই বিষয়ে তথ্য প্রদান করে যে আপনার গেম কী কন্ট্রোল ব্যবহার করে, যাতে সেগুলি ব্যবহারকারীকে দেখানো যায়। এছাড়াও, এটি ব্যবহারকারীদের জন্য ঐচ্ছিকভাবে কীবোর্ড রিম্যাপিংয়ের অনুমতি দিতে পারে।

প্রতিটি কন্ট্রোল হল একটি InputAction (যেমন, "Jump"-এর জন্য "J") এবং আপনি নিজের InputActions-কে InputGroups-এ সাজান। InputGroup আপনার গেমে আলাদা মোড দেখাতে পারে, যেমন "ড্রাইভিং" বা "ওয়াকিং" বা "প্রধান মেনু"। এছাড়াও, গেমের বিভিন্ন পয়েন্টে কোন গ্রুপ অ্যাক্টিভ আছে তা বোঝাতে InputContexts ব্যবহার করতে পারেন।

আপনার জন্য অটোমেটিক হ্যান্ডেল করার জন্য কীবোর্ড রিম্যাপিং চালু করতে পারেন, কিন্তু আপনি যদি নিজের কন্ট্রোল রিম্যাপিং ইন্টারফেস প্রদান করতে চান, তাহলে আপনি ইনপুট SDK রিম্যাপিং বন্ধ করতে পারেন।

নিচের সিকোয়েন্স ডায়াগ্রাম থেকে ইনপুট SDK-এর API কীভাবে কাজ করে তা বোঝা যায়:

ইনপুট SDK API কল করে এমন গেম ইমপ্লিমেন্টেশনের সিকোয়েন্স ডায়াগ্রাম
এবং Android
ডিভাইসের সাথে এর ইন্টার‍্যাকশন।

আপনার গেম ইনপুট SDK প্রয়োগ করলে, আপনার কন্ট্রোলগুলি পিসি (PC)-তে Google Play Games ওভারলেতে দেখানো হয়।

পিসি (PC)-তে Google Play Games ওভারলে

পিসি (PC)-তে Google Play Games ওভারলে ("ওভারলে") আপনার গেমের দ্বারা নির্ধারিত কন্ট্রোল দেখায়। Shift + Tab প্রেস করে ব্যবহারকারীরা যেকোনও সময় ওভারলে অ্যাক্সেস করতে পারেন।

পিসি (PC)-তে Google Play Games ওভারলে।

কী বাইন্ডিং ডিজাইন করার পেশাদার পদ্ধতি

কী বাইন্ডিং ডিজাইন করার সময় নিম্নলিখিত পেশাদার পদ্ধতি বিবেচনা করুন:

  • গেমপ্লে চলাকালীন কন্ট্রোলগুলির নেভিগেশন ও খুঁজে পাওয়ার যোগ্যতা উন্নত করতে, আপনার InputActions-কে যুক্তিসঙ্গতভাবে সম্পর্কিত InputGroups-এ গ্রুপ করুন।
  • প্রতিটি InputGroup সর্বাধিক একটি InputContext-এর সাথে অ্যাসাইন করুন। ফাইন গ্র্যানুলার InputMap হলে ওভারলেতে কন্ট্রোল নেভিগেট করার ক্ষেত্রে আরও ভালো অভিজ্ঞতা পাওয়া যায়।
  • আপনার গেমের প্রতিটি আলাদা আলাদা ধরনের দৃশ্যের জন্য একটি করে InputContext তৈরি করুন। সাধারণত, আপনার সব "মেনু-এর মতো" সিনগুলির জন্য একটি InputContext ব্যবহার করতে পারবেন। আপনার গেমে থাকা যেকোনও মিনিগেমের জন্য আলাদা InputContexts ব্যবহার করুন অথবা একটি দৃশ্যের জন্য বিকল্প কন্ট্রোল ব্যবহার করুন।
  • দুটি অ্যাকশন যদি একই InputContext-এর অধীনে একই কী ব্যবহার করার জন্য ডিজাইন করা হয়, তাহলে "ইন্টার‍্যাক্ট / ফায়ার"-এর মতো লেবেল স্ট্রিং ব্যবহার করুন।
  • দুটি কী একই InputAction-এর সাথে বাইন্ড করার জন্য ডিজাইন করা হলে, আপনার গেমে একই অ্যাকশন পারফর্ম করে এমন ২টি আলাদা InputActions ব্যবহার করুন। আপনি দুটি InputActions-এর জন্য একই লেবেল স্ট্রিং ব্যবহার করতে পারেন, তবে এর আইডি আলাদা হতে হবে।
  • কীগুলির একটি সেটে মডিফায়ার কী প্রয়োগ করা হলে, একাধিক InputActions-এর পরিবর্তে মডিফায়ার কী সহ একটি InputAction রাখার কথা বিবেচনা করুন যা মডিফায়ার কী (যেমন: Shift + W, Shift + A, Shift + S, Shift + D-এর পরিবর্তে Shift ও W, A, S, D) একত্রিত করে।
  • ব্যবহারকারী টেক্সট ফিল্ডে লিখলে ইনপুট রিম্যাপিং অটোমেটিক বন্ধ হয়ে যায়। Android টেক্সট ফিল্ড প্রয়োগ করার জন্য পেশাদার পদ্ধতি অনুসরণ করুন যাতে Android আপনার গেমে টেক্সট ফিল্ড শনাক্ত করতে পারে এবং রিম্যাপ করা কী সেগুলির সাথে ইন্টারফেয়ার করতে না পারে। আপনার গেমকে যদি প্রথাগত নয় এমন টেক্সট ফিল্ড ব্যবহার করতে হয়, তাহলে আপনি ম্যানুয়ালি রিম্যাপিং বন্ধ করতে, setInputContext() ব্যবহার করতে পারেন, যার মধ্যে InputContext-এ InputGroups-এর একটি খালি তালিকা থাকে।
  • আপনার গেম রিম্যাপিং সাপোর্ট করলে, আপনার কী বাইন্ডিং আপডেট করার কথা বিবেচনা করুন। এটি একটি সংবেদনশীল অপারেশন যা ব্যবহারকারীর সেভ করা ভার্সনের সাথে কনফ্লিক্ট করতে পারে। সম্ভব হলে আগে থেকে থাকা কন্ট্রোলের আইডি পরিবর্তন করা এড়িয়ে চলুন।

রিম্যাপিং ফিচার

পিসি (PC)-তে Google Play Games, Input SDK ব্যবহার করে আপনার গেমের দেওয়া কী বাইন্ডিংয়ের উপর ভিত্তি করে কীবোর্ড কন্ট্রোল রিম্যাপিং কাজ করে। এটি ঐচ্ছিক এবং সম্পূর্ণ বন্ধ করা যেতে পারে। যেমন, আপনি হয়ত নিজের কীবোর্ড রিম্যাপিং ইন্টারফেস প্রদান করতে চান। আপনার গেমের জন্য রিম্যাপিং বন্ধ করতে, আপনাকে শুধু আপনার InputMap-এর জন্য রিম্যাপিং বিকল্প বন্ধ করতে হবে (আরও তথ্যের জন্য InputMap তৈরি করুন দেখুন)।

এই ফিচার অ্যাক্সেস করতে, ব্যবহারকারীকে ওভারলে খুলতে হবে এবং তারপর যে অ্যাকশন রিম্যাপ করতে চান সেটিতে ক্লিক করতে হবে। প্রতিটি রিম্যাপিং ইভেন্টের পরে, পিসি (PC)-তে Google Play Games, আপনার গেমের ডিফল্ট কন্ট্রোলে ব্যবহারকারীর রিম্যাপ করা প্রতিটি কন্ট্রোল ম্যাপ করে। তাই, প্লেয়ারের রিম্যাপিং সম্পর্কে আপনার গেমকে সচেতন হতে হবে না। আপনি ঐচ্ছিকভাবে, রিম্যাপিং ইভেন্টের জন্য কলব্যাক যোগ করে আপনার গেমে কীবোর্ড কন্ট্রোল দেখানোর জন্য ব্যবহৃত অ্যাসেট আপডেট করতে পারেন।

কী রিম্যাপ করার চেষ্টা করুন

পিসি (PC)-তে Google Play Games প্রতিটি ব্যবহারকারীর জন্য লোকালি রিম্যাপ করা কন্ট্রোল সেভ করে, এর ফলে গেমিং সেশন জুড়ে কন্ট্রোল সেভ করা যায়। এই তথ্য শুধুমাত্র পিসি (PC) প্ল্যাটফর্মের জন্য ডিস্কে সেভ করা হয় এবং এটি মোবাইল অভিজ্ঞতাকে প্রভাবিত করে না। ব্যবহারকারী পিসি (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 + মাউসের ডানদিকের বোতামে ক্লিক করা রিম্যাপ করা যাবে না।

পিসি (PC)-তে Google Play Games ইমুলেটরে কী ম্যাপ করার সুবিধা পরীক্ষা করা

আপনি যেকোনও সময় পিসি (PC) ইমুলেটরে Google Play Games-এ রিম্যাপিং ফিচার চালু করতে পারেন নিম্নলিখিত adb কমান্ড দিয়ে:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

নিচের ছবিতে দেখানো উপায়ে ওভারলে পরিবর্তন করুন:

কী রিম্যাপিং চালু করা ওভারলে।

SDK যোগ করুন

আপনার ডেভেলপমেন্ট প্ল্যাটফর্ম অনুযায়ী 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 ব্যবহার করে ইনস্টল করা

অথবা, আপনি Unity Package Manager ব্যবহার করে প্যাকেজ ইনস্টল করতে পারেন। এর জন্য .tgz ডাউনলোড করুন এবং এর ডিপেন্ডেন্সি ইনস্টল করুন:

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

জাভা

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

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

C#

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

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

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

আপনার ইনপুট অ্যাকশন সংজ্ঞায়িত করুন

InputAction ক্লাসটি কোনও গেম অ্যাকশনের সাথে কোনও কী বা কী কম্বিনেশন ম্যাপ করতে ব্যবহৃত হয়। InputActions-এর মধ্যে InputActions-এর অনন্য আইডি থাকতে হবে।

আপনি রিম্যাপিং সমর্থন করলে, কী InputActions রিম্যাপ করা যাবে তা নির্ধারণ করতে পারবেন। আপনার গেমে রিম্যাপিং কাজ না করলে, আপনার সব InputActions-এর জন্য রিম্যাপিং বিকল্প বন্ধ করে দিন, তবে ইনপুট SDK এতটাই বুদ্ধিমান যে আপনার InputMap-এ রিম্যাপিং কাজ না করলে সেটি বন্ধ করে দেয়।

এই উদাহরণে স্পেস কী-কে Drive অ্যাকশনের সাথে ম্যাপ করা হয়েছে।

Kotlin

companion object {
  private val driveInputAction = InputAction.create(
    "Drive",
    InputActionsIds.DRIVE.ordinal.toLong(),
    InputControls.create(listOf(KeyEvent.KEYCODE_SPACE), emptyList()),
    InputEnums.REMAP_OPTION_ENABLED)
}

জাভা

private static final InputAction driveInputAction = InputAction.create(
    "Drive",
    InputEventIds.DRIVE.ordinal(),
    InputControls.create(
            Collections.singletonList(KeyEvent.KEYCODE_SPACE),
            Collections.emptyList()),
    InputEnums.REMAP_OPTION_ENABLED
);

C#

private static readonly InputAction driveInputAction = InputAction.Create(
    "Drive",
    (long)InputEventIds.DRIVE,
    InputControls.Create(
        new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(),
        new ArrayList<Integer>()),
    InputEnums.REMAP_OPTION_ENABLED
);

ওভারলেতে একটি কী ইনপুট অ্যাকশন দেখানো হয়।

অ্যাকশন মাউস ইনপুটও দেখাতে পারে। এই উদাহরণে লেফ্ট-ক্লিক-কে সরান অ্যাকশনে সেট করা হয়েছে:

Kotlin

companion object {
  private val mouseInputAction = InputAction.create(
    "Move",
    InputActionsIds.MOUSE_MOVEMENT.ordinal.toLong(),
    InputControls.create(emptyList(), listOf(InputControls.MOUSE_LEFT_CLICK)),
    InputEnums.REMAP_OPTION_DISABLED)
}

জাভা

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

জাভা

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

জাভা

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: এই অ্যাকশন বোঝানোর জন্য UI-তে দেখানো স্ট্রিং। স্থানীয়করণ অটোমেটিক হয় না, তাই আগে থেকেই কোনও স্থানীয়করণ করে নিন।
  • InputControls: এই অ্যাকশন ব্যবহার করে এমন ইনপুট কন্ট্রোলকে সংজ্ঞায়িত করে। ওভারলেতে কন্ট্রোলগুলি একই ধরনের গ্লিফে ম্যাপ করা হয়।
  • InputActionId: InputIdentifier অবজেক্ট যা InputAction-এর (আরও তথ্যের জন্য ট্র্যাকিং কী আইডি দেখুন) নম্বর আইডি ও ভার্সন স্টোর করে।
  • InputRemappingOption: InputEnums.REMAP_OPTION_ENABLED বা InputEnums.REMAP_OPTION_DISABLED-এর মধ্যে একটি। অ্যাকশনটি রিম্যাপ করার জন্য চালু করা আছে কিনা তা নির্ধারণ করে। আপনার গেম রিম্যাপিং সাপোর্ট না করলে, আপনি এই ফিল্ড এড়িয়ে যেতে পারেন অথবা সেটি বন্ধ করে দিতে পারেন।
  • RemappedInputControls: রিম্যাপিং ইভেন্টে ব্যবহারকারীর রিম্যাপ করা কীসেট পড়ার জন্য InputControls রিড-অনলি অবজেক্ট ব্যবহার করা হয় (রিম্যাপিং ইভেন্টে বিজ্ঞপ্তি পাওয়ার জন্য ব্যবহার করা হয়)।

InputControls কোনও অ্যাকশনের সাথে যুক্ত ইনপুটকে বোঝায় এবং এতে নিম্নলিখিত ফিল্ড থাকে::

  • AndroidKeycodes: হল একটি অ্যাকশনের সাথে যুক্ত কীবোর্ড ইনপুট এর প্রতিনিধিত্বকারী পূর্ণসংখ্যার তালিকা। এগুলি Unity-এর জন্য KeyEvent ক্লাস বা AndroidKeycode ক্লাসে সংজ্ঞায়িত করা হয়।
  • MouseActions: হল MouseAction ভ্যালুর একটি তালিকা যা এই অ্যাকশনের সাথে যুক্ত মাউস ইনপুট কে উপস্থাপন করে।

আপনার ইনপুট গ্রুপকে সংজ্ঞায়িত করুন

ওভারলেতে নেভিগেশন ও কন্ট্রোল ডিসকভারেবিলিটি উন্নত করতে, InputActions-কে InputGroups ব্যবহার করে যুক্তিযুক্তভাবে সম্পর্কিত অ্যাকশনের সাথে গ্রুপ করা হয়। আপনার গেমের সব InputGroups জুড়ে প্রতিটি InputGroup আইডি অনন্য হতে হবে।

ইনপুট অ্যাকশনকে গ্রুপে সাজানোর মাধ্যমে, আপনি কোনও প্লেয়ারের পক্ষে তার বর্তমান কনটেক্সটের জন্য সঠিক কী বাইন্ডিং খুঁজে পাওয়া সহজ করে তোলেন।

আপনি রিম্যাপিং সমর্থন করলে, কী InputGroups রিম্যাপ করা যাবে তা নির্ধারণ করতে পারবেন। আপনার গেমে রিম্যাপিং কাজ না করলে, আপনার সব InputGroups-এর জন্য রিম্যাপিং বিকল্প বন্ধ করে দিন, তবে ইনপুট SDK এতটাই বুদ্ধিমান যে আপনার InputMap-এ রিম্যাপিং কাজ না করলে সেটি বন্ধ করে দেয়।

Kotlin

companion object {
  private val menuInputGroup = InputGroup.create(
    "Menu keys",
    listOf(
      navigateUpInputAction,
      navigateLeftInputAction,
      navigateDownInputAction,
      navigateRightInputAction,
      openMenuInputAction,
      returnMenuInputAction),
    InputGroupsIds.MENU_ACTION_KEYS.ordinal.toLong(),
    InputEnums.REMAP_OPTION_ENABLED
  )
}

জাভা

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. আপনার গেমের বিভিন্ন অংশের জন্য InputContext-এ এইসব InputGroups অ্যাসাইন করুন

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

জাভা

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

জাভা

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-এর নম্বর ID ও ভার্সন সেভ করে (আরও তথ্যের জন্য ট্র্যাকিং কী ID দেখুন )।
  • 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)
  }
}

জাভা

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-এর মধ্যে InputGroups InputGroup অবজেক্ট আইডি অনন্য হতে হবে। আপনার অবজেক্টের অনন্য আইডি ট্র্যাক করার জন্য কীভাবে 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

জাভা

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-এ রিম্যাপ করার পরে, গেমের UI এলিমেন্টগুলি আপডেট হয়ে ব্যবহারকারীর সেট করা কীগুলি দেখায়।

InputRemappingListener কলব্যাক ব্যবহার করে রিম্যাপিং ইভেন্টে UI প্রতিক্রিয়া জানায়।

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

জাভা

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 রেজিস্টার করুন অন্যথায়, লঞ্চের সময় আপনার গেম গুরুত্বপূর্ণ ইভেন্ট মিস করতে পারে।

নিম্নলিখিত নমুনা থেকে কীভাবে API চালু করতে হয় তা জানুন:

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

জাভা

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (isGooglePlayGamesOnPC()) {
        InputMappingClient inputMappingClient =
                Input.getInputMappingClient(this);
        // Register listener before registering the provider
        inputMappingClient.registerRemappingListener(
                new InputSDKRemappingListener());
        inputMappingClient.setInputMappingProvider(
                new InputSDKProvider());
        // Set the context after you have registered the provider
        inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext);
    }
}

C#

#if PLAY_GAMES_PC
using Google.Android.Libraries.Play.Games.Inputmapping;
using Google.Android.Libraries.Play.Games.InputMapping.ExternalType.Android.Content;
using Google.LibraryWrapper.Java;
#endif

public class GameManager : MonoBehaviour
{
#if PLAY_GAMES_PC
    private InputSDKMappingProvider _inputMapProvider =
        new InputSDKMappingProvider();
    private InputMappingClient _inputMappingClient;
#endif

    public void Awake()
    {
#if PLAY_GAMES_PC
        Context context = (Context)Utils.GetUnityActivity().GetRawObject();
        _inputMappingClient = Google.Android.Libraries.Play.Games.Inputmapping
            .Input.GetInputMappingClient(context);
        // Register listener before registering the provider.
        _inputMappingClient.RegisterRemappingListener(
            new InputSDKRemappingListener());
        _inputMappingClient.SetInputMappingProvider(_inputMapProvider);
        // Register context after you have registered the provider.
       _inputMappingClient.SetInputContext(
           InputSDKMappingProvider.menuSceneInputContext);
#endif
    }
}

অপ্রয়োজনীয়গুলি মুছুন

আপনার গেম বন্ধ হয়ে গেলে, আপনার InputMappingProvider ইনস্ট্যান্স এবং যেকোনও InputRemappingListener ইনস্ট্যান্স আনরেজিস্টার করুন, যদিও ইনপুট SDK এত স্মার্ট যে আপনি এটি না করলেও রিসোর্স লিক হওয়া এড়াতে পারে:

Kotlin

override fun onDestroy() {
    if (isGooglePlayGamesOnPC()) {
        val inputMappingClient = Input.getInputMappingClient(this)
        inputMappingClient.clearInputMappingProvider()
        inputMappingClient.clearRemappingListener()
    }

    super.onDestroy()
}

জাভা

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

পরীক্ষা

প্লেয়ার অভিজ্ঞতা দেখতে, ম্যানুয়ালি ওভারলে খুলে অথবা অটোমেটিক টেস্টিং ও যাচাইকরণের জন্য adb shell ব্যবহার করে, আপনার Input SDK প্রয়োগ করা হয়েছে কিনা তা পরীক্ষা করে দেখতে পারবেন।

পিসি (PC)-তে Google Play Games ইমুলেটর, সাধারণ সমস্যার সাথে তুলনা করে আপনার ইনপুট ম্যাপ সঠিক কিনা তা চেক করে। ডুপ্লিকেট অনন্য আইডি, আলাদা ইনপুট ম্যাপ ব্যবহার করা বা রিম্যাপিং সংক্রান্ত নিয়মের ক্ষেত্রে সমস্যা হলে (রিম্যাপিং চালু থাকলে), ওভারলেতে নিচে দেখানো সমস্যার মেসেজ দেখা যায়: Input SDK ওভারলে।

কমান্ড লাইনে adb ব্যবহার করে আপনার Input 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 ব্যবহার করার সময়, SDK যাতে আপনার ফাইনাল প্যাকেজ থেকে বাদ না যায় তা নিশ্চিত করতে, আপনার proguard কনফিগারেশন ফাইলে নিম্নলিখিত নিয়ম যোগ করুন:

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

এর পরে কী করতে হবে

আপনার গেমে Input SDK ইন্টিগ্রেট করার পরে, পিসি (PC)-তে Google Play Games-এর বাকি থাকা প্রয়োজনীয়তাগুলি আপনি পূরণ করতে পারবেন। আরও তথ্যের জন্য, পিসি (PC)-তে Google Play Games ব্যবহার করা শুরু করুন দেখুন।