Эволюция 2D-камеры: от одного экрана Space Invaders и Defender до скроллинга Super Mario Bros. и The Legend of Zelda

Коротко

Первые 2D-аркады помещались на одном неподвижном экране, потому что процессоры конца 1970-х годов не успевали перерисовывать тысячи байт фона 60 раз в секунду. Когда миры стали шире экрана, разработчики изобрели три фундаментальные модели камеры: скоростное упреждение по курсу корабля с верхней миникартой-радаром в Defender (1981), односторонний аппаратный скроллинг через регистр PPUSCROLL в Super Mario Bros. (1985) и покомнатное переключение экранов 16 × 11 тайлов в The Legend of Zelda (1986). В статье разобрано аппаратное устройство этих трёх решений по материалам исследования Итая Керена (GDC 2015) и документации NESdev, приведены формулы каждой камеры и проверенный в Node.js код покомнатной и односторонней камеры.

Содержание

  1. Один неподвижный экран: почему Space Invaders (1978) не могла двигать камеру
  2. Defender (1981): выход за границы экрана, камера с упреждением и радар
  3. Super Mario Bros. (1985): регистр PPUSCROLL и почему Марио не может пойти назад
  4. The Legend of Zelda (1986): дискретная сетка комнат 16×11 тайлов
  5. Практический сценарий: переключение комнат и односторонняя камера на JavaScript
  6. Когда вам это не подойдёт

Один неподвижный экран: почему 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-миром:

  1. Смещение камеры в сторону полёта (Camera Look-Ahead): если держать быстро летящий истребитель строго по центру экрана (160; 128), у игрока остаётся всего 160 пикселей обзора впереди — на высокой скорости вражеский снаряд прилетает быстрее времени реакции человека. Поэтому при полёте вправо камера Defender прижимает корабль к левой четверти экрана (X ≈ 64..80 пикс), отдавая 75% ширины монитора (240 пикселей) под обзор впереди по курсу. При развороте корабля влево камера переезжает так, чтобы корабль оказался у правого края:
targetCameraX = shipX + shipDirection * lookAheadOffset
  1. Двухуровневое зрение (основной вид + радар): поскольку игрок видел только 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
Сравнение трёх классических архитектур 2D-камеры для выбора под свою игру
Архитектура камерыИсторический эталонФормула координаты камеры 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 игровой движок; он в разработке и публично пока не открыт, заявку можно оставить на странице раннего доступа (подача заявки не гарантирует приглашение).

Читайте также:

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

Почему в первых аркадах вроде Space Invaders экран вообще не двигался?

В автомате Space Invaders (1978) не было аппаратного регистра сдвига фона — видеопамять объёмом 7 КБ хранила битовую карту 224×256 пикселей, и чтобы сдвинуть весь экран на 1 пиксель, процессору Intel 8080 на частоте 2 МГц пришлось бы перезаписывать 7168 байт в каждом кадре.

Почему в первой Super Mario Bros. (1985) нельзя вернуться по уровню влево?

У консоли NES/Famicom было всего 2 КБ оперативной памяти и видеопамять на два экрана тайлов (два nametable по 256×240 пикселей). Игра подгружала новые столбцы уровня справа по мере движения и не хранила в памяти состояние разрушенных кирпичей и сбитых врагов слева за кадром.

Зачем в The Legend of Zelda (1986) мир разбили на отдельные комнаты вместо плавной прокрутки?

Дискретные комнаты размером 16×11 мета-тайлов (256×176 пикселей игрового поля плюс 64 пикселя панели интерфейса сверху) превратили каждый экран в отдельную тактическую загадку с собственным набором врагов, секретов и дверей.

Какую схему камеры выбрать для своей 2D-игры?

Для скоростных раннеров и классических аркад подходит односторонний скроллинг (камера не возвращается назад), для головоломок и подземелий — переключение комнат по сетке, а для исследовательских платформеров — свободное слежение камеры с границами уровня.