कंट्रोलर में दो तरह की कार्रवाइयां होती हैं:
KeyEventइसका इस्तेमाल "चालू" और "बंद" की बाइनरी स्थिति वाले किसी भी बटन के लिए किया जाता हैMotionEventइसका इस्तेमाल ऐसे किसी भी ऐक्सिस के लिए किया जाता है जो वैल्यू की रेंज दिखाता है. जैसे, एनालॉग स्टिक के लिए -1 से 1 या एनालॉग ट्रिगर के लिए 0 से 1.
इन इनपुट को View से पढ़ा जा सकता है. इसके लिए, focus होना ज़रूरी है.
onGenericMotionEventको किसीMotionEventके लिए बढ़ाया गया हो.बटन दबाने और छोड़ने पर,
KeyEventके लिएonKeyDownऔरonKeyUpबढ़ जाते हैं.
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.isFromSource(SOURCE_GAMEPAD)
&& event.repeatCount == 0
) {
Log.d("GameView", "Gamepad key pressed: $keyCode")
return true
}
return super.onKeyDown(keyCode, event)
}
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
if (event.isFromSource(SOURCE_JOYSTICK)) {
Log.d("GameView", "Gamepad event: $event")
return true
}
return super.onGenericMotionEvent(event)
}
Java
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.isFromSource(SOURCE_GAMEPAD)
&& event.getRepeatCount() == 0
) {
Log.d("GameView", "Gamepad key pressed: " + keyCode);
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (event.isFromSource(SOURCE_JOYSTICK)) {
Log.d("GameView", "Gamepad event: " + event);
return true;
}
return super.onGenericMotionEvent(event);
}
अगर ज़रूरत हो, तो सीधे Activity से इवेंट पढ़े जा सकते हैं.
dispatchGenericMotionEventको किसी भीMotionEventके लिए बढ़ाया गया होdispatchKeyEvent. को किसी भीKeyEventके लिए बढ़ाया जाता है.
पुष्टि करें कि गेम कंट्रोलर कनेक्ट किया गया हो
इनपुट इवेंट की रिपोर्टिंग करते समय, Android अलग-अलग तरह के इनपुट डिवाइसों के लिए एक ही कुंजी या ऐक्सिस आईडी का फिर से इस्तेमाल करेगा. उदाहरण के लिए, टचस्क्रीन पर की गई कार्रवाई से AXIS_X इवेंट जनरेट होता है. यह इवेंट, टचस्क्रीन के X कोऑर्डिनेट को दिखाता है. वहीं, गेमपैड से AXIS_X इवेंट जनरेट होता है. यह इवेंट, बाईं स्टिक की X पोज़िशन को दिखाता है. इसका मतलब है कि आपको इनपुट इवेंट को सही तरीके से समझने के लिए, सोर्स टाइप की जांच करनी होगी.
यह पुष्टि करने के लिए कि कनेक्ट किया गया InputDevice एक गेम कंट्रोलर है, supportsSource(int) फ़ंक्शन का इस्तेमाल करें:
SOURCE_GAMEPADसोर्स टाइप से पता चलता है कि इनपुट डिवाइस में कंट्रोलर बटन हैं. उदाहरण के लिए,KEYCODE_BUTTON_A. ध्यान दें कि इस सोर्स टाइप से यह पता नहीं चलता कि गेम कंट्रोलर में डी-पैड बटन हैं या नहीं. हालांकि, ज़्यादातर कंट्रोलर में आम तौर पर दिशा बदलने वाले कंट्रोल होते हैं.SOURCE_DPADटाइप का सोर्स, यह दिखाता है कि इनपुट डिवाइस में डी-पैड बटन हैं. उदाहरण के लिए,DPAD_UP.SOURCE_JOYSTICKसोर्स टाइप से पता चलता है कि इनपुट डिवाइस में ऐनलॉग कंट्रोल स्टिक हैं. उदाहरण के लिए, एक ऐसा जॉयस्टिक जोAXIS_XऔरAXIS_Yके साथ-साथ गतिविधियों को रिकॉर्ड करता है.
यहां दिए गए कोड स्निपेट में, एक हेल्पर तरीका दिखाया गया है. इसकी मदद से, यह पता लगाया जा सकता है कि कनेक्ट किए गए इनपुट डिवाइस, गेम कंट्रोलर हैं या नहीं. अगर ऐसा है, तो यह तरीका गेम कंट्रोलर के डिवाइस आईडी वापस पाता है. इसके बाद, हर डिवाइस आईडी को अपने गेम में किसी खिलाड़ी से जोड़ा जा सकता है. साथ ही, कनेक्ट किए गए हर खिलाड़ी के लिए, गेम से जुड़ी कार्रवाइयों को अलग-अलग तरीके से प्रोसेस किया जा सकता है. एक ही Android डिवाइस पर एक साथ कनेक्ट किए गए कई गेम कंट्रोलर के साथ काम करने के बारे में ज़्यादा जानने के लिए, कई गेम कंट्रोलर के साथ काम करना लेख पढ़ें.
Kotlin
fun getGameControllerIds(): List<Int> {
val gameControllerDeviceIds = mutableListOf<Int>()
val deviceIds = InputDevice.getDeviceIds()
deviceIds.forEach { deviceId ->
InputDevice.getDevice(deviceId)?.apply {
// Verify that the device has gamepad buttons, control sticks, or both.
if (supportsSource(SOURCE_GAMEPAD)
|| supportsSource(SOURCE_JOYSTICK)) {
// This device is a game controller. Store its device ID.
gameControllerDeviceIds
.takeIf { !it.contains(deviceId) }
?.add(deviceId)
}
}
}
return gameControllerDeviceIds
}
Java
public ArrayList<Integer> getGameControllerIds() {
ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>();
int[] deviceIds = InputDevice.getDeviceIds();
for (int deviceId : deviceIds) {
InputDevice dev = InputDevice.getDevice(deviceId);
if (dev == null) {
continue;
}
// Verify that the device has gamepad buttons, control sticks, or both.
if (dev.supportsSource(SOURCE_GAMEPAD) || dev.supportsSource(SOURCE_JOYSTICK)) {
// This device is a game controller. Store its device ID.
if (!gameControllerDeviceIds.contains(deviceId)) {
gameControllerDeviceIds.add(deviceId);
}
}
}
return gameControllerDeviceIds;
}
प्रोसेस कंट्रोलर के इनपुट
इस सेक्शन में, Android पर काम करने वाले गेम कंट्रोलर के टाइप के बारे में बताया गया है.
C++ डेवलपर को गेम कंट्रोलर लाइब्रेरी का इस्तेमाल करना चाहिए. यह सभी कंट्रोलर को सुविधाओं के सबसे सामान्य सबसेट के साथ जोड़ता है. साथ ही, उनके बीच एक जैसा इंटरफ़ेस उपलब्ध कराता है. इसमें बटन लेआउट का पता लगाने की सुविधा भी शामिल है.
इस इमेज में दिखाया गया है कि Android गेम डेवलपर को Android पर सामान्य कंट्रोलर कैसा दिखेगा.
इस टेबल में, गेम कंट्रोलर के लिए स्टैंडर्ड इवेंट के नाम और टाइप दिए गए हैं. इवेंट की पूरी सूची के लिए, सामान्य वैरिएंट देखें. सिस्टम, MotionEvent इवेंट को onGenericMotionEvent और KeyEvent इवेंट को onKeyDown और onKeyUp के ज़रिए भेजता है.
| कंट्रोलर इनपुट | KeyEvent | MotionEvent |
|---|---|---|
| 1. डी-पैड |
AXIS_HAT_X(हॉरिज़ॉन्टल इनपुट) AXIS_HAT_Y(वर्टिकल इनपुट) |
|
| 2. लेफ़्ट ऐनालॉग स्टिक |
KEYCODE_BUTTON_THUMBL(दबाने पर) |
AXIS_X(हॉरिजॉन्टल मूवमेंट) AXIS_Y(वर्टिकल मूवमेंट) |
| 3. राइट ऐनालॉग स्टिक |
KEYCODE_BUTTON_THUMBR(दबाने पर) |
AXIS_Z(हॉरिजॉन्टल मूवमेंट) AXIS_RZ(वर्टिकल मूवमेंट) |
| 4. X बटन | KEYCODE_BUTTON_X |
|
| 5. A बटन | KEYCODE_BUTTON_A |
|
| 6. Y बटन | KEYCODE_BUTTON_Y |
|
| 7. B बटन | KEYCODE_BUTTON_B |
|
| 8. राइट बंपर |
KEYCODE_BUTTON_R1 |
|
| 9. राइट ट्रिगर |
AXIS_RTRIGGER |
|
| 10. लेफ़्ट ट्रिगर | AXIS_LTRIGGER |
|
| 11. लेफ़्ट बंपर | KEYCODE_BUTTON_L1 |
|
| 12. शुरू करें | KEYCODE_BUTTON_START |
|
| 13. चुनें | KEYCODE_BUTTON_SELECT |
बटन दबाने की कार्रवाइयों को मैनेज करना
Android, कंट्रोलर बटन दबाने की जानकारी को कीबोर्ड बटन दबाने की जानकारी के तौर पर रिपोर्ट करता है. इसलिए, आपको ये काम करने होंगे:
- पुष्टि करें कि इवेंट,
SOURCE_GAMEPADसे आ रहा है. - पक्का करें कि आपको बटन सिर्फ़ एक बार मिले. ऐसा न होने पर, Android, कीबोर्ड के किसी बटन को दबाकर रखने पर होने वाले इवेंट की तरह ही, मुख्य इवेंट को बार-बार भेजेगा.
KeyEvent.getRepeatCount() trueको वापस भेजकर यह बताएं कि इवेंट को हैंडल किया गया है.जिन इवेंट को हैंडल नहीं किया गया है उन्हें
superपर पास करें, ताकि यह पुष्टि की जा सके कि Android की अलग-अलग कंपैटिबिलिटी लेयर सही तरीके से काम कर रही हैं.Kotlin
class GameView : View { // ... override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { event.apply { var handled = false // make sure we're handling gamepad events if (isFromSource(SOURCE_GAMEPAD)) { // avoid processing the keycode repeatedly if (repeatCount == 0) { when (keyCode) { // handle the "A" button KEYCODE_BUTTON_A -> { handled = true } } // ... } } if (handled) { return true } } return super.onKeyDown(keyCode, event) } }Java
public class GameView extends View { // ... @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; // make sure we're handling gamepad events if (event.isFromSource(SOURCE_GAMEPAD)) { // avoid processing the keycode repeatedly if (event.getRepeatCount() == 0) { switch (keyCode) { case KEYCODE_BUTTON_A: // handle the "A" button handled = true; break; // ... } } // mark this event as handled if (handled) { return true; } } // Always do this instead of "return false" // it allows Android's input compatibility layers to work return super.onKeyDown(keyCode, event); } }
डायरेक्शनल पैड के इनपुट को प्रोसेस करना
चार दिशाओं वाला डी-पैड, कई गेम कंट्रोलर में मौजूद एक सामान्य बटन है. Android, डी-पैड के ऊपर और नीचे के बटन दबाने को AXIS_HAT_Y इवेंट के तौर पर रिपोर्ट करता है. इसमें -1.0 का मतलब ऊपर और 1.0 का मतलब नीचे होता है. यह डी-पैड पर LEFT या RIGHT बटन दबाने की जानकारी को AXIS_HAT_X इवेंट के तौर पर रिपोर्ट करता है. इसमें -1.0 का मतलब बाईं ओर और 1.0 का मतलब दाईं ओर होता है.
कुछ कंट्रोलर, डी-पैड को दबाने की जानकारी, कुंजी कोड के साथ देते हैं. अगर आपके गेम में डी-पैड बटन दबाने की सुविधा है, तो आपको हैट ऐक्सिस इवेंट और डी-पैड के की कोड को एक ही इनपुट इवेंट के तौर पर मानना चाहिए. इसके बारे में टेबल 2 में बताया गया है.
टेबल 2. डी-पैड के बटन के कोड और हैट ऐक्सिस की वैल्यू के लिए, गेम की डिफ़ॉल्ट कार्रवाइयां सुझाई गई हैं.
| गेम ऐक्शन | डी-पैड का कुंजी कोड | हैट ऐक्सिस कोड |
|---|---|---|
| ऊपर ले जाएं | KEYCODE_DPAD_UP |
AXIS_HAT_Y (वैल्यू 0 से -1.0 के लिए) |
| नीचे ले जाएं | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (0 से 1.0 तक की वैल्यू के लिए) |
| बाईं ओर ले जाएं | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (वैल्यू 0 से -1.0 के लिए) |
| दाईं ओर ले जाएं | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (0 से 1.0 तक की वैल्यू के लिए) |
यहां दिए गए कोड स्निपेट में, एक हेल्पर क्लास दिखाई गई है. इसकी मदद से, इनपुट इवेंट से हैट ऐक्सिस और कुंजी कोड की वैल्यू की जांच की जा सकती है. इससे डी-पैड की दिशा का पता चलता है.
Kotlin
class Dpad {
private var directionPressed = -1 // initialized to -1
fun getDirectionPressed(event: InputEvent): Int {
if (!isDpadDevice(event)) {
return -1
}
// If the input event is a MotionEvent, check its hat axis values.
(event as? MotionEvent)?.apply {
// Use the hat axis value to find the D-pad direction
val xaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_X)
val yaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_Y)
directionPressed = when {
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
// LEFT and RIGHT direction accordingly.
xaxis.compareTo(-1.0f) == 0 -> Dpad.LEFT
xaxis.compareTo(1.0f) == 0 -> Dpad.RIGHT
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
// UP and DOWN direction accordingly.
yaxis.compareTo(-1.0f) == 0 -> Dpad.UP
yaxis.compareTo(1.0f) == 0 -> Dpad.DOWN
else -> directionPressed
}
}
// If the input event is a KeyEvent, check its key code.
(event as? KeyEvent)?.apply {
// Use the key code to find the D-pad direction.
directionPressed = when(event.keyCode) {
KeyEvent.KEYCODE_DPAD_LEFT -> Dpad.LEFT
KeyEvent.KEYCODE_DPAD_RIGHT -> Dpad.RIGHT
KeyEvent.KEYCODE_DPAD_UP -> Dpad.UP
KeyEvent.KEYCODE_DPAD_DOWN -> Dpad.DOWN
KeyEvent.KEYCODE_DPAD_CENTER -> Dpad.CENTER
else -> directionPressed
}
}
return directionPressed
}
companion object {
internal const val UP = 0
internal const val LEFT = 1
internal const val RIGHT = 2
internal const val DOWN = 3
internal const val CENTER = 4
fun isDpadDevice(event: InputEvent): Boolean =
// Check that input comes from a device with directional pads.
return event.isFromSource(InputDevice.SOURCE_DPAD)
}
}
Java
public class Dpad {
final static int UP = 0;
final static int LEFT = 1;
final static int RIGHT = 2;
final static int DOWN = 3;
final static int CENTER = 4;
int directionPressed = -1; // initialized to -1
public int getDirectionPressed(InputEvent event) {
if (!isDpadDevice(event)) {
return -1;
}
// If the input event is a MotionEvent, check its hat axis values.
if (event instanceof MotionEvent) {
// Use the hat axis value to find the D-pad direction
MotionEvent motionEvent = (MotionEvent) event;
float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
// LEFT and RIGHT direction accordingly.
if (Float.compare(xaxis, -1.0f) == 0) {
directionPressed = Dpad.LEFT;
} else if (Float.compare(xaxis, 1.0f) == 0) {
directionPressed = Dpad.RIGHT;
}
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
// UP and DOWN direction accordingly.
else if (Float.compare(yaxis, -1.0f) == 0) {
directionPressed = Dpad.UP;
} else if (Float.compare(yaxis, 1.0f) == 0) {
directionPressed = Dpad.DOWN;
}
}
// If the input event is a KeyEvent, check its key code.
else if (event instanceof KeyEvent) {
// Use the key code to find the D-pad direction.
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
directionPressed = Dpad.LEFT;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
directionPressed = Dpad.RIGHT;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
directionPressed = Dpad.UP;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
directionPressed = Dpad.DOWN;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
directionPressed = Dpad.CENTER;
}
}
return directionPressed;
}
public static boolean isDpadDevice(InputEvent event) {
// Check that input comes from a device with directional pads.
return event.isFromSource(InputDevice.SOURCE_DPAD);
}
}
इस हेल्पर क्लास का इस्तेमाल अपने गेम में कहीं भी किया जा सकता है. इससे डी-पैड के इनपुट को प्रोसेस किया जा सकता है. उदाहरण के लिए, onGenericMotionEvent() या onKeyDown() कॉलबैक में.
उदाहरण के लिए:
Kotlin
private val dpad = Dpad()
...
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
if (Dpad.isDpadDevice(event)) {
when (dpad.getDirectionPressed(event)) {
Dpad.LEFT -> {
// Do something for LEFT direction press
...
return true
}
Dpad.RIGHT -> {
// Do something for RIGHT direction press
...
return true
}
Dpad.UP -> {
// Do something for UP direction press
...
return true
}
...
}
}
// Check if this event is from a joystick movement and process accordingly.
...
}
Java
Dpad dpad = new Dpad();
...
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
// Check if this event if from a D-pad and process accordingly.
if (Dpad.isDpadDevice(event)) {
int press = dpad.getDirectionPressed(event);
switch (press) {
case LEFT:
// Do something for LEFT direction press
...
return true;
case RIGHT:
// Do something for RIGHT direction press
...
return true;
case UP:
// Do something for UP direction press
...
return true;
...
}
}
// Check if this event is from a joystick movement and process accordingly.
...
}
जॉयस्टिक की गतिविधियों को प्रोसेस करना
जब गेम खेलने वाले लोग, गेम कंट्रोलर पर जॉयस्टिक को घुमाते हैं, तो Android एक MotionEvent रिपोर्ट करता है. इसमें ACTION_MOVE ऐक्शन कोड और जॉयस्टिक के ऐक्सिस की अपडेट की गई पोज़िशन शामिल होती हैं. आपका गेम, MotionEvent से मिले डेटा का इस्तेमाल करके यह पता लगा सकता है कि जॉयस्टिक को हिलाया गया है या नहीं.
ध्यान दें कि जॉयस्टिक के मोशन इवेंट, एक ही ऑब्जेक्ट में कई मूवमेंट सैंपल को एक साथ बैच कर सकते हैं. MotionEvent ऑब्जेक्ट में, हर जॉयस्टिक ऐक्सिस की मौजूदा पोज़िशन के साथ-साथ हर ऐक्सिस की कई पुरानी पोज़िशन भी शामिल होती हैं. जब ऐक्शन कोड ACTION_MOVE (जैसे कि जॉयस्टिक की गतिविधियों) के साथ मोशन इवेंट रिपोर्ट किए जाते हैं, तो Android, ऐक्सिस की वैल्यू को एक साथ प्रोसेस करता है, ताकि बेहतर तरीके से काम किया जा सके. किसी ऐक्सिस की पुरानी वैल्यू में, मौजूदा ऐक्सिस वैल्यू से पुरानी और मोशन से जुड़े किसी भी पिछले इवेंट में रिपोर्ट की गई वैल्यू से नई वैल्यू का सेट शामिल होता है. ज़्यादा जानकारी के लिए, MotionEvent
रेफ़रंस देखें.
जॉयस्टिक के इनपुट के आधार पर, गेम ऑब्जेक्ट की गतिविधि को सटीक तरीके से रेंडर करने के लिए, MotionEvent ऑब्जेक्ट से मिली पुरानी जानकारी का इस्तेमाल किया जा सकता है.
इन तरीकों का इस्तेमाल करके, मौजूदा और पुरानी वैल्यू वापस पाई जा सकती हैं:
getAxisValue()getHistoricalAxisValue()getHistorySize()(जॉयस्टिक इवेंट में ऐतिहासिक पॉइंट की संख्या ढूंढने के लिए)
नीचे दिए गए स्निपेट में, जॉयस्टिक इनपुट को प्रोसेस करने के लिए onGenericMotionEvent() कॉलबैक को बदलने का तरीका बताया गया है. आपको सबसे पहले किसी ऐक्सिस के लिए पुरानी वैल्यू प्रोसेस करनी चाहिए. इसके बाद, उसकी मौजूदा पोज़िशन प्रोसेस करनी चाहिए.
Kotlin
class GameView(...) : View(...) {
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
// Check that the event came from a game controller
return if (event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK
&& event.action == MotionEvent.ACTION_MOVE) {
// Process the movements starting from the
// earliest historical position in the batch
(0 until event.historySize).forEach { i ->
// Process the event at historical position i
processJoystickInput(event, i)
}
// Process the current movement sample in the batch (position -1)
processJoystickInput(event, -1)
true
} else {
super.onGenericMotionEvent(event)
}
}
}
Java
public class GameView extends View {
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
// Check that the event came from a game controller
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) ==
InputDevice.SOURCE_JOYSTICK &&
event.getAction() == MotionEvent.ACTION_MOVE) {
// Process all historical movement samples in the batch
final int historySize = event.getHistorySize();
// Process the movements starting from the
// earliest historical position in the batch
for (int i = 0; i < historySize; i++) {
// Process the event at historical position i
processJoystickInput(event, i);
}
// Process the current movement sample in the batch (position -1)
processJoystickInput(event, -1);
return true;
}
return super.onGenericMotionEvent(event);
}
}
जॉयस्टिक इनपुट का इस्तेमाल करने से पहले, आपको यह तय करना होगा कि जॉयस्टिक बीच में है या नहीं. इसके बाद, उसके ऐक्सिस के हिसाब से मूवमेंट का हिसाब लगाएं. जॉयस्टिक में आम तौर पर एक फ़्लैट एरिया होता है. इसका मतलब है कि (0,0) कोऑर्डिनेट के आस-पास की वैल्यू की एक रेंज होती है, जिस पर ऐक्सिस को सेंटर में माना जाता है. अगर Android से रिपोर्ट की गई ऐक्सिस वैल्यू, फ़्लैट एरिया में आती है, तो आपको कंट्रोलर को स्थिर मानना चाहिए. इसका मतलब है कि दोनों ऐक्सिस पर कोई हलचल नहीं हो रही है.
इस स्निपेट में, एक हेल्पर मेथड दिखाया गया है. यह हर ऐक्सिस के हिसाब से मूवमेंट का हिसाब लगाता है. इस हेल्पर को processJoystickInput() तरीके से लागू किया जाता है. इस बारे में यहां दिए गए सैंपल में बताया गया है:
Kotlin
private fun getCenteredAxis(
event: MotionEvent,
device: InputDevice,
axis: Int,
historyPos: Int
): Float {
val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source)
// A joystick at rest does not always report an absolute position of
// (0,0). Use the getFlat() method to determine the range of values
// bounding the joystick axis center.
range?.apply {
val value: Float = if (historyPos < 0) {
event.getAxisValue(axis)
} else {
event.getHistoricalAxisValue(axis, historyPos)
}
// Ignore axis values that are within the 'flat' region of the
// joystick axis center.
if (Math.abs(value) > flat) {
return value
}
}
return 0f
}
Java
private static float getCenteredAxis(MotionEvent event,
InputDevice device, int axis, int historyPos) {
final InputDevice.MotionRange range =
device.getMotionRange(axis, event.getSource());
// A joystick at rest does not always report an absolute position of
// (0,0). Use the getFlat() method to determine the range of values
// bounding the joystick axis center.
if (range != null) {
final float flat = range.getFlat();
final float value =
historyPos < 0 ? event.getAxisValue(axis):
event.getHistoricalAxisValue(axis, historyPos);
// Ignore axis values that are within the 'flat' region of the
// joystick axis center.
if (Math.abs(value) > flat) {
return value;
}
}
return 0;
}
इन सभी को एक साथ इस्तेमाल करके, यहां बताया गया है कि अपने गेम में जॉयस्टिक की गतिविधियों को कैसे प्रोसेस किया जा सकता है:
Kotlin
private fun processJoystickInput(event: MotionEvent, historyPos: Int) {
val inputDevice = event.device
// Calculate the horizontal distance to move by
// using the input value from one of these physical controls:
// the left control stick, hat axis, or the right control stick.
var x: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos)
if (x == 0f) {
x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos)
}
if (x == 0f) {
x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos)
}
// Calculate the vertical distance to move by
// using the input value from one of these physical controls:
// the left control stick, hat switch, or the right control stick.
var y: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos)
if (y == 0f) {
y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos)
}
if (y == 0f) {
y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos)
}
// Update the ship object based on the new x and y values
}
Java
private void processJoystickInput(MotionEvent event,
int historyPos) {
InputDevice inputDevice = event.getDevice();
// Calculate the horizontal distance to move by
// using the input value from one of these physical controls:
// the left control stick, hat axis, or the right control stick.
float x = getCenteredAxis(event, inputDevice,
MotionEvent.AXIS_X, historyPos);
if (x == 0) {
x = getCenteredAxis(event, inputDevice,
MotionEvent.AXIS_HAT_X, historyPos);
}
if (x == 0) {
x = getCenteredAxis(event, inputDevice,
MotionEvent.AXIS_Z, historyPos);
}
// Calculate the vertical distance to move by
// using the input value from one of these physical controls:
// the left control stick, hat switch, or the right control stick.
float y = getCenteredAxis(event, inputDevice,
MotionEvent.AXIS_Y, historyPos);
if (y == 0) {
y = getCenteredAxis(event, inputDevice,
MotionEvent.AXIS_HAT_Y, historyPos);
}
if (y == 0) {
y = getCenteredAxis(event, inputDevice,
MotionEvent.AXIS_RZ, historyPos);
}
// Update the ship object based on the new x and y values
}
एक जॉयस्टिक के अलावा, ज़्यादा बेहतर सुविधाओं वाले गेम कंट्रोलर के साथ काम करने के लिए, इन सबसे सही तरीकों को अपनाएं:
- दोनों कंट्रोलर स्टिक को हैंडल करें. कई गेम कंट्रोलर में, बाईं और दाईं, दोनों जॉयस्टिक होती हैं. लेफ़्ट स्टिक के लिए, Android हॉरिज़ॉन्टल मूवमेंट को
AXIS_Xइवेंट और वर्टिकल मूवमेंट कोAXIS_Yइवेंट के तौर पर रिपोर्ट करता है. राइट स्टिक के लिए, Android हॉरिज़ॉन्टल मूवमेंट कोAXIS_Zइवेंट और वर्टिकल मूवमेंट कोAXIS_RZइवेंट के तौर पर रिपोर्ट करता है. पक्का करें कि आपने अपने कोड में दोनों कंट्रोलर स्टिक को हैंडल किया हो. - कंधे के ट्रिगर दबाने की सुविधा को मैनेज करें. साथ ही, पक्का करें कि आपका गेम
AXIS_औरKEYCODE_BUTTON_इवेंट के साथ काम करता हो. कुछ कंट्रोलर में बाएं और दाएं कंधे के ट्रिगर होते हैं. ये ट्रिगर मौजूद होने पर,AXIS_*TRIGGERयाKEYCODE_BUTTON_*2इवेंट या दोनों इवेंट ट्रिगर होते हैं. लेफ़्ट ट्रिगर के लिए, यहAXIS_LTRIGGERऔरKEYCODE_BUTTON_L2होगा. राइट ट्रिगर के लिए, यहAXIS_RTRIGGERऔरKEYCODE_BUTTON_R2होगा. ऐक्सिस इवेंट सिर्फ़ तब होते हैं, जब ट्रिगर 0 से 1 के बीच की वैल्यू की रेंज दिखाता है. साथ ही, ऐनलॉग आउटपुट वाले कुछ कंट्रोलर, ऐक्सिस इवेंट के अलावा बटन इवेंट भी दिखाते हैं. सभी सामान्य गेम कंट्रोलर के साथ काम करने के लिए, गेम मेंAXIS_औरKEYCODE_BUTTON_, दोनों इवेंट काम करने चाहिए. हालांकि, अगर कोई कंट्रोलर दोनों इवेंट रिपोर्ट करता है, तो गेमप्ले के लिए सबसे सही इवेंट को प्राथमिकता दें. Android 4.3 (एपीआई लेवल 18) और इसके बाद के वर्शन में,AXIS_LTRIGGERजनरेट करने वाला कंट्रोलर,AXIS_BRAKEऐक्सिस के लिए भी एक जैसी वैल्यू रिपोर्ट करता है.AXIS_RTRIGGERऔरAXIS_GASके लिए भी यही नियम लागू होता है. Android, ऐनलॉग ट्रिगर को दबाने की सभी कार्रवाइयों को रिपोर्ट करता है. इसके लिए, वह 0.0 (रिलीज़ किया गया) से लेकर 1.0 (पूरी तरह से दबाया गया) तक की सामान्य वैल्यू का इस्तेमाल करता है. - इमुलेट किए गए एनवायरमेंट में, कुछ खास व्यवहार और सहायता अलग-अलग हो सकती है.
इमुलेट किए गए प्लैटफ़ॉर्म, जैसे कि Google Play Games, होस्ट ऑपरेटिंग सिस्टम की क्षमताओं के आधार पर थोड़े अलग तरीके से काम कर सकते हैं. उदाहरण के लिए,
AXIS_औरKEYCODE_BUTTON_, दोनों इवेंट भेजने वाले कुछ कंट्रोलर सिर्फ़AXIS_इवेंट भेजते हैं. साथ ही, हो सकता है कि कुछ कंट्रोलर के लिए सहायता उपलब्ध न हो.
सामान्य वैरिएंट
Android में कंट्रोलर के लिए कई तरह की सुविधाएं उपलब्ध हैं. इसलिए, यह समझना मुश्किल हो सकता है कि अपने गेम को बिना किसी गड़बड़ी के चलाने के लिए, उसे कैसे बनाया और टेस्ट किया जाए. हमें पता चला है कि दुनिया भर में कंट्रोलर बनाने वाली कंपनियां, कंट्रोलर के तीन अलग-अलग स्टाइल का इस्तेमाल करती हैं. कुछ में, इन दोनों के बीच हार्डवेयर टॉगल करने की सुविधा होती है.
इसका मतलब है कि डेवलपर टीम के तीन कंट्रोलर के साथ भी टेस्टिंग की जा सकती है. साथ ही, आपको यह भरोसा रहेगा कि अनुमति और अस्वीकार की सूचियों का इस्तेमाल किए बिना भी आपका गेम खेला जा सकता है.
सामान्य कंट्रोलर टाइप
सबसे ज़्यादा इस्तेमाल किए जाने वाले कंट्रोलर, लोकप्रिय गेम कंसोल के लेआउट की तरह होते हैं. यह बटन के लेबल और लेआउट, दोनों में बेहतर दिखता है. साथ ही, यह उन इवेंट के हिसाब से काम करता है जो ट्रिगर होते हैं. अलग-अलग कंसोल टाइप के बीच हार्डवेयर टॉगल करने वाले कंट्रोलर, भेजे जाने वाले इवेंट और अक्सर उनके लॉजिकल बटन लेआउट को बदल देंगे.
हमारा सुझाव है कि टेस्टिंग के दौरान, यह पुष्टि करें कि आपका गेम हर कैटगरी के एक कंट्रोलर के साथ काम करता है. आपके पास पहले पक्ष के कंट्रोलर या तीसरे पक्ष की लोकप्रिय कंपनियों के कंट्रोलर के साथ टेस्टिंग करने का विकल्प होता है. आम तौर पर, हम सबसे लोकप्रिय कंट्रोलर को ऊपर दी गई परिभाषा के हिसाब से मैप करने की पूरी कोशिश करेंगे.
| कंट्रोलर का टाइप | व्यवहार में अंतर | लेबलिंग के अलग-अलग वर्शन |
|---|---|---|
| Xbox स्टाइल वाले कंट्रोलर
ये कंट्रोलर, आम तौर पर Microsoft Xbox और Windows* प्लैटफ़ॉर्म के लिए बनाए जाते हैं. |
ये कंट्रोलर, प्रोसेस कंट्रोलर इनपुट में बताई गई सुविधाओं के सेट से मेल खाते हैं | इन कंट्रोलर पर मौजूद L2/R2 बटन को LT/RT के तौर पर लेबल किया गया है |
| स्टाइल कंट्रोलर स्विच करना
आम तौर पर, इन कंट्रोलर को Nintendo Switch* के कंसोल के लिए डिज़ाइन किया जाता है. |
ये कंट्रोलर, KeyEvent
KEYCODE_BUTTON_R2
KEYCODE_BUTTON_L2
MotionEvent भेजते हैं |
इन कंट्रोलर पर मौजूद L2/R2 बटन को ZL/ZR के तौर पर लेबल किया गया है.
इन कंट्रोलर में, A और B बटन के साथ-साथ X और Y बटन की जगह भी बदल जाती है. इसलिए, |
| PlayStation स्टाइल वाले कंट्रोलर
आम तौर पर, इन कंट्रोलर को Sony PlayStation* कंसोल के लिए डिज़ाइन किया जाता है. |
ये कंट्रोलर, MotionEvent जैसे Xbox स्टाइल वाले कंट्रोलर भेजते हैं. हालांकि, पूरी तरह से दबाए जाने पर, ये KeyEvent जैसे Switch स्टाइल वाले कंट्रोलर भी भेजते हैं. |
इन कंट्रोलर में, फ़ेस बटन के लिए अलग-अलग ग्लिफ़ का इस्तेमाल किया जाता है. |
* Microsoft, Xbox, और Windows, Microsoft के रजिस्टर किए हुए ट्रेडमार्क हैं; Nintendo Switch, Nintendo of America Inc. का रजिस्टर किया हुआ ट्रेडमार्क है; PlayStation, Sony Interactive Entertainment Inc. का रजिस्टर किया हुआ ट्रेडमार्क है.
ट्रिगर बटन को अलग-अलग करना
कुछ कंट्रोलर AXIS_LTRIGGER और AXIS_RTRIGGER इवेंट भेजते हैं, कुछ KEYCODE_BUTTON_L2 और KEYCODE_BUTTON_R2 इवेंट भेजते हैं, और कुछ कंट्रोलर अपने हार्डवेयर की क्षमताओं के आधार पर ये सभी इवेंट भेजते हैं. इन सभी इवेंट के साथ काम करके, कंपैटबिलिटी बढ़ाएं.
AXIS_LTRIGGER भेजने वाले सभी कंट्रोलर, AXIS_BRAKE भी भेजेंगे. इसी तरह, AXIS_RTRIGGER और AXIS_GAS भी भेजेंगे, ताकि रेसिंग व्हील और सामान्य गेम कंट्रोलर के बीच ज़्यादा से ज़्यादा कंपैटिबिलिटी हो. आम तौर पर, इससे कोई समस्या नहीं होगी. हालांकि, बटन रीमैप करने की स्क्रीन जैसी सुविधाओं के लिए सावधान रहें.
| Trigger | MotionEvent |
KeyEvent |
|---|---|---|
| लेफ़्ट ट्रिगर | AXIS_LTRIGGERAXIS_BRAKE
|
KEYCODE_BUTTON_L2
|
| राइट ट्रिगर | AXIS_RTRIGGERAXIS_GAS
|
KEYCODE_BUTTON_R2
|
यह पक्का करें कि आपका गेम, KeyEvent और MotionEvent, दोनों को हैंडल कर सकता हो, ताकि ज़्यादा से ज़्यादा कंट्रोलर के साथ काम कर सके. साथ ही, यह भी पक्का करें कि इवेंट डुप्लीकेट न हों.
इस्तेमाल किए जा सकने वाले कंट्रोलर
हमारा सुझाव है कि टेस्टिंग के दौरान, यह पुष्टि करें कि आपका गेम हर कैटगरी के एक कंट्रोलर के साथ काम करता है.
- Xbox स्टाइल
- Nintendo Switch स्टाइल
- PlayStation स्टाइल
पहले पक्ष (ग्राहक) के कंट्रोलर या तीसरे पक्ष के लोकप्रिय मैन्युफ़ैक्चरर के साथ टेस्ट किया जा सकता है. हम आम तौर पर, सबसे लोकप्रिय कंट्रोलर को परिभाषा के हिसाब से मैप करते हैं.