ورودی ماوس

این مبحث نحوه پیاده‌سازی ورودی ماوس برای بازی‌های Google Play در رایانه شخصی را برای بازی‌هایی که حالت ترجمه ورودی تجربه بازیکنی ایده‌آل ارائه نمی‌دهد، پوشش می‌دهد.

پخش‌کننده‌های رایانه‌های شخصی معمولاً به جای صفحه‌نمایش لمسی، صفحه‌کلید و ماوس دارند، و این مهم است که در نظر بگیرید آیا بازی شما ورودی ماوس را دارد یا خیر. به‌طور پیش‌فرض، بازی‌های Google Play در رایانه شخصی هر رویداد کلیک چپ ماوس را به یک رویداد ضربه مجازی تبدیل می‌کند. این به عنوان "حالت ترجمه ورودی" شناخته می شود.

اگرچه این حالت با تغییرات اندکی بازی شما را کاربردی می کند، اما تجربه ای با احساس بومی برای بازیکنان رایانه شخصی فراهم نمی کند. برای این منظور توصیه می کنیم موارد زیر را پیاده سازی کنید:

  • به جای فشار دادن و نگه داشتن عملکردها، حالت ها را برای منوهای زمینه نگه دارید
  • برای اقدامات جایگزینی که با فشار طولانی یا در منوی زمینه اتفاق می‌افتند، کلیک راست کنید
  • ماوس را برای بازی های اکشن اول یا سوم شخص به جای یک رویداد مطبوعاتی و کشیدنی جستجو کنید

به منظور پشتیبانی از الگوهای رابط کاربری رایج در رایانه های شخصی، باید حالت ترجمه ورودی را غیرفعال کنید.

مدیریت ورودی بازی‌های Google Play در رایانه شخصی مشابه ChromeOS است. تغییراتی که از رایانه های شخصی پشتیبانی می کند همچنین بازی شما را برای همه بازیکنان اندروید بهبود می بخشد.

حالت ترجمه ورودی را غیرفعال کنید

در فایل AndroidManifest.xml ، ویژگی android.hardware.type.pc را اعلام کنید. این نشان می دهد که بازی شما از سخت افزار رایانه شخصی استفاده می کند و حالت ترجمه ورودی را غیرفعال می کند. علاوه بر این، افزودن required="false" به شما کمک می کند تا مطمئن شوید که بازی شما همچنان می تواند بدون ماوس روی تلفن ها و تبلت ها نصب شود. به عنوان مثال:

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

نسخه تولیدی بازی‌های Google Play در رایانه شخصی هنگام راه‌اندازی بازی به حالت صحیح تغییر می‌کند. هنگام اجرا در شبیه ساز توسعه دهنده، باید روی نماد نوار وظیفه کلیک راست کنید، گزینه های توسعه دهنده و سپس حالت PC (KiwiMouse) را برای دریافت ورودی خام ماوس انتخاب کنید.

اسکرین شات از "حالت کامپیوتر (KiwiMouse)" انتخاب شده در منوی زمینه

پس از انجام این کار، حرکت ماوس توسط 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 برای دریافت وضعیت همه دکمه ها استفاده کنید.

در این مثال، از یک enum برای کمک به نمایش نتیجه getActionButton استفاده شده است:

کاتلین

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() فقط زمانی کار می کند که سلسله مراتب view حاوی view شما فوکوس داشته باشد. به همین دلیل، نمی‌توانید در پاسخ به تماس 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() را فراخوانی کنید.