HeapPlay

Как добавить сенсорное управление в браузерную игру, рассчитанную только на клавиатуру?

Положите поверх игры отдельный сенсорный слой, который передаёт ей уже понятные ей команды. Рассказываем, как мы сделали это для KittenGalaxy и что пока не проверили.

Добавьте отдельный слой экранных кнопок, который превращает касания в команды, уже понятные вашей игре, и показывайте на каждом экране игры свои кнопки. Переписывать игру не нужно. Именно так мы сделали KittenGalaxy играбельной на телефонах, и в этой статье разбираем принятые решения, включая то, что пока не удалось проверить.

Чего игра ожидала раньше?

KittenGalaxy — аркадный шутер, написанный одним файлом JavaScript, который рисует на canvas. Весь ввод приходил тремя путями: нажатия клавиш для полёта, стрельбы и меню; набранные символы для имени пилота; щелчки мышью по списку магазина и по нарисованной на canvas цифровой панели в математических заданиях.

На телефоне игроку при этом нечего нажимать. Клавиш нет, а нарисованные на canvas цифровые кнопки шириной 38 единиц при поле в 720 единиц на телефоне шириной 375 пикселей получаются примерно по 20 CSS-пикселей. В такие надёжно не попасть.

Должно ли касание менять общее состояние ввода или посылать события клавиш?

Есть два распространённых подхода.

ПодходКак работаетКогда подходит
Общее состояние вводаОбработчики клавиатуры и касаний выставляют флаги вроде left или fire; игровой цикл читает только флагиКод игры ваш, и вы можете изменить то, как он читает ввод
Синтетические события клавишСенсорный слой отправляет события keydown и keyup; их получают уже существующие обработчики игрыКод игры должен остаться как есть

Общее состояние — более чистое решение, и если вы начинаете игру сегодня, делайте так. Мы выбрали синтетические события клавиш по одной причине: KittenGalaxy разрабатывается в другом месте, и мы храним её файл байт в байт таким, каким получаем, чтобы переход на новую версию никогда не требовал переделывать наши изменения. События, созданные скриптом, доходят до обычных обработчиков. Они не запускают собственные действия браузера по умолчанию, но игре те и не нужны.

Сенсорному слою нужно ещё знать, на каком экране находится игра. Для этого наш шаг сборки добавляет один небольшой объект только для чтения, который открывает несколько значений, например текущее состояние и установлена ли ракета. Изменить игру через него нельзя.

Касание пальца попадает в сенсорный слой, который посылает события клавиш неизменённой игре и читает её состояние
Где находится сенсорный слой.

Какие кнопки нужны на каждом экране?

Обычно сначала пробуют один постоянный набор кнопок, и он перестаёт работать, как только в игре появляется меню. Выпишите все экраны и то, что игрок должен уметь делать на каждом.

ЭкранЧто нужно игрокуЧто мы показываем
МенюНачать, сменить или добавить пилотаБольшую главную кнопку и маленькие, которые появляются только когда уместны
Имя пилотаВвести имяНастоящее текстовое поле, чтобы телефон показал клавиатуру
ПолётДвигаться, стрелять, применять дополнения, ставить паузуСтик под большой палец, автострельбу, кнопки дополнений только после их покупки
МагазинПросматривать и покупатьКнопки вкладок и стрелок; касание строки выбирает её, повторное касание покупает
Математическое заданиеВвести числоПолноразмерную цифровую панель
Конец игры, концовкиПродолжить или выйтиДве кнопки

Три детали оказались важнее, чем мы ожидали.

Для текста используйте настоящее текстовое поле. Только поле в фокусе заставляет телефон показать клавиатуру. Нажатия клавиш в этом поле мы до игры не допускаем, а готовое имя вводим в игру за один раз.

Палец не умеет наводиться. Мышью наведение на строку магазина выбирает её, а щелчок покупает. Касание делает и то и другое сразу, из-за чего легко купить случайно. Слой превращает первое касание строки в выбор, а второе пропускает как покупку.

Прячьте то, что неприменимо. Кнопка ракеты появляется, когда ракета установлена, а кнопка бомбы — когда бомба есть. Меньше кнопок — крупнее кнопки.

Как сделать стик под большой палец?

Корабль в игре движется в восьми направлениях, как от стрелок, поэтому стику нужно лишь решить, какие стрелки нажаты. Наш появляется там, куда опустился палец, не реагирует на движения внутри мёртвой зоны в 12 пикселей и считает направление нажатым, когда палец ушёл достаточно далеко по этой оси:

const DEAD = 12;
function steer(dx, dy) {
  const far = Math.hypot(dx, dy) > DEAD;
  const want = {
    ArrowLeft:  far && dx < 0 && Math.abs(dx) >= Math.abs(dy) * 0.41,
    ArrowRight: far && dx > 0 && Math.abs(dx) >= Math.abs(dy) * 0.41,
    ArrowUp:    far && dy < 0 && Math.abs(dy) >= Math.abs(dx) * 0.41,
    ArrowDown:  far && dy > 0 && Math.abs(dy) >= Math.abs(dx) * 0.41,
  };
  // press the keys that became true, release the ones that became false
}

0,41 — это тангенс 22,5 градуса, он делит круг на восемь равных секторов. Когда палец выходит за край, центр стика следует за ним, поэтому для разворота достаточно короткого движения, а не длинного.

Мы использовали события указателя, которые одним набором обработчиков охватывают касание, перо и мышь, и захват указателя, чтобы стик продолжал получать палец, соскользнувший с него. Стрельба по умолчанию автоматическая, с переключателем для тех, кому удобнее кнопка огня: держать палец прижатым всю игру утомительно, а шутер мало теряет от постоянной стрельбы.

Что мешает браузеру бороться с игрой?

Браузер воспринимает касания как прокрутку, масштабирование и выделение текста, пока ему не сказать иначе.

  • Задайте [touch-action: none](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/touch-action) для игры и её кнопок, чтобы перетаскивания доставались вам.
  • Отключите выделение текста и меню долгого нажатия над игрой.
  • Отпускайте все удерживаемые клавиши, когда окно теряет фокус. Иначе корабль продолжит лететь влево после того, как экран займёт уведомление.
  • Запускайте звук по настоящему касанию. Браузеры разрешают звук только после того, как игрок что-то сделал на странице, поэтому первое касание заодно будит звук игры.
  • Обновляйте кнопки по таймеру, а не только из цикла отрисовки, чтобы нужные кнопки были на месте ещё до первого кадра.
  • Используйте полосы, которые игра оставляет пустыми. В портретной ориентации наше квадратное поле стоит посередине, поэтому кнопки идут в чёрные полосы сверху и снизу. В альбомной они уходят в углы и остаются полупрозрачными.

Что мы проверили, а что нет?

В день выпуска, 8 октября 2026 года, мы проверили сенсорный слой в настольном браузере, выставленном на размер телефона, в портретной (375 × 812) и альбомной (812 × 375) ориентации, управляя им скриптовыми касаниями: создание пилота через текстовое поле, начало игры, все восемь направлений стика, магазин и ответ на математический вопрос на цифровой панели.

На настоящем телефоне или планшете мы в неё ещё не играли. Эмуляция не показывает, как стик ощущается под настоящим пальцем, как ведёт себя клавиатура каждого телефона и как справляется более медленное устройство. Именно это и написано на странице игры у варианта для мобильного браузера, и мы обновим запись, когда попробуем на настоящих устройствах. Если вы сыграете на своём телефоне, отзыв с указанием устройства и того, что произошло, — самое полезное, что вы можете прислать.

Частые вопросы

Нужен ли игровой движок для сенсорного управления? Нет. Кнопки — обычные элементы HTML, расположенные поверх canvas, а какой из них коснулись, определяет браузер.

Рисовать кнопки на canvas или делать в HTML? В большинстве случаев в HTML. Определение попаданий, мультитач и подписи для доступности вы получаете, не написав их сами, а оформление можно менять через CSS.

Какого размера должна быть сенсорная кнопка? Кнопки, которые нажимают во время игры, в портретной ориентации не меньше 46 CSS-пикселей по каждой стороне, а главные больше; несколько служебных кнопок в углах намеренно меньше. Нарисованные на canvas кнопки, которые мы заменили, были около 20.

Найдут ли игроки скрытый жест? Считайте, что нет. У каждого действия в нашем слое есть видимая подписанная кнопка.

Можно ли добавить игру на HeapPlay до того, как готово мобильное управление? Да. Каждый способ играть указывается и проверяется отдельно, поэтому можно добавить игру с вариантом для компьютера сейчас, а мобильный добавить позже. Подтверждённые разработчики затем сами записывают каждую версию; см. что получают разработчики.

touch-controls mobile browser-games

Делаете игру? Добавьте её на HeapPlay и посмотрите, что получают разработчики.