মাউস ইনপুট

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

পিসি প্লেয়ারদের সাধারণত টাচস্ক্রিনের পরিবর্তে কীবোর্ড এবং মাউস থাকে, তাই আপনার গেমটিতে মাউস ইনপুট আছে কিনা তা বিবেচনা করা গুরুত্বপূর্ণ। ডিফল্টরূপে, পিসিতে গুগল প্লে গেমস যেকোনো বাম-ক্লিক মাউস ইভেন্টকে একটি ভার্চুয়াল ট্যাপ ইভেন্টে রূপান্তর করে। এটি "ইনপুট ট্রান্সলেশন মোড" নামে পরিচিত।

যদিও এই মোডটি আপনার গেমটিকে কিছু পরিবর্তনের সাথে কার্যকর করে তোলে, এটি পিসি প্লেয়ারদের স্থানীয় অনুভূতির অভিজ্ঞতা প্রদান করে না। এর জন্য, আমরা আপনাকে নিম্নলিখিতগুলি বাস্তবায়ন করার পরামর্শ দিচ্ছি:

  • অ্যাকশন টিপে ধরে রাখার পরিবর্তে কনটেক্সট মেনুর জন্য হোভার স্টেট ব্যবহার করুন
  • দীর্ঘক্ষণ প্রেস করলে বা প্রসঙ্গ মেনুতে ঘটতে পারে এমন বিকল্প ক্রিয়াগুলির জন্য ডান-ক্লিক করুন।
  • প্রেস এবং ড্র্যাগ ইভেন্টের পরিবর্তে ফার্স্ট বা থার্ড পারসন অ্যাকশন গেমের জন্য মাউসলুক

পিসিতে প্রচলিত UI প্যাটার্নগুলিকে সমর্থন করার জন্য, আপনাকে ইনপুট অনুবাদ মোড অক্ষম করতে হবে।

পিসিতে গুগল প্লে গেমসের ইনপুট হ্যান্ডলিং ChromeOS এর মতোই। পিসিতে যে পরিবর্তনগুলি সাপোর্ট করে তা সমস্ত অ্যান্ড্রয়েড প্লেয়ারের জন্য আপনার গেমটিকে উন্নত করে।

ইনপুট অনুবাদ মোড অক্ষম করুন

আপনার AndroidManifest.xml ফাইলে, android.hardware.type.pc বৈশিষ্ট্যটি ঘোষণা করুন। এটি নির্দেশ করে যে আপনার গেমটি পিসি হার্ডওয়্যার ব্যবহার করে এবং ইনপুট অনুবাদ মোড অক্ষম করে। এছাড়াও, required="false" যোগ করলে নিশ্চিত হতে সাহায্য করে যে আপনার গেমটি এখনও মাউস ছাড়াই ফোন এবং ট্যাবলেটে ইনস্টল করা যেতে পারে। উদাহরণস্বরূপ:

<manifest ...>
  <uses-feature
      android:name="android.hardware.type.pc"
      android:required="false" />
  ...
</manifest>

পিসিতে গুগল প্লে গেমসের প্রোডাকশন ভার্সনটি যখন কোনও গেম চালু হয় তখন সঠিক মোডে চলে যায়। ডেভেলপার এমুলেটরে চালানোর সময়, আপনাকে টাস্ক বার আইকনে ডান-ক্লিক করতে হবে, ডেভেলপার অপশন নির্বাচন করতে হবে এবং তারপর পিসি মোড (কিউইমাউস) নির্বাচন করতে হবে যাতে কাঁচা মাউস ইনপুট পাওয়া যায়।

প্রসঙ্গ মেনুতে নির্বাচিত "পিসি মোড(কিউইমাউস)" এর স্ক্রিনশট

এটি করার পরে, View.onGenericMotionEvent দ্বারা মাউসের নড়াচড়ার রিপোর্ট করা হবে যেখানে SOURCE_MOUSE সোর্সটি নির্দেশ করবে যে এটি একটি মাউস ইভেন্ট।

কোটলিন

gameView.setOnGenericMotionListener { _, motionEvent ->
    var handled = false
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // handle the mouse event here
        handled = true
    }
    handled
}

জাভা

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        // handle the mouse event here
        return true;
    }
    return false;
});

মাউস ইনপুট পরিচালনা সম্পর্কে বিস্তারিত জানার জন্য, ChromeOS ডকুমেন্টেশন দেখুন।

মাউসের নড়াচড়া পরিচালনা করা

মাউসের নড়াচড়া শনাক্ত করতে, ACTION_HOVER_ENTER , ACTION_HOVER_EXIT এবং ACTION_HOVER_MOVE ইভেন্টগুলি শুনুন।

এটি সবচেয়ে ভালোভাবে ব্যবহার করা হয় যখন ব্যবহারকারী গেমের বোতাম বা বস্তুর উপর ঘোরাফেরা করছে তা সনাক্ত করে, যা আপনাকে একটি ইঙ্গিত বাক্স প্রদর্শন করার সুযোগ দেয় অথবা খেলোয়াড় কী নির্বাচন করতে চলেছে তা হাইলাইট করার জন্য একটি মাউসওভার অবস্থা বাস্তবায়নের সুযোগ দেয়। উদাহরণস্বরূপ:

কোটলিন

gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when(motionEvent.action) {
           MotionEvent.ACTION_HOVER_ENTER -> Log.d("MA", "Mouse entered at ${motionEvent.x}, ${motionEvent.y}")
           MotionEvent.ACTION_HOVER_EXIT -> Log.d("MA", "Mouse exited at ${motionEvent.x}, ${motionEvent.y}")
           MotionEvent.ACTION_HOVER_MOVE -> Log.d("MA", "Mouse hovered at ${motionEvent.x}, ${motionEvent.y}")
       }
       handled = true
   }

   handled
}

জাভা

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_HOVER_ENTER:
                Log.d("MA", "Mouse entered at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_HOVER_EXIT:
                Log.d("MA", "Mouse exited at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_HOVER_MOVE:
                Log.d("MA", "Mouse hovered at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
        }
        return true;
    }
    return false;
});

মাউস বোতাম পরিচালনা করা

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

বোতাম টিপে কাজ পরিচালনা করতে, ACTION_DOWN এবং ACTION_UP ব্যবহার করুন। তারপর কোন বোতামটি অ্যাকশনটি ট্রিগার করেছে তা নির্ধারণ করতে getActionButton ব্যবহার করুন অথবা সমস্ত বোতামের অবস্থা জানতে getButtonState করুন।

এই উদাহরণে, getActionButton এর ফলাফল প্রদর্শনে সাহায্য করার জন্য একটি enum ব্যবহার করা হয়েছে:

কোটলিন

enum class MouseButton {
   LEFT,
   RIGHT,
   UNKNOWN;
   companion object {
       fun fromMotionEvent(motionEvent: MotionEvent): MouseButton {
           return when (motionEvent.actionButton) {
               MotionEvent.BUTTON_PRIMARY -> LEFT
               MotionEvent.BUTTON_SECONDARY -> RIGHT
               else -> UNKNOWN
           }
       }
   }
}

জাভা

enum MouseButton {
    LEFT,
    RIGHT,
    MIDDLE,
    UNKNOWN;
    static MouseButton fromMotionEvent(MotionEvent motionEvent) {
        switch (motionEvent.getActionButton()) {
            case MotionEvent.BUTTON_PRIMARY:
                return MouseButton.LEFT;
            case MotionEvent.BUTTON_SECONDARY:
                return MouseButton.RIGHT;
            default:
                return MouseButton.UNKNOWN;
        }
    }
}

এই উদাহরণে, ক্রিয়াটি হোভার ইভেন্টের মতোই পরিচালিত হয়:

কোটলিন

// Handle the generic motion event
gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when (motionEvent.action) {
           MotionEvent.ACTION_BUTTON_PRESS -> Log.d(
               "MA",
               "${MouseButton.fromMotionEvent(motionEvent)} pressed at ${motionEvent.x}, ${motionEvent.y}"
           )
           MotionEvent.ACTION_BUTTON_RELEASE -> Log.d(
               "MA",
               "${MouseButton.fromMotionEvent(motionEvent)} released at ${motionEvent.x}, ${motionEvent.y}"
           )
       }
       handled = true
   }

   handled
}

জাভা

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_BUTTON_PRESS:
                Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " pressed at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
            case MotionEvent.ACTION_BUTTON_RELEASE:
                Log.d("MA", MouseButton.fromMotionEvent(motionEvent) + " released at " + motionEvent.getX() + ", " + motionEvent.getY());
                break;
        }
        return true;
    }
    return false;
});

মাউসহুইল স্ক্রোলিং পরিচালনা করুন

আমরা সুপারিশ করছি যে আপনি আপনার গেমের জেসচার জুম করতে বা স্ক্রোল এরিয়া স্পর্শ করে টেনে আনতে পিঞ্চের পরিবর্তে মাউস স্ক্রোল হুইল ব্যবহার করুন।

স্ক্রোল হুইল ভ্যালু পড়তে, ACTION_SCROLL ইভেন্টটি শুনুন। শেষ ফ্রেমের ডেল্টাটি getAxisValue ব্যবহার করে উল্লম্ব অফসেটের জন্য AXIS_VSCROLL এবং অনুভূমিক অফসেটের জন্য AXIS_HSCROLL ব্যবহার করে পুনরুদ্ধার করা যেতে পারে। উদাহরণস্বরূপ:

কোটলিন

gameView.setOnGenericMotionListener { _, motionEvent ->
   var handled = false
   if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
       when (motionEvent.action) {
           MotionEvent.ACTION_SCROLL -> {
               val scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL)
               val scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL)
               Log.d("MA", "Mouse scrolled $scrollX, $scrollY")
           }
       }
       handled = true
   }
   handled
}

জাভা

gameView.setOnGenericMotionListener((view, motionEvent) -> {
    if (motionEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_SCROLL:
                float scrollX = motionEvent.getAxisValue(MotionEvent.AXIS_HSCROLL);
                float scrollY = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL);
                Log.d("MA", "Mouse scrolled " + scrollX + ", " + scrollY);
                break;
        }
        return true;
    }
    return false;
});

মাউস ইনপুট ক্যাপচার করুন

কিছু গেমের জন্য মাউস কার্সারের সম্পূর্ণ নিয়ন্ত্রণ নিতে হয়, যেমন ফার্স্ট বা থার্ড পারসন অ্যাকশন গেম যা মাউসের গতিবিধিকে ক্যামেরার গতিবিধির সাথে ম্যাপ করে। মাউসের একচেটিয়া নিয়ন্ত্রণ নিতে, View.requestPointerCapture() ব্যবহার করুন।

requestPointerCapture() শুধুমাত্র তখনই কাজ করে যখন আপনার ভিউ ধারণকারী ভিউ হায়ারার্কিতে ফোকাস থাকে। এই কারণে, আপনি onCreate কলব্যাকে পয়েন্টার ক্যাপচার অর্জন করতে পারবেন না। আপনার হয় প্লেয়ার ইন্টারঅ্যাকশনের জন্য অপেক্ষা করা উচিত যাতে মাউস পয়েন্টার ক্যাপচার হয়, যেমন প্রধান মেনুর সাথে ইন্টারঅ্যাক্ট করার সময়, অথবা onWindowFocusChanged কলব্যাক ব্যবহার করা উচিত। উদাহরণস্বরূপ:

কোটলিন

override fun onWindowFocusChanged(hasFocus: Boolean) {
   super.onWindowFocusChanged(hasFocus)

   if (hasFocus) {
       gameView.requestPointerCapture()
   }
}

জাভা

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    if (hasFocus) {
        View gameView = findViewById(R.id.game_view);
        gameView.requestPointerCapture();
    }
}

requestPointerCapture() দ্বারা ক্যাপচার করা ইভেন্টগুলি OnCapturedPointerListener নিবন্ধিত ফোকাসেবল ভিউতে প্রেরণ করা হয়। উদাহরণস্বরূপ:

কোটলিন

gameView.focusable = View.FOCUSABLE
gameView.setOnCapturedPointerListener { _, motionEvent ->
    Log.d("MA", "${motionEvent.x}, ${motionEvent.y}, ${motionEvent.actionButton}")
    true
}

জাভা

gameView.setFocusable(true);
gameView.setOnCapturedPointerListener((view, motionEvent) -> {
    Log.d("MA", motionEvent.getX() + ", " + motionEvent.getY() + ", " + motionEvent.getActionButton());
    return true;
});

এক্সক্লুসিভ মাউস ক্যাপচার রিলিজ করার জন্য, যেমন প্লেয়ারদের একটি পজ মেনুর সাথে ইন্টারঅ্যাক্ট করার অনুমতি দেওয়ার জন্য, View.releasePointerCapture() ব্যবহার করুন।