ورودی ماوس

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

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

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

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

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

مدیریت ورودی برای بازی‌های گوگل پلی در کامپیوتر شخصی مشابه سیستم عامل کروم است. تغییراتی که از کامپیوتر شخصی پشتیبانی می‌کنند، بازی شما را برای همه بازیکنان اندروید نیز بهبود می‌بخشند.

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

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

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

نسخه اصلی Google Play Games روی کامپیوتر، هنگام اجرای بازی، به حالت صحیح تغییر می‌کند. هنگام اجرا در شبیه‌ساز توسعه‌دهندگان، برای دریافت ورودی خام ماوس، باید روی آیکون نوار وظیفه کلیک راست کنید، گزینه‌های توسعه‌دهندگان و سپس حالت PC(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;
        }
    }
}

در این مثال، این عمل مشابه رویدادهای hover مدیریت می‌شود:

کاتلین

// 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() را فراخوانی کنید.