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


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

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


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


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

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

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

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

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


Горизонтальный скроллинг


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

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

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

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

Вертикальный скроллинг


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

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

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


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

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


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


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

Скроллинг в играх с одной экранной страницей


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


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


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

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


Возможен также интересный эффект анимации резкой сменой позиции скролла.
Пример такой анимации – второй босс в игре Mitsume Ga Tooru.


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

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


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


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


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


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

Отрисовка большого объекта в фоне


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

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


Или в Chip & Dale 2


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

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

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

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


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

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

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

Отрисовка GUI


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


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

Параллакс


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

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

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


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

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


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

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



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

Отдельный интересный случай параллакса с движущимся дальним фоном — уровни с движущимся транспортом, несколько примеров:


Spartan X2

Tiny toon 2

Batman: Return of the Joker

Параллакс также заметен, если камера находится внутри овального объекта или пещеры. В таком случае нижняя и верхняя часть будут ближе к камере, чем дальняя стена. Лучший пример — турбо-туннель в Battletoads:


Или Batman: Return of the Joker:


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

Посмотрите на количество слоёв пола в TMNT4: Tournament Fighters:


Либо на море в TMNT3: Manhatten Project:


Пол в Battletoads and Double Dragon (предельный случай, отдельный скролл каждой строки):


Отображение движения частей сцены


Данный эффект применяется для отображения крупных частей сцены


Босс в Tiny Toon Adventures



Несколько примеров из Bucky O'Hare

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


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


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


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


Демо-эффекты


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


Эффекты волн в Tmnt 3, Mickey Mouse 3, Mitusme Ga Tooru:





И другие подобные.

Изменение вертикальной позиции скролла


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


Mitsume Ga Tooru


Batman: Return of The Joker

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


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

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

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


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

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

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


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

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

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

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

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

Комментарии (16)


  1. Bad_proger
    03.05.2018 11:07
    -1

    Понастольгировал. Спасибо.


    1. spiiin Автор
      03.05.2018 11:09
      +1

      Нoстaльгируйте на здоровье. Пожалуйста


      1. Bad_proger
        03.05.2018 11:56
        +1

        За орфографию тоже спасибо


  1. Lord_Ahriman
    03.05.2018 12:28
    +1

    Я правильно понимаю, что именно из-за реализации скролла при игре на Денди, где тайминги отличаются от Famicom и NES, появлялись артефакты (мусор в Eleminator Boat Duel, например, или «дрожание» экрана в Battletoads, или мусорные тайлы в области GUI в некоторых играх)?


    1. spiiin Автор
      03.05.2018 13:00

      Артефакты появляются вроде только если запускать PAL версию игры на денди, в NTSC-версиях всё нормально.
      www.emu-land.net/forum/index.php?topic=78279.0

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

      Для Elimination Boards (версия игра для региона PAL) строки разделения экрана на слои
      в режиме PAL:


      в режиме Dendy (сбиты тайминги рассчёта строк, на которых надо разделять экран и тайминг переключения банка памяти с графики GUI на банк с графикой облаков):


      1. Lord_Ahriman
        03.05.2018 17:12

        Спасибо за исчерпывающий ответ!
        Но глюки есть и в NTSC-играх. Я два дня назад перепроходил первые TMNT (U-ROM) с флэш-картриджа на Junior I с UM6561F. Периодически на верхней границе игрового экрана и там же, сверху, в экране паузы, возникала тайловая каша. Появлялось это тогда, когда на экране много объектов (например. огненные монстры выпустили много огней и летят «летучие мыши» из этого набора врагов) и экран сдвигается вверх или вниз (лезем по лестнице, к примеру). Насколько помню, было такое и в моем детстве, только версия игры японская была. На оригинальном Famicom этот же картридж с этим же ромом такого не выдает.


        1. spiiin Автор
          03.05.2018 17:38

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


        1. ZurgInq
          03.05.2018 20:43

          Бак с мерцающими многими объектами больше похож на железное ограничение, не более 5 (или сколько там было) спрайтов на одной линии.


          1. Lord_Ahriman
            04.05.2018 12:45

            Это я знаю, он хорошо в Contra Force заметен, да и в TMNT1. Но я говорю не о мерцании спрайтов при превышении лимита, а именно о возникновении мусора в области скролла при большом количестве спрайтов на экране.


          1. spiiin Автор
            04.05.2018 14:34

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

            Каша из тайлов вызывается сбитыми таймингами — где-то в коде игры предполагается, что видеопроцессор находится в определённом месте кадра, а это почему-то не так. Отличий в таймингах денди от других режимов много -https://wiki.nesdev.com/w/index.php/Clock_rate, точно я не возьмусь предположить, что именно вызывает отличия, вполне возможно, что это связано с Time during which OAM can be written (это как раз время, за которое игра должна успеть записать данные о всех спрайтах на экране).


  1. erondondon
    03.05.2018 17:24
    -1

    Лампово.


  1. TriBar
    03.05.2018 18:24

    Огромное спасибо за цикл статей! Читаю с удовольствием.
    Хотелось бы еще узнать, каким образом был реализован эффект трассы во всех гонках с видом из кабины/сзади? Например, Rad Racer.


    1. spiiin Автор
      03.05.2018 18:29
      +1

      Таким же способом, как и в Super Spy Hunter, отдельный скроллинг каждой линии.

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


  1. alexxz
    04.05.2018 10:43
    +1

    Спасибо за великолепный цикл статей. Особенно доставляло мерцание спрайтов в детстве. Я всё на картридж грешил, мол контакты плохие или ещё что. Теперь, когда стал понимать, как отрисованы картинки, стал лучше понимать, откуда эти рудименты. Большинство вызвано ограничением числа спрайтов на линию. Однако некоторые мерцания остались для меня загадкой. Например:
    image
    Из-за чего имена полосок индиакторов мерцают?

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


    1. Lord_Ahriman
      04.05.2018 12:43

      Во FCEUX лимит спрайтов отключается в секции Config>Video>Allow more than 8 sprites per scanline.
      В Nestopia отключается по Shift+U.
      В остальных эмуляторах не помню, но даже в JNes такая опция была, поищите.


    1. spiiin Автор
      04.05.2018 12:53

      Из-за чего имена полосок индиакторов мерцают?

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

      Аппаратных причин для этого никаких нет. То, что этот спрайт выводится через кадр просто прописано в коде игры. Разработчики, скорее всего, случайно сделали вывод его той же функцией, которой рендерятся снаряды — там как раз программный вывод через кадр оправдан, чтобы показывать более 8 снарядов в линию (на чётных кадрах выводится одна половина снарядов, на нечётных – другая). Проверю внимательнее к следующей статье.