---
title: "Камера, параллакс и «джус» (Game Feel): как оживить плоскую сцену в 2D-игре"
description: "Формулы плавной 2D-камеры, мёртвой зоны и упреждения, коэффициенты параллакса слоёв, сжатие и растяжение с сохранением площади, тряска камеры через trauma и проверенный код камеры и отклика на JavaScript."
slug: kamera-parallaks-i-game-feel-v-2d-igre
date: 2026-10-30
updated: 2026-11-02
scheduled_at: "2026-10-30T14:00:00+03:00"
rubric: gejmdizajn-i-mehaniki
tags: ["kamera", "parallaks", "game-feel", "animaciya", "zvuk"]
reading_time: 10
draft: false
summary: "Плоская 2D-сцена оживает за счёт трёх слоёв отклика: камеры, которая следует за героем плавно и с упреждением, параллакса, при котором дальние слои движутся медленнее ближних, и мгновенной обратной связи на каждое действие — звука, частиц, короткого сжатия спрайта и дозированной тряски. Сглаживание камеры надо считать через экспоненту от шага времени, иначе оно меняется вместе с частотой кадров, а тряску — через убывающую величину trauma, возведённую в квадрат."
---

## Коротко

2D-сцена кажется живой, когда камера следует за героем плавно и смотрит чуть вперёд, фон разделён на слои с разной скоростью движения (параллакс), а каждое действие игрока получает мгновенный отклик: звук, частицы, короткое сжатие спрайта и редкую дозированную тряску. Плавность камеры считается по формуле `1 - exp(-k * dt)`, чтобы она не зависела от частоты кадров, а тряска — через убывающую величину `trauma`, возведённую в квадрат. В статье — формулы, таблицы коэффициентов и проверенный в Node.js код камеры, параллакса, сжатия спрайта и тряски.

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

1. Почему жёстко привязанная камера утомляет
2. Плавное следование камеры, не зависящее от частоты кадров
3. Мёртвая зона и упреждение взгляда
4. Параллакс: коэффициенты слоёв и формула смещения
5. Game Feel: шесть приёмов отклика и их дозировка
6. Тряска камеры через trauma
7. Практический сценарий: камера, параллакс и отклик в коде на JavaScript
8. Когда вам это не подойдёт

## Почему жёстко привязанная камера утомляет

Камера, жёстко прикреплённая к центру персонажа, повторяет каждый пиксель его движения, включая дрожание при приземлении и разворотах, и при этом показывает одинаково мало пространства впереди и позади. Итай Керен в докладе *«Scroll Back: The Theory and Practice of Cameras in Side-Scrollers»* (GDC 2015, источник: GDC Vault, проверено: октябрь 2026) разобрал десятки классических игр и показал, что почти все удачные платформеры используют комбинацию мёртвой зоны, упреждения и сглаживания вместо жёсткой привязки.

## Плавное следование камеры, не зависящее от частоты кадров

Плавная камера на каждом кадре сдвигается на долю расстояния до цели, и эту долю нужно считать от шага времени. Частая ошибка — `cam += (target - cam) * 0.1` в каждом кадре: при `60 к/с` камера догоняет цель вдвое быстрее, чем при `30 к/с`. Правильная формула:

```text
cam = cam + (target - cam) * (1 - exp(-k * dt))
```

Параметр `k` задаёт жёсткость. Время, за которое камера проходит половину оставшегося пути, равно `t_1/2 = ln(2) / k`. При `k = 8` это `87 мс`, при `k = 4` — `173 мс`.

Таблица: Доля пути, проходимая камерой за кадр при k = 8

| Частота | Шаг `dt` | Доля за кадр `1 - exp(-8 * dt)` | Доля за 1 секунду |
|---|---|---|---|
| 60 к/с | 16,67 мс | 12,5% | 99,97% |
| 30 к/с | 33,33 мс | 23,4% | 99,97% |

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

## Мёртвая зона и упреждение взгляда

Мёртвая зона — прямоугольник в центре экрана, внутри которого герой ходит, а камера стоит; упреждение — смещение точки цели камеры вперёд по направлению движения. Для окна `1280×720` рабочие значения: мёртвая зона `160×120` пикселей, упреждение по X — `96–160` пикселей (3–5 клеток по `32`), переход упреждения при развороте — за `300–500 мс`, чтобы экран не дёргался при каждом шаге назад.

Цель камеры с упреждением:

```text
target_x = x_героя + dir * L   (где dir = -1 или +1, L = 128 пикс)
```

По вертикали в платформерах камеру обычно двигают только после приземления на новую высоту (platform snapping), иначе экран качается вверх-вниз на каждом прыжке.

## Параллакс: коэффициенты слоёв и формула смещения

Параллакс — эффект глубины, при котором дальние слои фона смещаются медленнее ближних. Смещение слоя на экране — это смещение камеры, умноженное на коэффициент слоя `p`:

```text
x_экран = x_мир - cam_x * p
```

При `p = 0` слой неподвижен (небо), при `p = 1` движется вместе с игровым миром, при `p > 1` — быстрее (передний план). Многослойный параллакс в аркадах стал узнаваемым с *Moon Patrol* (Irem, 1982 год, источник: каталог *The International Arcade Museum / KLOV*, проверено: октябрь 2026), где три слоя фона двигались с разной скоростью.

Таблица: Рабочая схема коэффициентов параллакса

| Слой | Коэффициент `p` | Смещение при сдвиге камеры на 1000 пикс | Контраст и насыщенность |
|---|---|---|---|
| Небо | 0,0–0,1 | 0–100 пикс | Минимальные |
| Дальние горы | 0,2–0,3 | 200–300 пикс | Низкие, с цветом неба |
| Средний план | 0,5 | 500 пикс | Средние |
| Игровой слой | 1,0 | 1000 пикс | Максимальные, чёткий контур |
| Передний план | 1,1–1,3 | 1100–1300 пикс | Тёмные силуэты, не закрывают героя |

Правило читаемости: чем дальше слой, тем ближе его цвет к цвету неба. Тогда игрок никогда не спутает фоновую скалу с платформой.

## Game Feel: шесть приёмов отклика и их дозировка

Game Feel — это ощущение прямого управления виртуальным объектом, складывающееся из отклика в реальном времени и визуальной полировки (определение Стива Свинка, книга *«Game Feel: A Game Designer's Guide to Virtual Sensation»*, Morgan Kaufmann, 2008 год, проверено: октябрь 2026). Доклад Мартина Йонассона и Петри Пурхо *«Juice it or lose it»* (2012 год) показал, как одна и та же игра-арканоид меняется, если по очереди добавлять к ней звук, частицы, анимацию и тряску.

Таблица: Приёмы отклика и безопасная дозировка

| Приём | Что делает | Рабочая дозировка |
|---|---|---|
| Звук | Подтверждает действие на слух | Каждое значимое действие, вариация высоты тона ±5–10% |
| Частицы | Показывают точку события | 6–20 частиц, жизнь 0,2–0,5 с |
| Сжатие и растяжение | Передают вес и упругость | Приземление: масштаб Y 0,8, X 1,25, возврат за 80–120 мс |
| Пауза при ударе (hit stop) | Подчёркивает силу удара | 2–6 кадров при 60 к/с (33–100 мс) |
| Вспышка | Отмечает получение урона | 1–2 кадра белого цвета |
| Тряска камеры | Сообщает о сильном событии | Амплитуда 8–16 пикс, 0,2–0,4 с, только для редких событий |

Сжатие и растяжение — один из двенадцати принципов анимации студии Disney (Ф. Томас и О. Джонстон, *«The Illusion of Life: Disney Animation»*, 1981 год). Чтобы спрайт не «надувался», произведение масштабов держат равным единице:

```text
sx * sy = 1   →   при sy = 0,8 получаем sx = 1,25
```

## Тряска камеры через trauma

Тряска через trauma — это способ, при котором событие добавляет к переменной `trauma` значение от `0` до `1`, она равномерно убывает со временем, а сила тряски пропорциональна её квадрату. Метод описал Сквиррел Айзерло в докладе *«Math for Game Programmers: Juicing Your Cameras With Math»* (GDC 2016, источник: GDC Vault, проверено: октябрь 2026).

```text
shake    = trauma * trauma
offset_x = A_max * shake * noise(t)
trauma   = max(0, trauma - r * dt)
```

Здесь `A_max = 12` пикселей, `r = 2,5` в секунду (полное затухание от `1` до `0` за `400 мс`), `noise(t)` — шум в диапазоне `[-1, 1]`. Квадрат нужен, чтобы слабые события давали почти незаметную тряску, а сильные — выразительную: `trauma = 0,3` даёт всего `9%` амплитуды, `trauma = 1` — `100%`.

## Практический сценарий: камера, параллакс и отклик в коде на JavaScript

Плавную камеру, слои параллакса, сжатие при приземлении и отключаемую тряску можно проверить без графики: каждая функция возвращает числа, которые легко сравнить с таблицами выше. Код ниже проверен в Node.js 24; комментарии показывают его фактический вывод.

```js
// 1. Плавная камера, не зависящая от частоты кадров
function follow(cam, target, k, dt) {
  return cam + (target - cam) * (1 - Math.exp(-k * dt));
}
function runCamera(fps) {
  let cam = 0;
  for (let i = 0; i < fps; i++) cam = follow(cam, 1000, 8, 1 / fps); // 1 секунда
  return cam.toFixed(2);
}
console.log("за 1 с при 60 и 30 к/с:", runCamera(60), runCamera(30)); // 999.66 999.66

// 2. Параллакс: экранная координата слоя с коэффициентом p
const layers = { sky: 0.1, mountains: 0.3, middle: 0.5, game: 1.0 };
function screenX(worldX, camX, p) { return worldX - camX * p; }
for (const name in layers) console.log(name, screenX(0, 1000, layers[name])); // -100 -300 -500 -1000

// 3. Сжатие при приземлении с сохранением площади: sx * sy = 1
function squash(t, duration) {                 // t — время с момента приземления, с
  const k = Math.min(1, t / duration);
  const sy = 0.8 + (1 - 0.8) * k;              // от 0,8 обратно к 1,0
  return { sx: 1 / sy, sy: sy };
}
console.log(squash(0, 0.1), squash(0.1, 0.1)); // { sx: 1.25, sy: 0.8 } { sx: 1, sy: 1 }

// 4. Тряска через trauma: амплитуда 12 пикс, затухание 2,5 в секунду
let trauma = 0;
const shakeEnabled = true;                     // настройка игрока
function addTrauma(v) { if (shakeEnabled) trauma = Math.min(1, trauma + v); }
function shakeOffset(dt, noise) {
  const offset = 12 * trauma * trauma * noise;
  trauma = Math.max(0, trauma - 2.5 * dt);
  return offset;
}
addTrauma(1);
let frames = 0;
while (trauma > 0) { shakeOffset(1 / 60, 1); frames++; }
console.log("тряска затухла за кадров:", frames); // 25 — около 0,4 с при 60 к/с
```

Дальние горы с `p = 0,3` смещаются втрое медленнее игрового слоя, а сжатие возвращается к `1,0` через `0,1 с`. Флаг `shakeEnabled` стоит вынести в настройки игры: при `false` функция `addTrauma` ничего не делает, и игрок, чувствительный к движению экрана, отключает тряску одним переключателем.

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

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

- **Головоломки и игры на точное прицеливание:** тряска и сжатие мешают считать клетки и траектории; в пошаговых головоломках достаточно звука и подсветки.
- **Игроки, чувствительные к движению экрана:** частая тряска, вспышки и быстрый параллакс могут вызывать дискомфорт — их нужно дозировать и давать отключать.
- **Игры на одном неподвижном экране:** если уровень целиком помещается в окно, как в аркадах конца 1970-х, слежение камеры и параллакс не нужны, а отклик сводится к звуку, частицам и вспышке.

---

Мы разрабатываем **J2DRU** — браузерный 2D игровой движок; он в разработке и публично пока не открыт, заявку можно оставить на [странице раннего доступа](/early-access?utm_source=blog&utm_medium=article&utm_campaign=kamera-parallaks-i-game-feel-v-2d-igre) (подача заявки не гарантирует приглашение).

**Читайте также:**
- [Эволюция 2D-камеры: от одного экрана до скроллинга](/blog/evolyuciya-2d-kamery-ot-odnogo-ekrana-do-skrollinga)
- [Идеальный прыжок и секрет Coyote Time](/blog/idealnyj-pryzhok-i-sekret-coyote-time)
- [Игровой цикл и физика столкновений AABB](/blog/igrovoj-cikl-i-fizika-stolknovenij-aabb)
