В этой теме рассматривается, как реализовать ввод с мыши для игр Google Play Games на ПК в тех играх, где режим преобразования ввода не обеспечивает идеального игрового опыта.
Игроки на ПК обычно используют клавиатуру и мышь, а не сенсорный экран, поэтому важно учитывать, поддерживает ли ваша игра ввод с мыши. По умолчанию Google Play Games на ПК преобразует любое событие щелчка левой кнопкой мыши в одно виртуальное событие касания. Это называется «режимом преобразования ввода».
Хотя этот режим позволяет с небольшими изменениями сделать вашу игру функциональной, он не обеспечивает игрокам на ПК ощущения, аналогичные тем, что были в оригинальной игре. Для этого мы рекомендуем реализовать следующее:
- Для контекстных меню используйте наведение курсора мыши, а не нажатие и удержание кнопки мыши.
- Щелкните правой кнопкой мыши, чтобы выполнить альтернативные действия, которые происходят при длительном нажатии или в контекстном меню.
- Для экшен-игр от первого или третьего лица используется управление мышью, а не перетаскивание мышью.
Для поддержки распространенных на ПК шаблонов пользовательского интерфейса необходимо отключить режим преобразования ввода.
Обработка ввода в играх Google Play на ПК идентична обработке в ChromeOS . Изменения, поддерживающие ПК, также улучшают игру для всех игроков на Android.
Отключить режим перевода ввода
В файле AndroidManifest.xml объявите свойство android.hardware.type.pc . Это указывает на то, что ваша игра использует аппаратное обеспечение ПК и отключает режим преобразования ввода. Кроме того, добавление параметра required="false" поможет гарантировать, что вашу игру можно будет установить на телефоны и планшеты без мыши. Например:
<manifest ...>
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
...
</manifest>
В рабочей версии Google Play Games на ПК при запуске игры автоматически переключается в нужный режим. При запуске в эмуляторе разработчика необходимо щелкнуть правой кнопкой мыши по значку на панели задач, выбрать «Параметры разработчика» , а затем «Режим ПК» (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 }
Java
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 }
Java
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 } } } }
Java
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 }
Java
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 }
Java
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() } }
Java
@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 }
Java
gameView.setFocusable(true); gameView.setOnCapturedPointerListener((view, motionEvent) -> { Log.d("MA", motionEvent.getX() + ", " + motionEvent.getY() + ", " + motionEvent.getActionButton()); return true; });
Для освобождения эксклюзивного захвата курсора мыши, например, для обеспечения возможности взаимодействия игроков с меню паузы, вызовите View.releasePointerCapture() .