ইনপুট SDK দিয়ে শুরু করুন

এই দস্তাবেজটি বর্ণনা করে যে কীভাবে পিসিতে Google Play গেমগুলিকে সমর্থন করে এমন গেমগুলিতে ইনপুট SDK সেট আপ এবং প্রদর্শন করতে হয়৷ কাজগুলির মধ্যে রয়েছে আপনার গেমে SDK যোগ করা এবং একটি ইনপুট মানচিত্র তৈরি করা, যাতে গেম-অ্যাকশন-টু-ব্যবহারকারী-ইনপুট অ্যাসাইনমেন্ট থাকে।

আপনি শুরু করার আগে

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

ইনপুট SDK পিসিতে Google Play গেমগুলিকে আপনার গেমটি কী নিয়ন্ত্রণ করে সে সম্পর্কে তথ্য সরবরাহ করে, যাতে সেগুলি ব্যবহারকারীর কাছে প্রদর্শিত হতে পারে৷ এটি ঐচ্ছিকভাবে ব্যবহারকারীদের জন্য কীবোর্ড রিম্যাপিংয়ের অনুমতি দিতে পারে।

প্রতিটি নিয়ন্ত্রণ হল একটি InputAction (যেমন "Jump" এর জন্য) এবং আপনি আপনার InputActions InputGroups এ সংগঠিত করেন। একটি InputGroup আপনার গেমে একটি ভিন্ন মোড উপস্থাপন করতে পারে, যেমন "ড্রাইভিং" বা "হাঁটা" বা "মেন মেনু"। গেমের বিভিন্ন পয়েন্টে কোন গোষ্ঠী সক্রিয় রয়েছে তা নির্দেশ করতে আপনি InputContexts ব্যবহার করতে পারেন।

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

ইনপুট SDK-এর API কীভাবে কাজ করে তা নিম্নলিখিত ক্রম চিত্রটি বর্ণনা করে:

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

যখন আপনার গেম ইনপুট SDK প্রয়োগ করে তখন আপনার নিয়ন্ত্রণগুলি PC ওভারলেতে Google Play গেমগুলিতে প্রদর্শিত হয়৷

পিসি ওভারলেতে গুগল প্লে গেমস

পিসি ওভারলেতে গুগল প্লে গেমস ("ওভারলে") আপনার গেম দ্বারা সংজ্ঞায়িত নিয়ন্ত্রণগুলি প্রদর্শন করে৷ ব্যবহারকারীরা যে কোনো সময় Shift + Tab টিপে ওভারলে অ্যাক্সেস করতে পারেন।

পিসি ওভারলেতে গুগল প্লে গেমস।

কী বাইন্ডিং ডিজাইন করার জন্য সর্বোত্তম অনুশীলন

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

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

রিম্যাপিং বৈশিষ্ট্য

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

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

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

পিসি স্টোরগুলিতে Google Play গেমগুলি প্রতিটি ব্যবহারকারীর জন্য স্থানীয়ভাবে নিয়ন্ত্রণগুলি পুনঃম্যাপ করা হয়েছে, গেমিং সেশন জুড়ে নিয়ন্ত্রণ স্থিরতা সক্ষম করে৷ এই তথ্যটি শুধুমাত্র 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 + রাইট-ক্লিক রিম্যাপ করা যাবে না।

পিসি এমুলেটরে গুগল প্লে গেমসে কী রিম্যাপিং পরীক্ষা করুন

আপনি নিম্নোক্ত adb কমান্ড জারি করে যেকোনো সময় PC এমুলেটরে Google Play Games-এ রিম্যাপিং বৈশিষ্ট্য সক্ষম করতে পারেন:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

নিম্নলিখিত চিত্রের মতো ওভারলে পরিবর্তন:

কী রিম্যাপিং সহ ওভারলে সক্ষম হয়েছে৷

SDK যোগ করুন

আপনার ডেভেলপমেন্ট প্ল্যাটফর্ম অনুযায়ী ইনপুট SDK ইনস্টল করুন।

জাভা এবং কোটলিন

আপনার মডিউল-স্তরের build.gradle ফাইলে একটি নির্ভরতা যোগ করে Java বা Kotlin-এর জন্য ইনপুট SDK পান:

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

ঐক্য

ইনপুট SDK হল একটি স্ট্যান্ডার্ড ইউনিটি প্যাকেজ যা বিভিন্ন নির্ভরতা সহ।

সমস্ত নির্ভরতা সহ প্যাকেজ ইনস্টল করা প্রয়োজন। প্যাকেজ ইনস্টল করার বিভিন্ন উপায় আছে।

.unitypackage ইন্সটল করুন

ইনপুট SDK ইউনিটিপ্যাকেজ ফাইলটি এর সমস্ত নির্ভরতা সহ ডাউনলোড করুন । আপনি সম্পদ > আমদানি প্যাকেজ > কাস্টম প্যাকেজ নির্বাচন করে এবং আপনার ডাউনলোড করা ফাইলটি সনাক্ত করে .unitypackage ইনস্টল করতে পারেন।

UPM ব্যবহার করে ইনস্টল করুন

বিকল্পভাবে আপনি .tgz ডাউনলোড করে এবং এর নির্ভরতা ইনস্টল করে ইউনিটি প্যাকেজ ম্যানেজার ব্যবহার করে প্যাকেজটি ইনস্টল করতে পারেন:

OpenUPM ব্যবহার করে ইনস্টল করুন

আপনি OpenUPM ব্যবহার করে প্যাকেজটি ইনস্টল করতে পারেন।

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

নমুনা গেম

ইনপুট SDK-এর সাথে কীভাবে একীভূত করা যায় তার উদাহরণগুলির জন্য, কোটলিন বা জাভা গেমগুলির জন্য AGDK টানেল এবং ইউনিটি গেমগুলির জন্য ট্রিভিয়াল কার্ট দেখুন৷

আপনার কী বাইন্ডিং তৈরি করুন

একটি InputMap তৈরি করে এবং একটি InputMappingProvider দিয়ে ফেরত দিয়ে আপনার কী বাইন্ডিংগুলি নিবন্ধন করুন৷ নিম্নলিখিত উদাহরণ একটি InputMappingProvider রূপরেখা দেয়:

কোটলিন

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

সি#

#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 জুড়ে অনন্য ID থাকতে হবে।

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

এই উদাহরণ মানচিত্র স্থান ড্রাইভ কর্মের চাবিকাঠি।

কোটলিন

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

সি#

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

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

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

কোটলিন

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

সি#

private static readonly InputAction mouseInputAction = InputAction.Create(
    "Move",
    (long)InputEventIds.MOUSE_MOVEMENT,
    InputControls.Create(
        new ArrayList<Integer>(),
        new[] { new Integer((int)PlayMouseAction.MouseLeftClick) }.ToJavaList()
    ),
    InputEnums.REMAP_OPTION_DISABLED
);

ওভারলেতে প্রদর্শিত মাউস ইনপুটঅ্যাকশন।

আপনার InputAction এ একাধিক কী কোড পাস করে কী সমন্বয় নির্দিষ্ট করা হয়। এই উদাহরণে স্থান + স্থানান্তর টার্বো অ্যাকশনে ম্যাপ করা হয়, যা তখনও কাজ করে স্থান ড্রাইভে ম্যাপ করা হয়েছে।

কোটলিন

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

সি#

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

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

ইনপুট SDK আপনাকে একটি একক ক্রিয়াকলাপের জন্য মাউস এবং কী বোতামগুলিকে একসাথে মিশ্রিত করতে দেয়৷ এই উদাহরণটি ইঙ্গিত করে শিফট এবং ডান-ক্লিক একসাথে চাপলে এই নমুনা গেমটিতে একটি ওয়েপয়েন্ট যোগ করে:

কোটলিন

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

সি#

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 : একটি কর্মের সাথে যুক্ত কীবোর্ড ইনপুট প্রতিনিধিত্বকারী পূর্ণসংখ্যার একটি তালিকা। এগুলি কী ইভেন্ট ক্লাস বা ইউনিটির জন্য অ্যান্ড্রয়েডকিকোড ক্লাসে সংজ্ঞায়িত করা হয়েছে।
  • MouseActions : এই ক্রিয়াটির সাথে যুক্ত মাউস ইনপুটগুলি উপস্থাপন করে MouseAction মানগুলির একটি তালিকা।

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

InputActions নেভিগেশন উন্নত করতে এবং ওভারলেতে আবিষ্কারযোগ্যতা নিয়ন্ত্রণ করতে InputGroups ব্যবহার করে যৌক্তিকভাবে-সম্পর্কিত ক্রিয়াগুলির সাথে গোষ্ঠীভুক্ত করা হয়। প্রতিটি InputGroup আইডি আপনার গেমের সমস্ত InputGroups জুড়ে অনন্য হওয়া প্রয়োজন৷

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

আপনি যদি রিম্যাপিং সমর্থন করেন তাহলে আপনি সংজ্ঞায়িত করতে পারেন যে InputGroups পুনরায় ম্যাপ করা যেতে পারে। যদি আপনার গেমটি রিম্যাপিং সমর্থন না করে তবে আপনার সমস্ত InputGroups জন্য রিম্যাপিং বিকল্পটি নিষ্ক্রিয় করা উচিত, তবে ইনপুট SDK রিম্যাপিং বন্ধ করার জন্য যথেষ্ট বুদ্ধিমান যদি আপনি এটিকে আপনার InputMap সমর্থন না করেন৷

কোটলিন

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

সি#

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() কল করুন। নিম্নলিখিত চিত্রটি এই আচরণটি প্রদর্শন করে: "ড্রাইভিং" দৃশ্যে, সড়ক নিয়ন্ত্রণের ক্রিয়াগুলি ওভারলের শীর্ষে দেখানো হয়েছে৷ "স্টোর" মেনু খোলার সময়, "মেনু নিয়ন্ত্রণ" ক্রিয়াগুলি ওভারলে এর শীর্ষে প্রদর্শিত হয়।

ওভারলেতে ইনপুট কনটেক্সট বাছাই করা গ্রুপ।

এই ওভারলে আপডেটগুলি আপনার গেমের বিভিন্ন পয়েন্টে একটি ভিন্ন InputContext সেট করে অর্জন করা হয়। এটি করতে:

  1. InputGroups ব্যবহার করে লজিক্যালি-সম্পর্কিত ক্রিয়াগুলির সাথে আপনার InputActions গোষ্ঠীবদ্ধ করুন৷
  2. আপনার গেমের বিভিন্ন অংশের জন্য এই InputGroups একটি InputContext বরাদ্দ করুন

একই InputContext এর অন্তর্গত InputGroups যেখানে একই কী ব্যবহার করা হয় সেখানে বিরোধপূর্ণ InputActions থাকতে পারে না। প্রতিটি InputGroup একটি InputContext এ বরাদ্দ করা একটি ভালো অভ্যাস।

নিম্নলিখিত নমুনা কোড InputContext যুক্তি প্রদর্শন করে:

কোটলিন

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

সি#

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 একটি সংগ্রহের প্রতিবেদন করতে ব্যবহৃত হয়।

কোটলিন

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

সি#

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

InputMap নিম্নলিখিত ক্ষেত্র রয়েছে:

  • InputGroups : আপনার গেম দ্বারা রিপোর্ট করা ইনপুট গোষ্ঠীগুলি। গোষ্ঠীগুলি ওভারলেতে ক্রমানুসারে প্রদর্শিত হয়, যদি না setInputContext() কলিং ব্যবহার করা বর্তমান গোষ্ঠীগুলি নির্দিষ্ট করা হয়।
  • MouseSettings : MouseSettings অবজেক্ট ইঙ্গিত করে যে মাউসের সংবেদনশীলতা সামঞ্জস্য করা যেতে পারে এবং মাউসটি y অক্ষে উল্টানো হয়।
  • InputMapId : InputIdentifier অবজেক্ট যা InputMap নম্বর আইডি এবং সংস্করণ সংরক্ষণ করে (আরো তথ্যের জন্য ট্র্যাকিং কী আইডি দেখুন)।
  • InputRemappingOption : InputEnums.REMAP_OPTION_ENABLED বা InputEnums.REMAP_OPTION_DISABLED মধ্যে একটি। রিম্যাপিং বৈশিষ্ট্য সক্রিয় করা হয়েছে কিনা তা নির্ধারণ করে।
  • ReservedControls : InputControls একটি তালিকা যা ব্যবহারকারীদের পুনরায় ম্যাপ করার অনুমতি দেওয়া হবে না।

কী আইডি ট্র্যাক করুন

InputAction , InputGroup , InputContext এবং InputMap অবজেক্টে একটি InputIdentifier অবজেক্ট থাকে যা একটি অনন্য নম্বর আইডি এবং একটি স্ট্রিং সংস্করণ আইডি সঞ্চয় করে। আপনার অবজেক্টের স্ট্রিং সংস্করণ ট্র্যাক করা ঐচ্ছিক কিন্তু আপনার InputMap এর সংস্করণগুলি ট্র্যাক করার জন্য সুপারিশ করা হয়। যদি স্ট্রিং সংস্করণ প্রদান করা না হয় তাহলে স্ট্রিং খালি। InputMap অবজেক্টের জন্য একটি স্ট্রিং সংস্করণ প্রয়োজন।

নিম্নলিখিত উদাহরণটি InputActions বা InputGroups এ একটি স্ট্রিং সংস্করণ বরাদ্দ করে:

কোটলিন

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

সি#

#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

আপনার InputMap সমস্ত InputActions জুড়ে InputAction অবজেক্ট নম্বর আইডি অবশ্যই অনন্য হতে হবে। একইভাবে, InputGroup অবজেক্ট আইডি অবশ্যই একটি InputMap এর সমস্ত InputGroups জুড়ে অনন্য হতে হবে। নিম্নলিখিত নমুনা দেখায় কিভাবে আপনার বস্তুর অনন্য আইডি ট্র্যাক করতে একটি enum ব্যবহার করতে হয়:

কোটলিন

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;

সি#

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 : ইনপুট ডেটা পরিবর্তনের 2 সংস্করণের মধ্যে ইনপুট ডেটার একটি সংস্করণ সনাক্ত করতে একটি মানব পাঠযোগ্য সংস্করণ স্ট্রিং সেট।

রিম্যাপিং ইভেন্টগুলিতে বিজ্ঞপ্তি পান (ঐচ্ছিক)

আপনার গেমে ব্যবহৃত কীগুলি সম্পর্কে অবহিত হওয়ার জন্য রিম্যাপ ইভেন্টগুলিতে বিজ্ঞপ্তিগুলি পান৷ এটি আপনার গেমটিকে অ্যাকশন কন্ট্রোল প্রদর্শন করতে ব্যবহৃত গেম স্ক্রিনে দেখানো সম্পদ আপডেট করতে দেয়।

নিম্নলিখিত চিত্রটি এই আচরণের একটি উদাহরণ দেখায় যেখানে কীগুলি পুনরায় ম্যাপ করার পরে জি , পৃ এবং এস থেকে জে , এক্স এবং টি যথাক্রমে, ব্যবহারকারীর দ্বারা সেট করা কীগুলি প্রদর্শনের জন্য গেমের UI উপাদানগুলি আপডেট করা হয়।

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

একটি InputRemappingListener কলব্যাক নিবন্ধন করে এই কার্যকারিতা অর্জন করা হয়। এই feautre বাস্তবায়ন করতে, একটি InputRemappingListener উদাহরণ নিবন্ধন করে শুরু করুন:

কোটলিন

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

সি#

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

নিম্নলিখিত নমুনা দেখায় কিভাবে API শুরু করতে হয়:

কোটলিন

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

সি#

#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 রিসোর্স ফাঁস হওয়া এড়াতে যথেষ্ট স্মার্ট যদি আপনি না করেন:

কোটলিন

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

সি#

public class GameManager : MonoBehaviour
{
    private void OnDestroy()
    {
#if PLAY_GAMES_PC
        _inputMappingClient.ClearInputMappingProvider();
        _inputMappingClient.ClearRemappingListener();
#endif
    }
}

পরীক্ষা

আপনি প্লেয়ারের অভিজ্ঞতা দেখতে ম্যানুয়ালি ওভারলে খোলার মাধ্যমে অথবা স্বয়ংক্রিয় পরীক্ষা ও যাচাইয়ের জন্য adb শেলের মাধ্যমে আপনার ইনপুট SDK বাস্তবায়ন পরীক্ষা করতে পারেন।

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

কমান্ড লাইনে adb ব্যবহার করে আপনার ইনপুট SDK বাস্তবায়ন যাচাই করুন। বর্তমান ইনপুট মানচিত্র পেতে, নিম্নলিখিত adb shell কমান্ড ব্যবহার করুন (আপনার গেমের নামের সাথে MY.PACKAGE.NAME প্রতিস্থাপন করুন):

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

আপনি যদি সফলভাবে আপনার InputMap নিবন্ধন করেন তাহলে আপনি এর অনুরূপ আউটপুট দেখতে পাবেন:

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

স্থানীয়করণ

ইনপুট SDK Android এর স্থানীয়করণ সিস্টেম ব্যবহার করে না। ফলস্বরূপ, InputMap জমা দেওয়ার সময় আপনাকে অবশ্যই স্থানীয় স্ট্রিং প্রদান করতে হবে। আপনি আপনার গেম ইঞ্জিনের স্থানীয়করণ সিস্টেমও ব্যবহার করতে পারেন।

প্রোগার্ড

আপনার গেমটি ছোট করার জন্য প্রোগার্ড ব্যবহার করার সময়, আপনার চূড়ান্ত প্যাকেজ থেকে SDK ছিনিয়ে না নেওয়ার জন্য আপনার প্রোগার্ড কনফিগারেশন ফাইলে নিম্নলিখিত নিয়মগুলি যোগ করুন:

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

এরপর কি

আপনি আপনার গেমে ইনপুট SDK সংহত করার পরে, আপনি পিসি প্রয়োজনীয়তাগুলির সাথে বাকি থাকা Google Play গেমগুলি চালিয়ে যেতে পারেন৷ আরও তথ্যের জন্য, পিসিতে গুগল প্লে গেমস দিয়ে শুরু করুন দেখুন।

,

এই দস্তাবেজটি বর্ণনা করে যে কীভাবে পিসিতে Google Play গেমগুলিকে সমর্থন করে এমন গেমগুলিতে ইনপুট SDK সেট আপ এবং প্রদর্শন করতে হয়৷ কাজগুলির মধ্যে রয়েছে আপনার গেমে SDK যোগ করা এবং একটি ইনপুট মানচিত্র তৈরি করা, যাতে গেম-অ্যাকশন-টু-ব্যবহারকারী-ইনপুট অ্যাসাইনমেন্ট থাকে।

আপনি শুরু করার আগে

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

ইনপুট SDK পিসিতে Google Play গেমগুলিকে আপনার গেমটি কী নিয়ন্ত্রণ করে সে সম্পর্কে তথ্য সরবরাহ করে, যাতে সেগুলি ব্যবহারকারীর কাছে প্রদর্শিত হতে পারে৷ এটি ঐচ্ছিকভাবে ব্যবহারকারীদের জন্য কীবোর্ড রিম্যাপিংয়ের অনুমতি দিতে পারে।

প্রতিটি নিয়ন্ত্রণ হল একটি InputAction (যেমন "Jump" এর জন্য) এবং আপনি আপনার InputActions InputGroups এ সংগঠিত করেন। একটি InputGroup আপনার গেমে একটি ভিন্ন মোড উপস্থাপন করতে পারে, যেমন "ড্রাইভিং" বা "হাঁটা" বা "মেন মেনু"। গেমের বিভিন্ন পয়েন্টে কোন গোষ্ঠী সক্রিয় রয়েছে তা নির্দেশ করতে আপনি InputContexts ব্যবহার করতে পারেন।

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

ইনপুট SDK-এর API কীভাবে কাজ করে তা নিম্নলিখিত ক্রম চিত্রটি বর্ণনা করে:

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

যখন আপনার গেম ইনপুট SDK প্রয়োগ করে তখন আপনার নিয়ন্ত্রণগুলি PC ওভারলেতে Google Play গেমগুলিতে প্রদর্শিত হয়৷

পিসি ওভারলেতে গুগল প্লে গেমস

পিসি ওভারলেতে গুগল প্লে গেমস ("ওভারলে") আপনার গেম দ্বারা সংজ্ঞায়িত নিয়ন্ত্রণগুলি প্রদর্শন করে৷ ব্যবহারকারীরা যে কোনো সময় Shift + Tab টিপে ওভারলে অ্যাক্সেস করতে পারেন।

পিসি ওভারলেতে গুগল প্লে গেমস।

কী বাইন্ডিং ডিজাইন করার জন্য সর্বোত্তম অনুশীলন

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

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

রিম্যাপিং বৈশিষ্ট্য

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

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

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

পিসি স্টোরগুলিতে Google Play গেমগুলি প্রতিটি ব্যবহারকারীর জন্য স্থানীয়ভাবে নিয়ন্ত্রণগুলি পুনঃম্যাপ করা হয়েছে, গেমিং সেশন জুড়ে নিয়ন্ত্রণ স্থিরতা সক্ষম করে৷ এই তথ্যটি শুধুমাত্র 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 + রাইট-ক্লিক রিম্যাপ করা যাবে না।

পিসি এমুলেটরে গুগল প্লে গেমসে কী রিম্যাপিং পরীক্ষা করুন

আপনি নিম্নোক্ত adb কমান্ড জারি করে যেকোনো সময় PC এমুলেটরে Google Play Games-এ রিম্যাপিং বৈশিষ্ট্য সক্ষম করতে পারেন:

adb shell dumpsys input_mapping_service --set RemappingFlagValue true

নিম্নলিখিত চিত্রের মতো ওভারলে পরিবর্তন:

কী রিম্যাপিং সহ ওভারলে সক্ষম হয়েছে৷

SDK যোগ করুন

আপনার ডেভেলপমেন্ট প্ল্যাটফর্ম অনুযায়ী ইনপুট SDK ইনস্টল করুন।

জাভা এবং কোটলিন

আপনার মডিউল-স্তরের build.gradle ফাইলে একটি নির্ভরতা যোগ করে Java বা Kotlin-এর জন্য ইনপুট SDK পান:

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

ঐক্য

ইনপুট SDK হল একটি স্ট্যান্ডার্ড ইউনিটি প্যাকেজ যা বিভিন্ন নির্ভরতা সহ।

সমস্ত নির্ভরতা সহ প্যাকেজ ইনস্টল করা প্রয়োজন। প্যাকেজ ইনস্টল করার বিভিন্ন উপায় আছে।

.unitypackage ইন্সটল করুন

ইনপুট SDK ইউনিটিপ্যাকেজ ফাইলটি এর সমস্ত নির্ভরতা সহ ডাউনলোড করুন । আপনি সম্পদ > আমদানি প্যাকেজ > কাস্টম প্যাকেজ নির্বাচন করে এবং আপনার ডাউনলোড করা ফাইলটি সনাক্ত করে .unitypackage ইনস্টল করতে পারেন।

UPM ব্যবহার করে ইনস্টল করুন

বিকল্পভাবে আপনি .tgz ডাউনলোড করে এবং এর নির্ভরতা ইনস্টল করে ইউনিটি প্যাকেজ ম্যানেজার ব্যবহার করে প্যাকেজটি ইনস্টল করতে পারেন:

OpenUPM ব্যবহার করে ইনস্টল করুন

আপনি OpenUPM ব্যবহার করে প্যাকেজটি ইনস্টল করতে পারেন।

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

নমুনা গেম

ইনপুট SDK-এর সাথে কীভাবে একীভূত করা যায় তার উদাহরণগুলির জন্য, কোটলিন বা জাভা গেমগুলির জন্য AGDK টানেল এবং ইউনিটি গেমগুলির জন্য ট্রিভিয়াল কার্ট দেখুন৷

আপনার কী বাইন্ডিং তৈরি করুন

একটি InputMap তৈরি করে এবং একটি InputMappingProvider দিয়ে ফেরত দিয়ে আপনার কী বাইন্ডিংগুলি নিবন্ধন করুন৷ নিম্নলিখিত উদাহরণ একটি InputMappingProvider রূপরেখা দেয়:

কোটলিন

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

সি#

#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 জুড়ে অনন্য ID থাকতে হবে।

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

এই উদাহরণ মানচিত্র স্থান ড্রাইভ কর্মের চাবিকাঠি।

কোটলিন

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

সি#

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

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

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

কোটলিন

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

সি#

private static readonly InputAction mouseInputAction = InputAction.Create(
    "Move",
    (long)InputEventIds.MOUSE_MOVEMENT,
    InputControls.Create(
        new ArrayList<Integer>(),
        new[] { new Integer((int)PlayMouseAction.MouseLeftClick) }.ToJavaList()
    ),
    InputEnums.REMAP_OPTION_DISABLED
);

ওভারলেতে প্রদর্শিত মাউস ইনপুটঅ্যাকশন।

আপনার InputAction এ একাধিক কী কোড পাস করে কী সমন্বয় নির্দিষ্ট করা হয়। এই উদাহরণে স্থান + স্থানান্তর টার্বো অ্যাকশনে ম্যাপ করা হয়, যা তখনও কাজ করে স্থান ড্রাইভে ম্যাপ করা হয়েছে।

কোটলিন

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

সি#

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

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

ইনপুট SDK আপনাকে একটি একক ক্রিয়াকলাপের জন্য মাউস এবং কী বোতামগুলিকে একসাথে মিশ্রিত করতে দেয়৷ এই উদাহরণটি ইঙ্গিত করে শিফট এবং ডান-ক্লিক একসাথে চাপলে এই নমুনা গেমটিতে একটি ওয়েপয়েন্ট যোগ করে:

কোটলিন

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

সি#

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 : একটি কর্মের সাথে যুক্ত কীবোর্ড ইনপুট প্রতিনিধিত্বকারী পূর্ণসংখ্যার একটি তালিকা। এগুলি কী ইভেন্ট ক্লাস বা ইউনিটির জন্য অ্যান্ড্রয়েডকিকোড ক্লাসে সংজ্ঞায়িত করা হয়েছে।
  • MouseActions : এই ক্রিয়াটির সাথে যুক্ত মাউস ইনপুটগুলি উপস্থাপন করে MouseAction মানগুলির একটি তালিকা।

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

InputActions নেভিগেশন উন্নত করতে এবং ওভারলেতে আবিষ্কারযোগ্যতা নিয়ন্ত্রণ করতে InputGroups ব্যবহার করে যৌক্তিকভাবে-সম্পর্কিত ক্রিয়াগুলির সাথে গোষ্ঠীভুক্ত করা হয়। প্রতিটি InputGroup আইডি আপনার গেমের সমস্ত InputGroups জুড়ে অনন্য হওয়া প্রয়োজন৷

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

আপনি যদি রিম্যাপিং সমর্থন করেন তাহলে আপনি সংজ্ঞায়িত করতে পারেন যে InputGroups পুনরায় ম্যাপ করা যেতে পারে। যদি আপনার গেমটি রিম্যাপিং সমর্থন না করে তবে আপনার সমস্ত InputGroups জন্য রিম্যাপিং বিকল্পটি নিষ্ক্রিয় করা উচিত, তবে ইনপুট SDK রিম্যাপিং বন্ধ করার জন্য যথেষ্ট বুদ্ধিমান যদি আপনি এটিকে আপনার InputMap সমর্থন না করেন৷

কোটলিন

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

সি#

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() প্রসঙ্গটি সেট করতে কল করুন। নিম্নলিখিত চিত্রটি এই আচরণটি প্রদর্শন করে: "ড্রাইভিং" দৃশ্যে, রাস্তা নিয়ন্ত্রণের ক্রিয়াগুলি ওভারলেটির শীর্ষে দেখানো হয়। "স্টোর" মেনুটি খোলার সময়, "মেনু নিয়ন্ত্রণগুলি" ক্রিয়াগুলি ওভারলেটির শীর্ষে প্রদর্শিত হয়।

ওভারলেতে ইনপুট কনটেক্সটস বাছাই গ্রুপগুলি।

এই ওভারলে আপডেটগুলি আপনার গেমের বিভিন্ন পয়েন্টে একটি আলাদা InputContext সেট করে অর্জন করা হয়। এটি করতে:

  1. InputGroups ব্যবহার করে যৌক্তিকভাবে সম্পর্কিত ক্রিয়াগুলির সাথে আপনার InputActions গ্রুপ করুন
  2. আপনার গেমের বিভিন্ন অংশের জন্য এই InputGroups একটি InputContext বরাদ্দ করুন

একই InputContext অন্তর্গত InputGroups একই কী ব্যবহৃত হয় যেখানে বিরোধী InputActions থাকতে পারে না। প্রতিটি InputGroup একটি একক InputContext বরাদ্দ করা ভাল অনুশীলন।

নিম্নলিখিত নমুনা কোডটি InputContext লজিক প্রদর্শন করে:

কোটলিন

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

সি#

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 তৈরি করেন।

যদি আপনার গেমটি রিম্যাপিং সমর্থন না করে তবে রিম্যাপিং বিকল্পটি অক্ষম এবং সংরক্ষিত কীগুলি খালি সেট করুন।

নিম্নলিখিত উদাহরণটি InputGroups সংগ্রহের প্রতিবেদন করতে ব্যবহৃত একটি InputMap তৈরি করে।

কোটলিন

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

সি#

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

InputMap নিম্নলিখিত ক্ষেত্রগুলি রয়েছে:

  • InputGroups : আপনার গেম দ্বারা রিপোর্ট করা ইনপুটগ্রুপগুলি। গোষ্ঠীগুলি ওভারলেতে ক্রমে প্রদর্শিত হয়, যদি না বর্তমান গোষ্ঠীগুলি ব্যবহার করে কলিং setInputContext() ব্যবহার করে।
  • MouseSettings : MouseSettings অবজেক্টটি ইঙ্গিত দেয় যে মাউস সংবেদনশীলতা সামঞ্জস্য করা যায় এবং মাউসটি y অক্ষের উপর উল্টানো হয়।
  • InputMapId : InputIdentifier অবজেক্ট যা InputMap নম্বর আইডি এবং সংস্করণ সঞ্চয় করে (আরও তথ্যের জন্য ট্র্যাকিং কী আইডি দেখুন)।
  • InputRemappingOption : InputEnums.REMAP_OPTION_ENABLED মধ্যে একটি InputEnums.REMAP_OPTION_DISABLED রিম্যাপিং বৈশিষ্ট্যটি সক্ষম থাকলে সংজ্ঞায়িত করে।
  • ReservedControls : InputControls একটি তালিকা যা ব্যবহারকারীদের পুনর্নির্মাণের অনুমতি দেওয়া হবে না।

কী আইডি ট্র্যাক করুন

InputAction , InputGroup , InputContext এবং InputMap অবজেক্টগুলিতে একটি InputIdentifier অবজেক্ট থাকে যা একটি অনন্য নম্বর আইডি এবং একটি স্ট্রিং সংস্করণ আইডি সঞ্চয় করে। আপনার অবজেক্টগুলির স্ট্রিং সংস্করণটি ট্র্যাক করা al চ্ছিক তবে আপনার InputMap সংস্করণগুলি ট্র্যাক করার জন্য প্রস্তাবিত। যদি স্ট্রিং সংস্করণ সরবরাহ না করা হয় তবে স্ট্রিংটি খালি। InputMap অবজেক্টগুলির জন্য একটি স্ট্রিং সংস্করণ প্রয়োজন।

নিম্নলিখিত উদাহরণটি InputActions বা InputGroups একটি স্ট্রিং সংস্করণ বরাদ্দ করে:

কোটলিন

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

সি#

#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 ব্যবহার করবেন:

কোটলিন

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;

সি#

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 : ইনপুট ডেটা পরিবর্তনের 2 সংস্করণের মধ্যে ইনপুট ডেটার একটি সংস্করণ সনাক্ত করতে একটি মানব পঠনযোগ্য সংস্করণ স্ট্রিং সেট।

রিম্যাপিং ইভেন্টগুলিতে অবহিত হন (al চ্ছিক)

আপনার গেমটিতে ব্যবহৃত কীগুলি সম্পর্কে অবহিত করার জন্য রিম্যাপ ইভেন্টগুলিতে বিজ্ঞপ্তিগুলি পান। এটি আপনার গেমটিকে অ্যাকশন নিয়ন্ত্রণগুলি প্রদর্শন করতে ব্যবহৃত গেম স্ক্রিনে প্রদর্শিত সম্পদগুলি আপডেট করার অনুমতি দেয়।

নিম্নলিখিত চিত্রটি এই আচরণের একটি উদাহরণ দেখায় যেখানে কীগুলি পুনরায় তৈরি করার পরে জি , পৃ এবং এস থেকে জে , এক্স এবং টি যথাক্রমে, গেমের ইউআই উপাদানগুলি ব্যবহারকারীর দ্বারা সেট করা কীগুলি প্রদর্শন করতে আপডেট হয়।

ইউআই ইনপুটরেম্যাপিংলিস্টনার কলব্যাক ব্যবহার করে ইভেন্টগুলি পুনরায় তৈরি করার প্রতিক্রিয়া জানায়।

এই কার্যকারিতাটি একটি InputRemappingListener কলব্যাক নিবন্ধন করে অর্জন করা হয়। এই ফিউট্রেটি বাস্তবায়নের জন্য, একটি InputRemappingListener উদাহরণ নিবন্ধন করে শুরু করুন:

কোটলিন

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

সি#

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

নিম্নলিখিত নমুনাটি কীভাবে এপিআই আরম্ভ করবেন তা প্রদর্শন করে:

কোটলিন

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

সি#

#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 উদাহরণগুলি নিবন্ধভুক্ত করুন, যদিও ইনপুট এসডিকে আপনি যদি না করেন তবে সংস্থানগুলি ফাঁস এড়াতে যথেষ্ট স্মার্ট:

কোটলিন

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

সি#

public class GameManager : MonoBehaviour
{
    private void OnDestroy()
    {
#if PLAY_GAMES_PC
        _inputMappingClient.ClearInputMappingProvider();
        _inputMappingClient.ClearRemappingListener();
#endif
    }
}

পরীক্ষা

আপনি প্লেয়ারের অভিজ্ঞতা দেখতে ওভারলে খোলার মাধ্যমে বা স্বয়ংক্রিয় পরীক্ষা এবং যাচাইয়ের জন্য এডিবি শেলের মাধ্যমে ম্যানুয়ালি ওভারলে খোলার মাধ্যমে আপনার ইনপুট এসডিকে বাস্তবায়ন পরীক্ষা করতে পারেন।

পিসি এমুলেটরে গুগল প্লে গেমস সাধারণ ত্রুটির বিরুদ্ধে আপনার ইনপুট মানচিত্রের সঠিকতা পরীক্ষা করে। ডুপ্লিকেট অনন্য আইডিগুলির মতো দৃশ্যের জন্য, বিভিন্ন ইনপুট মানচিত্র ব্যবহার করে বা রিম্যাপিং বিধিগুলিতে ব্যর্থ হওয়া (যদি রিম্যাপিং সক্ষম করা থাকে), ওভারলে নীচের মতো একটি ত্রুটি বার্তা দেখায়: ইনপুট এসডিকে ওভারলে।

কমান্ড লাইনে adb ব্যবহার করে আপনার ইনপুট এসডিকে বাস্তবায়ন যাচাই করুন। বর্তমান ইনপুট মানচিত্রটি পেতে, নিম্নলিখিত adb shell কমান্ডটি ব্যবহার করুন (আপনার গেমের নাম সহ MY.PACKAGE.NAME প্রতিস্থাপন করুন):

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

আপনি যদি নিজের InputMap সফলভাবে নিবন্ধভুক্ত করেন তবে আপনি এর মতো আউটপুট দেখতে পাবেন:

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

স্থানীয়করণ

ইনপুট এসডিকে অ্যান্ড্রয়েডের স্থানীয়করণ সিস্টেম ব্যবহার করে না। ফলস্বরূপ, InputMap জমা দেওয়ার সময় আপনাকে অবশ্যই স্থানীয় স্ট্রিং সরবরাহ করতে হবে। আপনি আপনার গেম ইঞ্জিনের স্থানীয়করণ সিস্টেমটিও ব্যবহার করতে পারেন।

প্রোগার্ড

আপনার গেমটি মিনিফাই করার জন্য প্রোগুয়ার্ড ব্যবহার করার সময়, এসডিকে আপনার চূড়ান্ত প্যাকেজ থেকে ছিটকে না যায় তা নিশ্চিত করার জন্য আপনার প্রোগুয়ার্ড কনফিগারেশন ফাইলে নিম্নলিখিত নিয়মগুলি যুক্ত করুন:

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

এরপর কি

আপনি আপনার গেমটিতে ইনপুট এসডিকে সংহত করার পরে, আপনি পিসির প্রয়োজনীয়তায় যে কোনও গুগল প্লে গেমগুলি চালিয়ে যেতে পারেন। আরও তথ্যের জন্য, পিসিতে গুগল প্লে গেমস দিয়ে শুরু করুন দেখুন।