Коротко
Первые 2D-аркады помещались на одном неподвижном экране, потому что процессоры конца 1970-х годов не успевали перерисовывать тысячи байт фона 60 раз в секунду. Когда миры стали шире экрана, разработчики изобрели три фундаментальные модели камеры: скоростное упреждение по курсу корабля с верхней миникартой-радаром в Defender (1981), односторонний аппаратный скроллинг через регистр PPUSCROLL в Super Mario Bros. (1985) и покомнатное переключение экранов 16 × 11 тайлов в The Legend of Zelda (1986). В статье разобрано аппаратное устройство этих трёх решений по материалам исследования Итая Керена (GDC 2015) и документации NESdev, приведены формулы каждой камеры и проверенный в Node.js код покомнатной и односторонней камеры.
Содержание
- Один неподвижный экран: почему Space Invaders (1978) не могла двигать камеру
- Defender (1981): выход за границы экрана, камера с упреждением и радар
- Super Mario Bros. (1985): регистр PPUSCROLL и почему Марио не может пойти назад
- The Legend of Zelda (1986): дискретная сетка комнат 16×11 тайлов
- Практический сценарий: переключение комнат и односторонняя камера на JavaScript
- Когда вам это не подойдёт
Один неподвижный экран: почему Space Invaders (1978) не могла двигать камеру
В аркадах конца 1970-х годов — Pong (1972), Breakout (1976) и Space Invaders (Taito, конструктор Томохиро Нисикадо, 1978 год) — камера была жёстко прибита к одной позиции: весь игровой мир совпадал с размерами телевизионного кинескопа.
Причина была чисто аппаратной. В автомате Space Invaders центральный процессор Intel 8080 на тактовой частоте 2 МГц работал с кадровым буфером объёмом 7 КБ (7168 байт), который отображал монохромную растровую сетку 224 × 256 пикселей (по 8 однобитных пикселей в каждом байте; источник: техническая схема автомата Taito Space Invaders Maintenance Manual, 1978 год, проверено: октябрь 2026). У видеосхемы не было ни аппаратных спрайтов, ни регистра сдвига фона:
- Даже чтобы сдвинуть
55инопланетян, процессор перерисовывал только по одному пришельцу за кадр (1/60с) — поэтому полный шаг строя из55врагов занимал почти секунду, а по мере уничтожения врагов оставшиеся двигались всё быстрее; - Если бы игра попыталась сдвинуть весь фон на
1пиксель в сторону, процессору пришлось бы копировать все7168байт в каждом кадре (7168 × 60 = 430 080байт в секунду), на что тактовой частоты2 МГцфизически не хватало.
Defender (1981): выход за границы экрана, камера с упреждением и радар
В феврале 1981 года Юджин Джарвис и студия Williams Electronics выпустили космический шутер Defender, который разорвал рамки одного экрана: действие разворачивалось над поверхностью планеты на горизонтальной ленте шириной 2048 мировых единиц — примерно в 6,4 раза шире видимого окна 320 × 256 пикселей, замкнутой в кольцо.
Как показал исследователь геймдизайна Итай Керен в своём историческом докладе на конференции GDC 2015 («Scroll Back: The Theory and Practice of Cameras in Side-Scrollers», Game Developers Conference, март 2015 года, проверено: октябрь 2026), в Defender впервые появились сразу два приёма работы с широким 2D-миром:
- Смещение камеры в сторону полёта (Camera Look-Ahead): если держать быстро летящий истребитель строго по центру экрана
(160; 128), у игрока остаётся всего160пикселей обзора впереди — на высокой скорости вражеский снаряд прилетает быстрее времени реакции человека. Поэтому при полёте вправо камера Defender прижимает корабль к левой четверти экрана (X ≈ 64..80пикс), отдавая75%ширины монитора (240пикселей) под обзор впереди по курсу. При развороте корабля влево камера переезжает так, чтобы корабль оказался у правого края:
targetCameraX = shipX + shipDirection * lookAheadOffset
- Двухуровневое зрение (основной вид + радар): поскольку игрок видел только
15%ширины планеты в конкретный момент, верхние32пикселя экрана занял сканер-миникарта (Radar), показывавший положение всех похитителей и астронавтов на всём кольце планеты сразу.
Super Mario Bros. (1985): регистр PPUSCROLL и почему Марио не может пойти назад
В сентябре 1985 года Сигэру Миямото, Такаси Тэдзука и ведущий программист Тосихико Накаго выпустили Super Mario Bros. для консоли Famicom / NES. Чтобы плавно прокручивать длинные уровни на частоте 60 к/с при крошечном объёме оперативной памяти (2 КБ основной RAM и 2 КБ видеопамяти VRAM), игра опиралась на аппаратное устройство видеопроцессора Ricoh 2C02 (PPU).
По технической документации архитектуры NES (справочник NESdev Wiki: PPU scrolling и регистр PPUSCROLL 0x2005, проверено: октябрь 2026), видеопамять консоли хранила одновременно ровно две экранные таблицы фоновых тайлов (Nametables), каждая размером 32 × 30 тайлов по 8×8 пикселей (256 × 240 пикселей):
- Чтобы сдвинуть весь фон на экране на любое число пикселей от
0до255по горизонтали, процессору больше не нужно было копировать тысячи байт — достаточно было один раз за кадр записать два байта смещения(scrollX, scrollY)в аппаратный регистрPPUSCROLLпо адресу0x2005; - Пока камера плавно двигалась вправо по первому экрану (
Nametable A), игра незаметно за правым обрезом телевизора дописывала в видеопамять по одному новому вертикальному столбцу из16×16мета-тайлов во второй экран (Nametable B).
Именно из экономии 2 КБ оперативной памяти родилось знаменитое правило камеры Super Mario Bros. — односторонний храповик (One-Way Camera Lock):
- Консоль не могла хранить в памяти изменённое состояние всего пройденного уровня (какие кирпичи уже разбиты, какие монеты собраны, какие грибы сбиты позади игрока) и не имела буфера для подгрузки столбцов слева;
- Поэтому координата левого края камеры
cameraLeftXмогла только расти и никогда не уменьшалась:
// Когда Марио переходит середину экрана, он толкает камеру вправо:
newCameraLeftX = playerX - 128
// Храповик: камера никогда не сдвигается назад влево
cameraLeftX = max(cameraLeftX, newCameraLeftX)
// Левый край экрана служит невидимой стеной для самого игрока:
playerX = max(playerX, cameraLeftX + 8)
Это техническое ограничение 1985 года стало приёмом геймдизайна: односторонняя камера задаёт постоянный темп движения вперёд и используется в современных аркадах, раннерах и скролл-шутерах.
The Legend of Zelda (1986): дискретная сетка комнат 16×11 тайлов
Через пять месяцев после Super Mario Bros., в феврале 1986 года, та же команда Nintendo выпустила The Legend of Zelda, где для исследования большого нелинейного мира применила противоположную архитектуру камеры — дискретное переключение комнат (Room Switching / Screen-by-Screen Flip).
Верхний мир игры (Overworld) представляет собой прямоугольную таблицу из 16 × 8 = 128 отдельных экранов-комнат. Каждый экран разбит следующим образом:
- Верхние
64пикселя высоты (256 × 64) занимает неподвижная панель интерфейса (карта, инвентарь и сердечки жизни); - Оставшиеся
256 × 176пикселей образуют игровое поле комнаты, выложенное сеткой ровно из16 × 11мета-тайлов размером16×16пикселей каждый (16 × 16 = 256пикс по ширине,11 × 16 = 176пикс по высоте).
Пока Линк ходит внутри одной комнаты (roomCol, roomRow), камера абсолютно неподвижна. Как только координаты героя выходят за границу 256 × 176, игра вычисляет индекс новой комнаты и переводит камеру ровно на один экран в сторону перехода:
roomCol = floor(playerX / roomWidth)
roomRow = floor(playerY / roomHeight)
targetCameraX = roomCol * roomWidth + roomWidth / 2
targetCameraY = roomRow * roomHeight + roomHeight / 2
| Архитектура камеры | Исторический эталон | Формула координаты камеры camX | Когда выбирать в своей 2D-игре |
|---|---|---|---|
| Односторонний храповик (только вперёд) | Super Mario Bros. (1985) | camX = max(camX, playerX) | Динамичные аркады, линейные уровни на время, горизонтальные и вертикальные скролл-шутеры |
| Свободное слежение с упреждением | Defender (1981), Sonic (1991) | camX = lerp(camX, playerX + dir * offset, t) | Просторные исследовательские платформеры, гонки, полёты с возвратом по карте |
| Дискретные комнаты по сетке | The Legend of Zelda (1986), Celeste (2018) | camX = floor(playerX / W) * W + W / 2 | Приключения с видом сверху, покомнатные головоломки, хардкорные платформеры с перезапуском одной комнаты |
Заметьте: вышедший в 2018 году платформер Celeste тоже построен по принципу отдельных комнат The Legend of Zelda — каждый экран является самостоятельным испытанием, при входе в которое камера плавно переезжает на координаты нового зала и фиксируется по его краям.
Практический сценарий: переключение комнат и односторонняя камера на JavaScript
Покомнатная камера в духе The Legend of Zelda и Celeste и односторонний храповик в духе Super Mario Bros. для окна 1280 × 720 укладываются в две короткие функции на JavaScript. Код ниже проверен в Node.js 24; комментарии показывают его фактический вывод.
const VIEW_W = 1280, VIEW_H = 720;
// 1. Покомнатная камера (Zelda, Celeste): центр комнаты, в которой стоит игрок
function roomCamera(playerX, playerY) {
const roomCol = Math.floor(playerX / VIEW_W);
const roomRow = Math.floor(playerY / VIEW_H);
return { x: roomCol * VIEW_W + VIEW_W / 2, y: roomRow * VIEW_H + VIEW_H / 2, roomCol: roomCol };
}
console.log(roomCamera(1270, 400)); // { x: 640, y: 360, roomCol: 0 }
console.log(roomCamera(1290, 400)); // { x: 1920, y: 360, roomCol: 1 }
// 2. Односторонняя камера (Super Mario Bros.): центр камеры только растёт,
// левый край окна — невидимая стена для игрока с отступом 16 пикс
function createRatchet() { return { camX: VIEW_W / 2 }; }
function updateRatchet(cam, player) {
cam.camX = Math.max(cam.camX, player.x);
const leftWall = cam.camX - VIEW_W / 2 + 16;
if (player.x < leftWall) player.x = leftWall;
}
const cam = createRatchet(), player = { x: 100 };
for (const x of [500, 900, 1500, 1200, 300]) { player.x = x; updateRatchet(cam, player); }
console.log(cam.camX, player.x); // 1500 876 — назад дальше левого края окна не пройти
Переход через отметку X = 1280 переключает камеру с центра 640 на центр второй комнаты 1920, а храповик после рывка до X = 1500 не пускает игрока левее 876 пикселей. В покомнатном режиме при смене комнаты стоит сохранять точку возрождения у входа, чтобы после ошибки игрок перезапускал только текущий зал.
Когда вам это не подойдёт
Исторические режимы жёсткой односторонней или покомнатной камеры подходят не каждой игре:
- Метроидвании и квесты с постоянным возвратом за секретами: если заблокировать возврат камеры влево по схеме Super Mario Bros., игрок не сможет вернуться к развилке или запертому сундуку — там нужна двунаправленная камера.
- Сверхскоростные полёты и гонки при покомнатном делении: если корабль летит со скоростью
800 пикс/с, он будет пересекать комнату шириной1280пикселей каждые1,6 секунды, и постоянные переключения экранов утомят глаза — для высоких скоростей нужна плавная камера с упреждением по схеме Defender. - Игры на одном экране: если поле целиком помещается в окно, как в Space Invaders, камера не нужна вовсе — любая из трёх схем только добавит код.
Мы разрабатываем J2DRU — браузерный 2D игровой движок; он в разработке и публично пока не открыт, заявку можно оставить на странице раннего доступа (подача заявки не гарантирует приглашение).
Читайте также: