Устройство спецэффектов для игр под NES. Часть 2

В этой статье вас ждёт продолжение описания устройства спецэффектов для игр под NES (первая часть здесь). На этот раз будет меньше теории и больше картинок-примеров.

norxk_h3ddqygfxq1es-0uzizqu.gif

Мы рассмотрим группы эффектов, созданные с помощью переключения позиции скролла видеопроцессора, а также пару эффектов, полученных переключением состояния видеопроцессора.

Анимация изменением позиции скролла


Межфреймовая


Самый базовый и очевидный «эффект», создаваемый с помощью изменения позиции скролла — это создание игровой камеры. Он воспринимается как нечто очевидное, однако я поставил бы целый биткоин на то, что вам не удастся правильно реализовать скроллинг с первого раза без единой ошибки.

Рассмотрим несколько вариантов скроллинга в разных играх. Хотя это не очень эффектно, но полезно, чтобы разобраться с тем, что делает видеопроцессор, и поможет понять следующие эффекты.

Как я уже упоминал в первой статье, в адресном пространстве видеопроцессора NES есть четыре экранные страницы, которые содержат символы для отображения. Также видеопроцессор имеет определённую позицию скролла — координаты, с которых он начинает отрисовывать тайлы на экране.

Однако чаще всего содержимое страниц зеркалируется (тут более детальное описание основных типов зеркалирования). Если не углубляться в детали, это означает, что чаще всего игре доступны не четыре, а всего две страницы (а иногда и вообще всего одна).

На скриншоте показан пример скроллинга с горизонтальным зеркалированием страниц из игры Mitsume Ga Tooru.
-o0naud9vrkylz6avrrioqevfwc.png

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

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

Именно поэтому в некоторых играх нельзя возвращаться назад, организовать движение камеры в обе стороны — уже нетривиальная задача для разработчиков.

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

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

Некоторые игры делают в уровнях с высотой более двух экранов «двери» (движок серии Megaman), при входе в которые игра делает небольшую паузу для обновления содержимого экранных страниц.

Другие же исхитряются и кодируют этот эффект программно:
x6qi0ny4pwdlumpgqx-vs_uiela.png

В играх вроде Jungle Book или Hudson«s Adventure Island основной тип скроллинга — горизонтальный, однако игры позволяют также перемещение камеры вверх и вниз, перестраивая верхнюю строку на нижнюю на лету, и организуя, таким образом, поддержку «диагонального» движения камеры.

Чтобы подчеркнуть сложность организации скроллинга в произвольную сторону, можно привести в пример ошибки разработчиков. Например, в игре Little Mermaid при вертикальном скроллинге игра каждый раз «съедает» полблока, которые видны в редакторе игры — т.е. дизайнеры создавали уровни без учёта этой ошибки.

hr6ldh4eyogvtq_c1g6nmpny1_g.png

Она связана с тем, что большинство игр для NES используют блочную систему описания уровней с размером блока, некратным размеру экрана, из-за чего нижняя часть последнего блока при вертикальном скроллинге будет выброшена. Этот эффект виден в игре Tiny Toon Adventures, где разработчики сознательно оставили в неотображаемом блоке мусор:
44lem-7nvsphyblwaai2385cjmy.png

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

Скроллинг в играх с одной экранной страницей
Некоторые мапперы и вовсе содержат всего одну экранную страницу, которая зеркалируется 4 раза. Для организации скроллинга в таких играх разработчики вынуждены были искать способ маскировки артефактов, которые возникают оттого, что правая часть экрана затирает левую.

wziaf1tdiertxajnqpqv_rcfpty.png
В Battletoads игра просто «гасит» луч видеопроцессора в начале вывода строки, чтобы скрыть то, что первые столбцы дублируют те, которые будут выведены после скролла экрана вправо.

g5hwri2nulevx-1mxc8gf0e7mhi.png
В играх Felix The Cat и Tom & Jerry правая часть строк замаскирована чёрными спрайтами, в чём можно убедиться с помощью скрипта отображения номеров спрайтов, описанного в первой части статьи.

Анимация переключением скролла

Возможен также интересный эффект анимации резкой сменой позиции скролла.
Пример такой анимации — второй босс в игре Mitsume Ga Tooru.
9ybqbb9xylzmrfpf07rngbe-u-0.gif

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

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

7huxt0pnzb3vz6jvnbjstzf5xxs.png
Для наглядности можно изменить блок-«индикатор», чтобы посмотреть, как игра при переключении экранных страниц будет изменять его положение:

Более продвинутый пример анимации фона в несколько кадров можно увидеть в игре Bucky O«Hare. В игре есть вращающийся лабиринт

Для его реализации в игре каждый кадр обновляется часть экранной страницы, которой в данный момент нет на экране. Как только экранная страница дорисована, скролл мгновенно «перекидывает» отображение на неё и создаёт эффект поворота комнаты на 90 градусов. После этого игра снова начинает прорисовывать следующий кадр в другой экранной странице.
d-lhe2mwa413e73kmmsi9fiv2ye.png

На скриншоте видна частичная прорисовка кадра в невидимой экранной странице.

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

В итоге получаются красивые большие боссы, например, как в Monster in My Pocket:
qbjw_uka3i622jvcd71zr2w5cds.gif

Или в Chip & Dale 2
tj_45svfz6yfrnpi9setdns2rxk.gif

Здесь видно отличное дизайнерское решение — босс-ведьма появляется только тогда, когда гаснут свечи, и у разработчиков появляется моральное право сделать фон чёрным.

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

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

Мидфреймовая анимация


Если изменять позицию скролла во время отрисовки кадра, возможно разбиение экрана на несколько горизонтальных «полос», движущихся с разной (в том числе нулевой) скоростью. Однако не существует способа менять позицию скролла прямо во время строки без дрожания экрана, поэтому если вы видите, что части строки движутся с разной скоростью, скорее всего, разработчики обманывают ваше зрение с помощью анимацией спрайтами или изменением CHR-банков (примеры в первой части статьи).

На основе движения «полос» экрана с разной скоростью могут быть созданы различные эффекты. Для того, чтобы исследовать такие эффекты, я сделал скрипт для эмулятора Mesen (только он позволяет отслеживать эффекты прямо посреди кадра).

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

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

p5p3qm7wicyjq2l1oimp6vbwpac.gif
Простейший пример — игра Super Mario Bros — верхняя часть экрана остаётся неподвижной. Трюки, которые используются для того, чтобы определить точный период времени, когда нужно изменить позицию скролла, иногда очень хитрые, но чаще всего используются известные Sprite Zero Hit или возможности по отслеживанию номера строки на маппере.

Параллакс
Эффект параллакса позволяет отобразить то, что для наблюдателя находящиеся дальше объекты движутся медленнее, чем более близкие. В консолях следующих поколений специально для реализации этого эффекта имеется возможность рисовать на нескольких слоях, независимых друг от друга, но на NES её нет, поэтому разработчики эмулировали слои за счёт горизонтального скроллинга частей картинки.

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

Простейший пример — бегущий на фоне заката кот-ниндзя из Kyatto Ninden Teyandee.
zim1braj3gn5lcxm_2ucc0620co.gif

Здесь, также как и в Марио, достаточно всего одного разделения экрана на подвижную и неподвижную часть (ну, и второе разделение в зоне GUI, которое встречается почти в каждой игре, про него отдельно упоминать не буду).

Более красивые и сложные примеры:
uiycew3jknh8fhkicyuq9oejryw.gif

Красная планета в Bucky O’Hare. Здесь к статичному небу добавлен слой дальних облаков в небе и более близких гор. Без разделительных линий кажется, что существует ещё слой ландшафта между горами и слоем игрока за счёт того, что он однородный, и глаз не может определить движется ли этот слой или нет.

Есть много игр с примерами параллакса такого типа — Joe & Mac — Caveman Ninja, Totally Rad, Metal Fighter, Vice — Project Doom и другие.
i1q_dpsmqgzp1ztwc628mxrwf0g.gif
jv6sorabo5-idgh0bn_qqfuu_ve.gif

Однако стоит помнить, что если вы видите эффект пересечения слоёв на одной горизонтали (параллакс части фона за окнами в Bucky O’Hare) или вообще вертикальный параллакс (на стенках колодца 2 уровня Battletoads, стартовая заставка Megaman 2), все эти примеры разобраны в первой статье, помните — горизонтальный скролл невозможно изменить посреди строки, в этих играх используются другие эффекты.

Отдельный интересный случай параллакса с движущимся дальним фоном — уровни с движущимся транспортом, несколько примеров:
3dlmh1l0ein7zes_h5u1jgpwthg.gif
Spartan X2
ifixmhyf3_53b84oaqfjvdesvew.gif
Tiny toon 2
norxk_h3ddqygfxq1es-0uzizqu.gif
Batman: Return of the Joker

Параллакс также заметен, если камера находится внутри овального объекта или пещеры. В таком случае нижняя и верхняя часть будут ближе к камере, чем дальняя стена. Лучший пример — турбо-туннель в Battletoads:
twpbnqkmfudum2s8belkmty2_ii.gif
Или Batman: Return of the Joker:
9j1qcbulzuo0hfzomgx-o6hv9oq.gif

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

Посмотрите на количество слоёв пола в TMNT4: Tournament Fighters:
k7fmcsxio6maqhf8riqf7_xpsis.gif
Либо на море в TMNT3: Manhatten Project:
trl9ydsbp4ofmtplvktwpwn9bso.gif
Пол в Battletoads and Double Dragon (предельный случай, отдельный скролл каждой строки):
wiampuwid_u1-4tmrgrhel-bwoo.gif

Отображение движения частей сцены
Данный эффект применяется для отображения крупных частей сцены
hioupccky9day3ec7vxq_ladbdm.gif
Босс в Tiny Toon Adventures
dyj9zjiumlbtd3t_lwwpdeyhxre.gif
jubwwvxsevswdr1vwgpezz9l9_u.gif
Несколько примеров из Bucky O’Hare

Для относительно мелких частей сцены, вплоть до отдельных строк (участки дороги при повороте в Super Spy Hunter):
_rircvpyrbn_5oyx5aiweez0f1s.gif

Для красивого совмещения частей сцены (Versus-экран в TMNT4: Tournament Fighters)
01f8wa2mz4tn_8gvh8h50qmwo1w.gif

А также для отображения полноэкранных паззлов (рулетка в Super Mario Bros. 3):
nxi5_knin9hwdxpqwsd-zposdsw.gif

Участком сцены также может быть крупный объект, который изначально выглядит спрайтом, а не фоном, но является слишком крупным для спрайта, потому что спрайты имеют ограничение на размер, общее количество, а также количество в одной строке. Например, шар у босса зелёной планеты в Bucky O' Hare (да, эта игра вообще очень богата на разные эффекты) рисуется фоном, но двигается отдельно от пола:
zrpejpowkxzfnheigrmrz1nigmu.gif

Демо-эффекты
Часто эффекты раздельного движения слоёв сцены применяются для эффектного появления текста или заставок. Сразу два эффекта на старте Jurassic Park:
gezyzxtqqpymejqj4d_60efnwuo.gif

Эффекты волн в Tmnt 3, Mickey Mouse 3, Mitusme Ga Tooru:
9ndfkrpp7n3ek7ishy6gytgtyle.gif
t2jb1lh4lljiz6vidiiq6-e8y54.gif
wob3gi2p78xpwxbr5a-kniqgalc.gif
И другие подобные.

Изменение вертикальной позиции скролла
Чаще всего используется для создания эффекта опускающегося потолка. Так же, как и для боссов, необходимое условие — чёрный фон, на котором не будет заметно движение всего слоя. Поэтому опускающийся потолок чаще всего встречается в тёмных пещерах:
x3uq9yvzazdionczqrqoom5ymri.gif
Mitsume Ga Tooru
1l1q0bdufeirxaajvilzlnqso4o.gif
Batman: Return of The Joker

Анимация изменением состояния процессора


В дополнение к основным типам анимации, графические эффекты могут создаваться с помощью изменения состояния видеопроцессора. Переключаемые флаги состояния можно посмотреть в документации (например, тут). Сюда относятся: перевод процессора в чёрно-белый режим, смена яркости или изменение адреса активной экранной страницы.
Например, в игре Battletoads интерфейс пользователя отрисовывается в отдельной экранной странице, которая посреди кадра переключается на другую, в которой нарисован сам уровень без интерфейса.

Дополнительные возможности также могут быть добавлены с помощью мапперов. Для примера можно рассмотреть игры Mappy Kids на маппере Namcot 163, который умеет переключает экранные страницы отдельной командой, за счёт чего игра поддерживает режим разделения экрана — во время рендера верхней половины экрана активна одна экранная страница, а во время рендера нижней части экрана — другая.
-z6z98uormo4iykkfv2aktxcz_q.png

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

Теперь можно попробовать запрограммировать какие-либо из этих эффектов, в следующих статьях я попробую показать примеры того, как сделать это на языке C, используя редактор CadEditor для вытаскивания графики и данных из ROM-файлов.

Использованные инструменты

Универсальный редактор уровней CadEditor

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

Скрипты для эмулятора Mesen:
logParallax — отрисовывает линии, на которых игра меняет позицию скролла в ходе отрисовки кадра.

makeScreenshots — по нажатию Q начинает делать скриншоты, повторное нажатие прекращает. Удобно для заготовки картинок и последующем сшивании их в gif-картинки.

modifyScreen — бонусом ещё один скрипт, позволяющий писать «шейдеры» и играться с созданием своих пост-эффектов для эмулятора.
vpezlcmnapxlwlk65vomzqxchau.gif

© Habrahabr.ru