এই বিষয়টিতে আলোচনা করা হয়েছে, কীভাবে পিসিতে গুগল প্লে গেমসের জন্য মাউস ইনপুট প্রয়োগ করতে হয়, বিশেষ করে সেইসব গেমের ক্ষেত্রে যেখানে ইনপুট ট্রান্সলেশন মোড খেলোয়াড়কে আদর্শ অভিজ্ঞতা দেয় না।
পিসি প্লেয়ারদের সাধারণত টাচস্ক্রিনের পরিবর্তে কিবোর্ড এবং মাউস থাকে, তাই আপনার গেমটি মাউস ইনপুট সমর্থন করে কিনা তা বিবেচনা করা গুরুত্বপূর্ণ। ডিফল্টরূপে, পিসিতে গুগল প্লে গেমস যেকোনো লেফট-ক্লিক মাউস ইভেন্টকে একটি একক ভার্চুয়াল ট্যাপ ইভেন্টে রূপান্তরিত করে। এটি 'ইনপুট ট্রান্সলেশন মোড' নামে পরিচিত।
যদিও এই মোডটি সামান্য কিছু পরিবর্তনের মাধ্যমে আপনার গেমটিকে কার্যকরী করে তোলে, এটি পিসি প্লেয়ারদের একটি নেটিভ-অনুভূতির অভিজ্ঞতা প্রদান করে না। সেজন্য, আমরা আপনাকে নিম্নলিখিত বিষয়গুলো বাস্তবায়ন করার পরামর্শ দিচ্ছি:
- প্রেস এবং হোল্ড অ্যাকশনের পরিবর্তে কনটেক্সট মেনুর জন্য হোভার স্টেট।
- লং প্রেস বা কনটেক্সট মেনুতে থাকা বিকল্প কাজগুলোর জন্য রাইট-ক্লিক করুন।
- প্রেস এবং ড্র্যাগ ইভেন্টের পরিবর্তে ফার্স্ট বা থার্ড পার্সন অ্যাকশন গেমের জন্য মাউসলুক।
পিসিতে প্রচলিত UI প্যাটার্নগুলো সমর্থন করার জন্য, আপনাকে ইনপুট ট্রান্সলেশন মোড নিষ্ক্রিয় করতে হবে।
পিসিতে গুগল প্লে গেমসের ইনপুট হ্যান্ডলিং ক্রোমওএস -এর মতোই। পিসির জন্য করা পরিবর্তনগুলো সকল অ্যান্ড্রয়েড প্লেয়ারের জন্য আপনার গেমটিকেও উন্নত করে।
ইনপুট অনুবাদ মোড নিষ্ক্রিয় করুন
আপনার 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 ইভেন্টটি শুনুন। শেষ ফ্রেমের পর থেকে পার্থক্যটি (ডেল্টা) উল্লম্ব অফসেটের জন্য AXIS_VSCROLL এবং অনুভূমিক অফসেটের জন্য AXIS_HSCROLL ব্যবহার করে getAxisValue মাধ্যমে পাওয়া যেতে পারে। উদাহরণস্বরূপ:
কোটলিন
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() কল করুন।