নিয়ন্ত্রক কর্ম হ্যান্ডেল

নিয়ন্ত্রকদের দুই ধরণের ক্রিয়া থাকে:

  • "চালু" এবং "বন্ধ" বাইনারি অবস্থা সহ যেকোনো বোতামের জন্য KeyEvent ব্যবহৃত হয়।
  • MotionEvent যেকোনো অক্ষের জন্য ব্যবহৃত হয় যা বিভিন্ন মানের মান প্রদান করে। যেমন অ্যানালগ স্টিকের জন্য -1 থেকে 1 অথবা অ্যানালগ ট্রিগারের জন্য 0 থেকে 1।

আপনি focus আছে এমন View থেকে এই ইনপুটগুলি পড়তে পারেন।

কোটলিন

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

জাভা

@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 থেকে ইভেন্টগুলি পড়তে পারেন।

একটি গেম কন্ট্রোলার সংযুক্ত আছে কিনা তা যাচাই করুন

ইনপুট ইভেন্ট রিপোর্ট করার সময়, Android বিভিন্ন ধরণের ইনপুট ডিভাইসের জন্য একই কী বা অক্ষ আইডি পুনরায় ব্যবহার করবে। উদাহরণস্বরূপ, একটি টাচস্ক্রিন অ্যাকশন একটি AXIS_X ইভেন্ট তৈরি করে যা টাচ সারফেসের X স্থানাঙ্ককে প্রতিনিধিত্ব করে, কিন্তু একটি গেমপ্যাড একটি AXIS_X ইভেন্ট তৈরি করে যা বাম স্টিকের X অবস্থানকে প্রতিনিধিত্ব করে। এর অর্থ হল ইনপুট ইভেন্টগুলি সঠিকভাবে ব্যাখ্যা করার জন্য আপনাকে অবশ্যই সোর্স টাইপ পরীক্ষা করতে হবে।

একটি সংযুক্ত InputDevice একটি গেম কন্ট্রোলার কিনা তা যাচাই করতে, supportsSource(int) ফাংশনটি ব্যবহার করুন:

  • SOURCE_GAMEPAD এর একটি সোর্স টাইপ নির্দেশ করে যে ইনপুট ডিভাইসে কন্ট্রোলার বোতাম আছে (উদাহরণস্বরূপ, KEYCODE_BUTTON_A )। মনে রাখবেন যে এই সোর্স টাইপটি স্পষ্টভাবে নির্দেশ করে না যে গেম কন্ট্রোলারে D-প্যাড বোতাম আছে কিনা, যদিও বেশিরভাগ কন্ট্রোলারে সাধারণত দিকনির্দেশনামূলক নিয়ন্ত্রণ থাকে।
  • SOURCE_DPAD এর একটি উৎস প্রকার নির্দেশ করে যে ইনপুট ডিভাইসে D-প্যাড বোতাম রয়েছে (উদাহরণস্বরূপ, DPAD_UP )।
  • SOURCE_JOYSTICK এর একটি উৎস প্রকার নির্দেশ করে যে ইনপুট ডিভাইসে অ্যানালগ কন্ট্রোল স্টিক রয়েছে (উদাহরণস্বরূপ, একটি জয়স্টিক যা AXIS_X এবং AXIS_Y বরাবর গতিবিধি রেকর্ড করে)।

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

কোটলিন

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
}

জাভা

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

প্রক্রিয়া নিয়ন্ত্রক ইনপুট

এই বিভাগে অ্যান্ড্রয়েডে সমর্থিত গেম কন্ট্রোলারের ধরণগুলি বর্ণনা করা হয়েছে।

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

এই চিত্রটি দেখায় যে একজন অ্যান্ড্রয়েড গেম ডেভেলপার অ্যান্ড্রয়েডে একজন সাধারণ কন্ট্রোলার কেমন দেখতে আশা করতে পারেন।

ডি-প্যাড, অ্যানালগ স্টিক এবং বোতাম সহ লেবেলযুক্ত ইনপুট সহ জেনেরিক গেম কন্ট্রোলার
চিত্র ১. একটি জেনেরিক গেম কন্ট্রোলারের প্রোফাইল।

টেবিলটিতে গেম কন্ট্রোলারের জন্য স্ট্যান্ডার্ড ইভেন্টের নাম এবং প্রকারগুলি তালিকাভুক্ত করা হয়েছে। ইভেন্টগুলির সম্পূর্ণ তালিকার জন্য, সাধারণ রূপগুলি দেখুন। সিস্টেমটি onGenericMotionEvent এর মাধ্যমে MotionEvent ইভেন্ট এবং onKeyDown এবং onKeyUp মাধ্যমে KeyEvent ইভেন্টগুলি পাঠায়।

কন্ট্রোলার ইনপুট কীইভেন্ট মোশনইভেন্ট
১. ডি-প্যাড
AXIS_HAT_X
(অনুভূমিক ইনপুট)
AXIS_HAT_Y
(উল্লম্ব ইনপুট)
2. বাম অ্যানালগ স্টিক
KEYCODE_BUTTON_THUMBL
(চাপা দিলে)
AXIS_X
(অনুভূমিক গতিবিধি)
AXIS_Y
(উল্লম্ব নড়াচড়া)
৩. ডান অ্যানালগ স্টিক
KEYCODE_BUTTON_THUMBR
(চাপা দিলে)
AXIS_Z
(অনুভূমিক গতিবিধি)
AXIS_RZ
(উল্লম্ব নড়াচড়া)
৪. এক্স বোতাম KEYCODE_BUTTON_X
৫. একটি বোতাম KEYCODE_BUTTON_A
৬. Y বোতাম KEYCODE_BUTTON_Y
৭. বি বোতাম KEYCODE_BUTTON_B
৮. ডান বাম্পার
KEYCODE_BUTTON_R1
9. ডান ট্রিগার
AXIS_RTRIGGER
১০. বাম ট্রিগার AXIS_LTRIGGER
১১. বাম বাম্পার KEYCODE_BUTTON_L1
১২. শুরু করুন KEYCODE_BUTTON_START
১৩. নির্বাচন করুন KEYCODE_BUTTON_SELECT

হ্যান্ডেলের বোতাম টিপে

যেহেতু অ্যান্ড্রয়েড রিপোর্ট করে যে কন্ট্রোলার বোতাম টিপলে কীবোর্ড বোতাম টিপলে একই রকম হয়, তাই আপনাকে নিম্নলিখিতগুলি করতে হবে:

  • ইভেন্টটি SOURCE_GAMEPAD থেকে আসছে কিনা তা যাচাই করুন।
  • KeyEvent.getRepeatCount() ব্যবহার করে নিশ্চিত করুন যে আপনি কেবল একবার বোতামটি পেয়েছেন, অ্যান্ড্রয়েড পুনরাবৃত্তি কী ইভেন্টগুলি পাঠাবে ঠিক যেমন আপনি একটি কীবোর্ড কী চেপে ধরে রাখেন।
  • true রিটার্ন করে একটি ইভেন্ট পরিচালনা করা হচ্ছে তা নির্দেশ করুন।
  • অ্যান্ড্রয়েডের বিভিন্ন সামঞ্জস্য স্তরগুলি সঠিকভাবে কাজ করছে কিনা তা যাচাই করার জন্য আনহ্যান্ডেলড ইভেন্টগুলিকে super পাস করুন।

    কোটলিন

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

    জাভা

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

প্রক্রিয়া নির্দেশমূলক প্যাড ইনপুট

৪-ওয়ে ডাইরেকশনাল প্যাড, বা ডি-প্যাড, অনেক গেম কন্ট্রোলারে একটি সাধারণ ফিজিক্যাল কন্ট্রোল। অ্যান্ড্রয়েড D-প্যাড UP এবং DOWN প্রেসকে AXIS_HAT_Y ইভেন্ট হিসেবে রিপোর্ট করে, যেখানে -1.0 উপরে এবং 1.0 নীচের দিকে নির্দেশ করে। এটি D-প্যাড LEFT বা RIGHT প্রেসকে AXIS_HAT_X ইভেন্ট হিসেবে রিপোর্ট করে, যেখানে -1.0 বাম দিকে নির্দেশ করে এবং 1.0 ডান দিকে নির্দেশ করে।

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

সারণী ২। ডি-প্যাড কী কোড এবং হ্যাট অক্ষের মানগুলির জন্য প্রস্তাবিত ডিফল্ট গেম অ্যাকশন।

গেম অ্যাকশন ডি-প্যাড কী কোড টুপি অক্ষ কোড
উপরে সরান KEYCODE_DPAD_UP AXIS_HAT_Y (০ থেকে -১.০ মানের জন্য)
নিচে সরান KEYCODE_DPAD_DOWN AXIS_HAT_Y (০ থেকে ১.০ মানের জন্য)
বামে সরান KEYCODE_DPAD_LEFT AXIS_HAT_X (০ থেকে -১.০ মানের জন্য)
ডানে সরান KEYCODE_DPAD_RIGHT AXIS_HAT_X (০ থেকে ১.০ মানের জন্য)

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

কোটলিন

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

জাভা

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() কলব্যাকে) এই সহায়ক ক্লাসটি ব্যবহার করতে পারেন।

উদাহরণস্বরূপ:

কোটলিন

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

জাভা

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

জয়স্টিকের নড়াচড়া প্রক্রিয়া করুন

যখন খেলোয়াড়রা তাদের গেম কন্ট্রোলারে একটি জয়স্টিক সরায়, তখন অ্যান্ড্রয়েড একটি MotionEvent রিপোর্ট করে যাতে ACTION_MOVE অ্যাকশন কোড এবং জয়স্টিকের অক্ষের আপডেট করা অবস্থান থাকে। আপনার গেমটি MotionEvent দ্বারা প্রদত্ত ডেটা ব্যবহার করে নির্ধারণ করতে পারে যে এটির জন্য গুরুত্বপূর্ণ কোনও জয়স্টিক নড়াচড়া ঘটেছে কিনা।

মনে রাখবেন যে জয়স্টিক মোশন ইভেন্টগুলি একটি একক বস্তুর মধ্যে একাধিক নড়াচড়ার নমুনা একসাথে ব্যাচ করতে পারে। MotionEvent অবজেক্টে প্রতিটি জয়স্টিক অক্ষের বর্তমান অবস্থানের পাশাপাশি প্রতিটি অক্ষের জন্য একাধিক ঐতিহাসিক অবস্থান থাকে। অ্যাকশন কোড ACTION_MOVE (যেমন জয়স্টিক মুভমেন্ট) দিয়ে গতি ইভেন্টগুলি রিপোর্ট করার সময়, Android দক্ষতার জন্য অক্ষের মানগুলিকে ব্যাচ করে। একটি অক্ষের ঐতিহাসিক মানগুলিতে বর্তমান অক্ষ মানের চেয়ে পুরানো এবং পূর্ববর্তী যেকোনো গতি ইভেন্টে রিপোর্ট করা মানের চেয়ে সাম্প্রতিক স্বতন্ত্র মানের সেট থাকে। বিস্তারিত জানার জন্য MotionEvent রেফারেন্স দেখুন।

জয়স্টিক ইনপুটের উপর ভিত্তি করে একটি গেম অবজেক্টের গতিবিধি সঠিকভাবে রেন্ডার করতে, আপনি MotionEvent অবজেক্ট দ্বারা প্রদত্ত ঐতিহাসিক তথ্য ব্যবহার করতে পারেন।

আপনি নিম্নলিখিত পদ্ধতিগুলি ব্যবহার করে বর্তমান এবং ঐতিহাসিক মানগুলি পুনরুদ্ধার করতে পারেন:

নিচের স্নিপেটটি দেখায় কিভাবে আপনি জয়স্টিক ইনপুট প্রক্রিয়া করার জন্য onGenericMotionEvent() কলব্যাককে ওভাররাইড করতে পারেন। আপনাকে প্রথমে একটি অক্ষের ঐতিহাসিক মানগুলি প্রক্রিয়া করতে হবে, তারপর এর বর্তমান অবস্থান প্রক্রিয়া করতে হবে।

কোটলিন

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

জাভা

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) স্থানাঙ্কের কাছে মানগুলির একটি পরিসর যেখানে অক্ষটি কেন্দ্রীভূত বলে বিবেচিত হয়। যদি অ্যান্ড্রয়েড দ্বারা রিপোর্ট করা অক্ষের মান সমতল এলাকার মধ্যে পড়ে, তাহলে আপনার নিয়ামকটিকে বিশ্রামে (অর্থাৎ, উভয় অক্ষ বরাবর গতিহীন) রাখা উচিত।

স্নিপেটটি একটি সহায়ক পদ্ধতি দেখায় যা প্রতিটি অক্ষ বরাবর গতিবিধি গণনা করে। আপনি নিম্নলিখিত নমুনায় আরও বর্ণিত processJoystickInput() পদ্ধতিতে এই সহায়কটি ব্যবহার করতে পারেন:

কোটলিন

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
}

জাভা

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

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

কোটলিন

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
}

জাভা

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
}

একটি একক জয়স্টিকের বাইরে আরও উন্নত বৈশিষ্ট্যযুক্ত গেম কন্ট্রোলারগুলিকে সমর্থন করার জন্য, এই সেরা অনুশীলনগুলি অনুসরণ করুন:

  • ডুয়াল কন্ট্রোলার স্টিক হ্যান্ডেল করুন। অনেক গেম কন্ট্রোলারে বাম এবং ডান উভয় ধরণের জয়স্টিক থাকে। বাম স্টিকের জন্য, অ্যান্ড্রয়েড অনুভূমিক নড়াচড়াকে AXIS_X ইভেন্ট এবং উল্লম্ব নড়াচড়াকে AXIS_Y ইভেন্ট হিসাবে রিপোর্ট করে। ডান স্টিকের জন্য, অ্যান্ড্রয়েড অনুভূমিক নড়াচড়াকে 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_ উভয় ইভেন্ট সমর্থন করতে হবে, তবে এমন ইভেন্ট পছন্দ করতে হবে যা আপনার গেমপ্লের জন্য সবচেয়ে বেশি অর্থবহ হয় যদি কোনও কন্ট্রোলার উভয়ই রিপোর্ট করে। অ্যান্ড্রয়েড ৪.৩ (এপিআই লেভেল ১৮) এবং তার উচ্চতর সংস্করণে, একটি AXIS_LTRIGGER তৈরি করে এমন একটি কন্ট্রোলার AXIS_BRAKE অক্ষের জন্যও একই মান রিপোর্ট করে। AXIS_RTRIGGER এবং AXIS_GAS ক্ষেত্রেও একই কথা প্রযোজ্য। অ্যান্ড্রয়েড 0.0 (মুক্ত) থেকে 1.0 (পূর্ণ চাপা) পর্যন্ত স্বাভাবিক মান সহ সমস্ত অ্যানালগ ট্রিগার প্রেস রিপোর্ট করে।
  • অনুকরণকৃত পরিবেশে নির্দিষ্ট আচরণ এবং সহায়তা ভিন্ন হতে পারে । হোস্ট অপারেটিং সিস্টেমের ক্ষমতার উপর ভিত্তি করে অনুকরণকৃত প্ল্যাটফর্ম, যেমন Google Play Games , আচরণে সামান্য ভিন্ন হতে পারে। উদাহরণস্বরূপ, AXIS_ এবং KEYCODE_BUTTON_ উভয় ইভেন্ট নির্গত করে এমন কিছু কন্ট্রোলার কেবল AXIS_ ইভেন্ট নির্গত করে এবং কিছু কন্ট্রোলারের জন্য সমর্থন সম্পূর্ণরূপে অনুপস্থিত থাকতে পারে।

সাধারণ রূপগুলি

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

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

সাধারণ নিয়ন্ত্রকের প্রকারভেদ

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

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

কন্ট্রোলারের ধরণ আচরণগত পার্থক্য লেবেলিং বৈচিত্র্য
এক্সবক্স স্টাইল কন্ট্রোলার

এগুলি সাধারণত মাইক্রোসফ্ট এক্সবক্স এবং উইন্ডোজ* প্ল্যাটফর্মের জন্য তৈরি কন্ট্রোলার।

এই কন্ট্রোলারগুলি প্রসেস কন্ট্রোলার ইনপুটগুলিতে বর্ণিত বৈশিষ্ট্য সেটের সাথে মেলে। এই কন্ট্রোলারগুলির L2/R2 বোতামগুলিকে LT/RT লেবেল করা হয়েছে
স্টাইল কন্ট্রোলার পরিবর্তন করুন

এই কন্ট্রোলারগুলি সাধারণত নিন্টেন্ডো সুইচ* পরিবারের কনসোলের জন্য ডিজাইন করা হয়।

এই কন্ট্রোলারগুলি KeyEvent KEYCODE_BUTTON_R2 KEYCODE_BUTTON_L2 MotionEvent গুলি পাঠায় এই কন্ট্রোলারগুলির L2/R2 বোতামগুলিতে ZL/ZR লেবেল করা আছে।

এই কন্ট্রোলারগুলি A এবং B বোতাম এবং X এবং Y বোতামগুলিও অদলবদল করে, তাই KEYCODE_BUTTON_A হল B লেবেলযুক্ত বোতাম এবং বিপরীতভাবে।

প্লেস্টেশন স্টাইল কন্ট্রোলার

এই কন্ট্রোলারগুলি সাধারণত Sony PlayStation* পরিবারের কনসোলের জন্য ডিজাইন করা হয়।

এই কন্ট্রোলারগুলি Xbox স্টাইল কন্ট্রোলারের মতো MotionEvent পাঠায়, কিন্তু সম্পূর্ণরূপে ডিপ্রেসড হলে সুইচ স্টাইল কন্ট্রোলারের মতো KeyEvent ও পাঠায়। এই কন্ট্রোলারগুলি ফেস বোতামগুলির জন্য আলাদা আলাদা গ্লিফ ব্যবহার করে।

* মাইক্রোসফট, এক্সবক্স এবং উইন্ডোজ মাইক্রোসফটের নিবন্ধিত ট্রেডমার্ক; নিন্টেন্ডো সুইচ নিন্টেন্ডো অফ আমেরিকা ইনকর্পোরেটেডের একটি নিবন্ধিত ট্রেডমার্ক; প্লেস্টেশন সনি ইন্টারেক্টিভ এন্টারটেইনমেন্ট ইনকর্পোরেটেডের একটি নিবন্ধিত ট্রেডমার্ক।

ট্রিগার বোতামগুলি দ্ব্যর্থহীন করুন

কিছু কন্ট্রোলার AXIS_LTRIGGER এবং AXIS_RTRIGGER পাঠায়, কিছু KEYCODE_BUTTON_L2 এবং KEYCODE_BUTTON_R2 পাঠায়, এবং অন্যরা তাদের হার্ডওয়্যার ক্ষমতার উপর ভিত্তি করে এই সমস্ত ইভেন্ট পাঠায়। এই সমস্ত ইভেন্ট সমর্থন করে সামঞ্জস্যতা সর্বাধিক করুন।

AXIS_LTRIGGER পাঠানো সকল কন্ট্রোলার AXIS_BRAKE ও পাঠাবে, একইভাবে AXIS_RTRIGGER এবং AXIS_GAS এর জন্য রেসিং হুইল এবং সাধারণ গেম কন্ট্রোলারের মধ্যে সামঞ্জস্য সর্বাধিক করতে সাহায্য করবে। সাধারণত এটি কোনও সমস্যা সৃষ্টি করবে না, তবে কী রিম্যাপিং স্ক্রিনের মতো বৈশিষ্ট্যগুলির জন্য সচেতন থাকুন।

ট্রিগার MotionEvent KeyEvent
বাম ট্রিগার AXIS_LTRIGGER
AXIS_BRAKE
KEYCODE_BUTTON_L2
ডান ট্রিগার AXIS_RTRIGGER
AXIS_GAS
KEYCODE_BUTTON_R2

আপনার গেমটি KeyEvent এবং MotionEvent উভয়ই পরিচালনা করতে পারে কিনা তা নিশ্চিত করার জন্য যত্ন নেওয়া উচিত যাতে যতটা সম্ভব কন্ট্রোলারের সাথে সামঞ্জস্য বজায় রাখা যায় এবং ইভেন্টগুলি ডি-ডুপ্লিকেট করা হয়।

সমর্থিত কন্ট্রোলার

পরীক্ষা করার সময় আমরা আপনাকে সুপারিশ করব যে আপনার গেমটি প্রতিটি বিভাগে একটি করে কন্ট্রোলারের সাথে কাজ করে তা যাচাই করুন।

  • এক্সবক্স স্টাইল
  • নিন্টেন্ডো সুইচ স্টাইল
  • প্লেস্টেশন স্টাইল

আপনি প্রথম-পক্ষের নিয়ন্ত্রক বা জনপ্রিয় তৃতীয়-পক্ষের নির্মাতাদের সাথে পরীক্ষা করতে পারেন, এবং আমরা সাধারণত সর্বাধিক জনপ্রিয় নিয়ন্ত্রকদের যতটা সম্ভব ঘনিষ্ঠভাবে সংজ্ঞা অনুসারে ম্যাপ করি।