В этой теме рассказывается, как реализовать ввод с помощью мыши в Google Play Games на ПК для игр, в которых режим трансляции ввода не обеспечивает идеальных условий для игроков.
У ПК-игроков обычно есть клавиатура и мышь, а не сенсорный экран, поэтому важно учитывать, поддерживает ли ваша игра ввод с помощью мыши. По умолчанию Google Play Games на ПК преобразует любое событие щелчка левой кнопкой мыши в одно виртуальное событие касания. Это известно как «режим трансляции ввода».
Хотя этот режим делает вашу игру функциональной с небольшими изменениями, он не дает игрокам на ПК ощущения естественного опыта. Для этого мы рекомендуем реализовать следующее:
- Состояния наведения для контекстных меню, а не действия по нажатию и удержанию
- Щелкните правой кнопкой мыши, чтобы увидеть альтернативные действия, которые происходят при длительном нажатии или в контекстном меню.
- Mouselook — это экшн-игры от первого или третьего лица, а не событие нажатия и перетаскивания.
Чтобы поддерживать шаблоны пользовательского интерфейса, распространенные на ПК, необходимо отключить режим трансляции ввода.
Обработка ввода для Google Play Games на ПК идентична обработке ввода в 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 }
Ява
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
чтобы получить состояние всех кнопок.
В этом примере перечисление используется для отображения результата 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()
работает только тогда, когда иерархия представлений, содержащая ваше представление, имеет фокус. По этой причине вы не можете получить захват указателя в обратном вызове 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()
.