---
title: "HUD и адаптивный интерфейс браузерной игры: якоря, масштаб, размер цели касания"
description: "Как сделать HUD браузерной 2D-игры, который не уезжает с экрана и не прячется под вырез телефона: экранные координаты против мировых, якоря и отступы, масштаб от опорного разрешения 1280×720, безопасные зоны env(safe-area-inset-*) и размер цели касания 24 и 44 CSS-пикселя по WCAG 2.2. Код проверен в Node.js 24."
slug: interfejs-poverh-igry-schetchik-ochkov-i-knopki
date: 2026-11-01
updated: 2026-11-02
scheduled_at: "2026-11-01T19:00:00+03:00"
rubric: praktika-i-uroki
tags: ["interfejs", "hud", "mobilnye-igry", "adaptivnost", "novichkam"]
reading_time: 9
draft: false
summary: "HUD — счётчик очков, полоска здоровья, значок паузы и сенсорные зоны управления — рисуется в экранных координатах поверх игрового мира и не двигается вместе с камерой. Каждый элемент привязывают якорем к углу или краю экрана с отступом, размеры умножают на общий масштаб от опорного разрешения, например 1280×720, с нижней границей, а на телефонах отступают от выреза и полосы жестов через env(safe-area-inset-*). Зоны касания делают не меньше 44×44 CSS-пикселей (WCAG 2.5.5), а абсолютный минимум по WCAG 2.2 — 24×24 CSS-пикселя."
---

## Коротко

HUD рисуют в экранных координатах после мира, привязывают каждый элемент якорем к углу или краю и масштабируют от опорного разрешения с нижней границей. На телефонах к отступам добавляют безопасные зоны `env(safe-area-inset-*)`, а зоны касания делают не меньше 44×44 CSS-пикселей. Ниже — формулы якорей и масштаба, таблица раскладки HUD и код, проверенный в Node.js 24 на экранах 1280×720 и 844×390.

## Содержание

1. Мировые координаты против экранных
2. Якоря и отступы: формула позиции
3. Масштаб интерфейса от опорного разрешения
4. Безопасные зоны: вырез и полоса жестов
5. Размер цели касания: 24 и 44 CSS-пикселя
6. Таблица: раскладка HUD платформера
7. Код на JavaScript: якоря, масштаб, зона нажатия
8. Практический сценарий: проверка HUD на трёх экранах
9. Когда вам это не подойдёт

## Мировые координаты против экранных

HUD живёт в экранных координатах: его позиция отсчитывается от угла окна и не зависит от камеры. Мир рисуется со смещением камеры, поэтому счётчик очков, нарисованный «в мире», уезжает влево, когда герой бежит вправо. Порядок кадра такой: сначала мир со смещением камеры, затем сброс смещения, затем HUD.

Обратное преобразование нужно, когда касание по экрану должно попасть в объект мира:

```text
мир_x = экран_x / зум + камера_x − ширина_экрана / (2 × зум)
```

Касание сначала проверяют по элементам HUD и только если оно мимо, переводят в мировые координаты.

## Якоря и отступы: формула позиции

Якорь задаёт, к какой точке экрана привязан элемент, в долях: 0 — левый или верхний край, 0,5 — середина, 1 — правый или нижний. Позиция левого верхнего угла элемента:

```text
x = левая_граница + (правая_граница − левая_граница) × якорь_x − ширина × якорь_x
левая_граница  = безопасная_зона_слева + отступ
правая_граница = ширина_экрана − безопасная_зона_справа − отступ
```

Для вертикали формула та же. Одна формула покрывает все девять позиций: углы, середины краёв и центр.

## Масштаб интерфейса от опорного разрешения

Масштаб HUD считают от опорного разрешения как меньшее из отношений ширины и высоты и ограничивают снизу и сверху:

```text
масштаб = clamp(min(ширина / 1280, высота / 720), 0,75, 2)
```

Без нижней границы на телефоне в альбомной ориентации 844×390 масштаб был бы 0,54, и значок паузы 32×32 сжался бы до 17×17 — по нему трудно попасть. Без верхней на мониторе 2560×1440 счётчик стал бы огромным. Размеры шрифтов умножают на тот же масштаб.

## Безопасные зоны: вырез и полоса жестов

На телефонах с вырезом и скруглёнными углами часть экрана перекрыта, и отступы HUD нужно увеличить на размер безопасной зоны. В CSS её дают переменные `env(safe-area-inset-top)`, `env(safe-area-inset-right)`, `env(safe-area-inset-bottom)` и `env(safe-area-inset-left)`; у функции `env()` есть запасное значение вторым аргументом, например `env(safe-area-inset-right, 0px)`. Игре на холсте эти значения удобно прочитать через вычисленные стили вспомогательного элемента и передать в расчёт якорей.

В альбомной ориентации вырез оказывается слева или справа, а полоса жестов — снизу, поэтому учитывайте все четыре стороны.

## Размер цели касания: 24 и 44 CSS-пикселя

Минимальный размер цели касания задают критерии WCAG 2.2, и считается он в CSS-пикселях, а не в физических. Критерий 2.5.8 (уровень AA) требует не меньше 24×24 CSS-пикселя либо достаточного отступа: круг диаметром 24 CSS-пикселя по центру маленькой цели не должен задевать соседние. Критерий 2.5.5 (уровень AAA) — не меньше 44×44 CSS-пикселя.

Для игры ориентируйтесь на 44×44 и больше: по зоне прыжка бьют не глядя и в спешке. Видимый значок может быть меньше, если зона нажатия расширена вокруг него, — так делает функция `hitBox` в коде ниже.

## Таблица: раскладка HUD платформера

Значения ниже заданы для опорного разрешения 1280×720 и умножаются на масштаб.

| Элемент | Якорь | Размер | Отступ | Зона нажатия |
|---|---|---|---|---|
| Очки | верхний левый | 160 × 32 | 16 | — |
| Здоровье | верхний левый, под очками | 160 × 16 | 16 | — |
| Пауза | верхний правый | 32 × 32 | 16 | не меньше 44 × 44 |
| Прыжок | нижний правый | 72 × 72 | 24 | сам элемент |
| Стик движения | нижний левый | 120 × 120 | 24 | вся левая треть экрана |

## Код на JavaScript: якоря, масштаб, зона нажатия

Код считает позиции элементов HUD для монитора и телефона с вырезом и расширяет зону нажатия маленького значка. Он проверен в Node.js 24, числа в комментариях совпадают с выводом.

```js
// Якорь элемента HUD: доля ширины и высоты экрана (0 — левый/верхний край, 1 — правый/нижний)
const ANCHORS = {
  topLeft: [0, 0], top: [0.5, 0], topRight: [1, 0],
  bottomLeft: [0, 1], bottom: [0.5, 1], bottomRight: [1, 1],
};

// Масштаб интерфейса от опорного разрешения 1280×720 с нижней и верхней границей
function uiScale(view) {
  const s = Math.min(view.w / 1280, view.h / 720);
  return Math.max(0.75, Math.min(2, s));
}

// Позиция левого верхнего угла элемента в CSS-пикселях с учётом безопасной зоны (вырез, скругления)
function place(el, view, safe) {
  const k = uiScale(view);
  const a = ANCHORS[el.anchor];
  const w = el.w * k, h = el.h * k;
  const left = safe.left + el.margin * k;
  const right = view.w - safe.right - el.margin * k;
  const top = safe.top + el.margin * k;
  const bottom = view.h - safe.bottom - el.margin * k;
  const x = left + (right - left) * a[0] - w * a[0];
  const y = top + (bottom - top) * a[1] - h * a[1];
  return { x: Math.round(x), y: Math.round(y), w: Math.round(w), h: Math.round(h) };
}

// Кнопка касания: видимый значок может быть меньше, но зона нажатия — не меньше minSide
function hitBox(r, minSide) {
  const w = Math.max(r.w, minSide), h = Math.max(r.h, minSide);
  return { x: r.x - (w - r.w) / 2, y: r.y - (h - r.h) / 2, w, h };
}

const pause = { anchor: "topRight", w: 32, h: 32, margin: 16 };
const score = { anchor: "topLeft", w: 160, h: 32, margin: 16 };
const jump  = { anchor: "bottomRight", w: 72, h: 72, margin: 24 };
const none = { top: 0, right: 0, bottom: 0, left: 0 };

const desktop = { w: 1280, h: 720 };
console.log(uiScale(desktop), place(pause, desktop, none)); // 1 { x: 1232, y: 16, w: 32, h: 32 }

// Телефон в альбомной ориентации 844×390 с вырезом слева 47 и полосой жестов снизу 21
const phone = { w: 844, h: 390 };
const notch = { top: 0, right: 47, bottom: 21, left: 47 };
console.log(uiScale(phone));               // 0.75 — нижняя граница, иначе было бы 0.54
console.log(place(score, phone, notch));   // { x: 59, y: 12, w: 120, h: 24 }
console.log(place(jump, phone, notch));    // { x: 725, y: 297, w: 54, h: 54 }

// Значок паузы 24×24 на телефоне: зона нажатия расширяется до 44×44
const p = place(pause, phone, notch);
console.log(p.w, hitBox(p, 44));           // 24 { x: 751, y: 2, w: 44, h: 44 }
```

На телефоне значок паузы виден размером 24×24, но принимает касания в квадрате 44×44; часть этой зоны заходит в отступ, а не под вырез, потому что безопасная зона уже учтена в позиции.

## Практический сценарий: проверка HUD на трёх экранах

Проверка занимает около 10 минут в инструментах разработчика браузера:

1. **Монитор 1280×720.** Масштаб 1: элементы на своих местах, отступы 16 и 24 пикселя.
2. **Телефон в портретной ориентации 390×844.** Масштаб упирается в нижнюю границу 0,75; проверьте, что очки и пауза не перекрываются на ширине 390.
3. **Телефон в альбомной ориентации 844×390.** Задайте безопасные зоны слева и справа по 47, снизу 21 и убедитесь, что ни один элемент не заходит под них.
4. **Цели касания.** Включите отображение зон нажатия и проверьте, что каждая не меньше 44×44 CSS-пикселей.
5. **Смена ориентации.** Поверните устройство во время игры: позиции должны пересчитываться по событию изменения размера, без перезагрузки.

## Когда вам это не подойдёт

Якоря с общим масштабом подходят большинству игр с HUD, но не всем:

- **Сложные меню с прокруткой и формами:** списки сохранений, магазин с фильтрами и поля ввода проще сверстать обычным HTML и CSS поверх холста, чем рассчитывать вручную.
- **Диегетический интерфейс:** если здоровье показано на самом персонаже, а патроны — на оружии, такие элементы живут в мировых координатах и двигаются с камерой.
- **Игры только для мыши на компьютере:** требования к целям касания там мягче, но минимум 24×24 CSS-пикселя по WCAG 2.5.8 всё равно полезен.

---

Мы разрабатываем **J2DRU** — браузерный 2D игровой движок; текст, кнопки и другие элементы интерфейса поверх игры входят в проверенные внутри разработки основы. Движок публично пока не открыт, заявку можно оставить на [странице раннего доступа](/early-access?utm_source=blog&utm_medium=article&utm_campaign=interfejs-poverh-igry-schetchik-ochkov-i-knopki) (подача заявки не гарантирует приглашение).

**Источники (проверено: ноябрь 2026):** [W3C — Understanding SC 2.5.8 Target Size (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html), [W3C — Understanding SC 2.5.5 Target Size (Enhanced)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-enhanced.html), [MDN — env()](https://developer.mozilla.org/en-US/docs/Web/CSS/env).

**Читайте также:**
- [Камера, параллакс и game feel в 2D-игре](/blog/kamera-parallaks-i-game-feel-v-2d-igre)
- [Эволюция 2D-камеры: от одного экрана до скроллинга](/blog/evolyuciya-2d-kamery-ot-odnogo-ekrana-do-skrollinga)
- [Действия ввода вместо клавиш: KeyboardEvent.code, Gamepad API, мёртвая зона](/blog/vvod-klaviatura-gejmpad-kasanie-v-2d-igre)
