Balloon Fight: перенос с VS system на NES

Предисловие

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

Вообще меня очень увлекает история аркадных автоматов, консолей, игр, и немножко программирование. О том, как программируют для NES в наши дни, я писал в другой «making of» статье, которую также публиковали на Хабре.

Сегодня я хотел бы попробовать запостить материал самостоятельно, и речь пойдет обо всём перечисленном сразу, и об аркадных автоматах, и о NES и о ретроиграх и об их отладке.

Игровые автоматы

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

Buck Rogers: Planet of Zoom (Sega Z80-3D System) и его ремейк (БК 0010-01)Buck Rogers: Planet of Zoom (Sega Z80–3D System) и его ремейк (БК 0010–01)

Примеров прямого портирования и заимствований множество, поскреби игру для любимого ZX Spectrum или БК0010, и вполне может обнаружиться официальный или неофициальный порт, либо полное или частичное заимствование из аркадной игры. Современные студии видеоигр также черпали вдохновение у аркад (напр. Zuma Deluxe от Popcap games — это аркадная Puzz Loop). Символы, узнаваемые сегодня для многих, пришли с аркадных автоматов (пришелец из Space invaders, предок шутеров). Начало многим жанрам видеоигр было положено на аркадных автоматах, пожалуй, исключая те, которые вообще не вписывались в концепцию аркадного автомата. Например, адвентюры и квесты. Автомат должен был заставить игрока побыстрее расстаться с монетой, через это игры на аркадах были в основном хардкорные по своей сложности, в отличие от своих портов на домашние игровые и неигровые системы.

R-Type (Irem M72) и его порт для ZX SpectrumR-Type (Irem M72) и его порт для ZX Spectrum

Аркады сегодня

На данный момент аркадных автоматов сохранилось не так много по очевидным причинам. Собирали их небольшими тиражами. Кроме того, площадь «музея» для коллекционера кабинетов будет стоить денег, а в квартире не поставишь десяток уникальных игр. Поэтому в качестве альтернативы можно использовать эмулятор MAME, поддерживаемый своим сообществом. В числе прочего, аркадам свойственна одна сложность — они собирались на базе самого разнообразного железа, и воткнуть туда могли что угодно. Если у вашего ZX Spectrum всего один Z80, и вы умеете разрабатывать для ZX, то, вероятно, ваших знаний на аркадном поле боя хватит только лишь на то, чтобы управлять музыкальным чипом, которых могло быть два, три, или не быть вовсе, а вместо него — бипер, а главный cpu, скажем, 6809. Вывод — тоже не везде одинаковый, бывали и векторные экраны, и растровые, и с высоким и с низким разрешением, короче говоря, аркады изнутри — это так круто, что эмуляция части автоматов, так и осталась тайной, над разгадкой которой бьются лучшие программисты эмуляторов. Попадались аркады на базе ZX Spectrum, причем один из них — откровенный лохотрон, кажется, он назывался «Тараканьи бега». Известны аркады на базе NES, в общем, аркадный автомат — это солянка процессоров и других устройств, и некоторые из них не документированы до сих пор. Аркадные автоматы — это тема, о которой нужно говорить отдельно и развернуто, а пока чуть передвинемся во времени.

Dendy

«Все любят Денди»: так нас знакомили с этой консолью 30 лет назад. Не знаю, есть ли смысл рассказывать что такое Dendy для тех, кого интересуют хэштеги статьи, поэтому не буду углубляться в историю этой консоли. Могу лишь уточнить, что работала консоль на базе процессора 6502 с некоторыми отсутствующими фичами, а графикой управлял PPU, позволяющий одновременно отображать 13 цветов одновременно на слое «задника», помимо которого Dendy имела «слой» спрайтов. Всё это было приправлено аппаратным скроллингом, неплохим звуком, суровым контролем качества со стороны Nintendo, профессиональным подходом к созданию саундтреков и графики для «задников». Игры для Dendy были аддиктивные, кстати, в дальнейшем я буду называть консоль её «американским именем» «NES». И, как и всякому ретро фанату, который предпочитает не задерживаться на одном процессоре, рано или поздно станут интересны аркадные автоматы, и одним из них стал я.

Contra (NES)Contra (NES)

Помимо других хитовых NES игр для двух игроков одновременно (Contra, Battle city), была довольно популярна ещё одна игра.

Balloon Fight

Balloon fight встречалась многим, кто застал эпоху NES, поскольку в некоторых странах (в частности, в России и Польше) игры распространялись с китайского рынка. Это были «палёные» картриджи, на которых китайские хакеры распространяли игры по вменяемым для российского рынка ценам.

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

Уже можно догадаться, эта игра пришла на NES с аркадных автоматов. Также она существовала в виде Game & Watch, была портирована на другие платформы (Gamecube, PC-88, MSX). Геймдизайнером этой игры был Ёсио Сакамото, в 1984 году её программировал Ивата Сатору для аркадного автомата VS system на базе NES. Это была типичная аркадная «царь горы», в которой игроку предлагалось управлять «истребителями», подвешенными к двум воздушным шарам, используемым в качестве средства передвижения. Бой происходил в воздухе, поэтому условием победы являлось лишение шаров остальных игроков, управляемых процессором. Враги так же имели способность летать, причем довольно неплохо, и лопать шары «истребителей». Пролетая ближе к поверхности моря, игрок (и враги) рисковали быть атакованными морским чудовищем, которое немедленно отнимало жизнь, будучи произведенным успешно.

Как и в случае с многими другими автоматами, этот VS system был сделан в аркадном стиле «не как все»: он имел два экрана, 4 джойстика и два процессора 6502, которые делили между собой небольшое общее ОЗУ для обмена данными об одновременной игре первого и второго игроков. Таких dual автоматов было два: Balloon fight и Wrecking crew. Также в один «неофициальный» кабинет Super Mario был добавлен Z80.

Теперь представьте, что вы играете вдвоём, но каждый на своём экране. Ваши персонажи синхронизированы, то есть первый игрок видит персонажа второго игрока на своём экране ровно с таким же поведением, которое ему задал со своего контроллера второй игрок, и наоборот, одним словом, это как «Танчики» («Battle city»), только наверное круче, когда имеешь всё своё. Добавьте сюда возможность настроить игру, щёлкая DIP переключателями, стоимость игры (в монетах), для 1984 года это было неплохо.

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

NES VS SYSTEM: графика

Владельцам NES эта игра знакома как одноэкранка, то есть, игра со статическим игровым 2D пространством, без скроллинга, яркий пример — Battle city. В официальной NES версии сцена так же расположилась на один экран.

Balloon fight, лицензионная NES версияBalloon fight, лицензионная NES версия

У аркадного автомата же высота игрового поля была равна двум игровым экранам, а текущую сцену автомат отображал при помощи скроллинга, имитирующего камеру.

Игровое двухэкранное поле Balloon fight для VS systemИгровое двухэкранное поле Balloon fight для VS system

Каждый процессор VS system имел по своему личному PPU аж с двумя 8 килобайтными страничками тайловой графики. Для сравнения, у Super Mario 2 и Battle city одна 8к страничка.

Засчёт этого, заставка аркадной версии использовала более богатую уникальными тайлами графику, в отличие от NES.

Титульный экран Ballon fight для NESТитульный экран Ballon fight для NES Титульный экран Balloon fight для VS system Титульный экран Balloon fight для VS system

Поскольку «базовая» конфигурация (NROM) картриджа NES имеет всего одну страничку графики, я решил использовать маппер CNROM на дискретной логике, позволяющий использовать 4 страницы графики. Две из них сохранили своё прежнее назначение, одна была использована на дополнительные нужды. Размер PRG (ПЗУ для кода) остался прежним — 32 килобайта.

Каждый PPU аркадного автомата имел также два дополнительных (итого четыре, в отличие от двух на NES) килобайта VRAM, для отрисовки игрового пространства в ещё две экранные страницы PPU, которых «не хватает» на NES. Аркадная версия использовала всего два килобайта VRAM, поэтому проблем при портировании не возникло.

Последний шар аркадной бонусной игры имел табличку «end» и всякий раз разную высоту труб.

В NES версии задник всех бонус уровней одинаковыйВ NES версии задник всех бонус уровней одинаковыйАркадная версия игры расставляла разные трубы для каждой бонусной игрыАркадная версия игры расставляла разные трубы для каждой бонусной игры

Геймплей

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

Аркадная игра имела больше уникальных уровней. На обеих системах уровни зацикливались.

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

Только консольная версия имеет режим «Balloon trip», по сути отдельная мини игра с горизонтальным скроллингом. У меня была мысль поддержать этот режим и для порта, но я решил не усложнять маппер, кроме того, в PRG оставалось критически мало места, а для «trip» режима пришлось бы значительно переписывать код вывода и скроллинга уровня.

Анимация врагов перед тем, как они начнут заново накачивать шары (поворот головы вправо-влево), присутствует только в аркадной версии.

Звук и прочее

Аркадная «Balloon fight» имела дополнительный трек для экрана с вводом имени в таблицу рекордов, а также трек для начала второго и последующих уровней. Для старта первого уровня был предусмотрен отдельный джингл. В NES версии (официальной) ни таблицы рекордов, ни этих двух треков не было. Также в NES версии при коллизии игрока с бонусным мыльным пузырём использовался более короткий шумовой эффект, чем при уничтожении шаров противника. Я поправил этот недочет, и теперь порт NES лопает мыльные пузыри более реалистично. Также NES версия имела обрезанный вдвое трек «game over», и, вероятно, при портировании/редактировании, этот трек обрёл резкий треск на последней ноте шумового канала.

Два процессора аркадного автомата обменивались данными при помощи дополнительного общего ОЗУ, а чтобы не наделать ошибок, синхронизировались между собой, передавая доступ к этому ОЗУ друг другу по очереди. Замечено, в MAME этот обмен данными почему-то эмулируется с ошибкой, либо что-то не то с дампами игры, но управление второго игрока на второстепенной «консоли» работает с рассинхроном, или есть другая причина для этого рассинхрона. Ошибка замечена только в Balloon fight, эмуляция кабинета Wrecking crew работает нормально. Возможно, что эмуляция точная, но это не точно.

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

Два DIP переключателя контролировали параметры игры:

  • цена одного сеанса игры в монетах, либо количество сеансов за одну монету;

  • сложность игры;

  • количество жизней персонажа;

  • скорость регенерации и передвижения врагов;

  • количество очков, необходимых для получения дополнительной жизни.

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

19e9d40699a46ba712cbe4b629b4e5a3.png

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

Итак, первый DIP контролировал 3 бита значения цены сеанса игры. Второй — всё остальное. Я поддержал работу только второго DIP«а, цена игры (которая кодировалась первым DIP«ом) в портированной версии всегда равна одной монете за игру. Монеты начисляются кнопкой select.

Также я добавил дополнительный однобитовый переключатель «A/B mode». Дело в том, что игры на аркадных автоматах не всегда давали игроку функцию автоповтора кнопок A и B. Turbo кнопки, которыми владели Dendy, являясь по сути своей, нелицензионными клонами NES, были бесполезными, поскольку не поднимали игрока в воздух вообще. Поэтому я реализовал эту возможность опциональной, предусмотрев управление как в лицензионной версии для NES, где функция «rapid» была предусмотрена. Я предпочитаю играть в аркадном режиме.

Активация DIP меню оформлена пасхалкой, также имеется и вторая пасхалка.

Пасхалок от авторов я либо ещё не нашёл, либо, и что скорее всего, они отсутствуют.

Чтобы понять как работает игра, мне пришлось дизассемблировать её, и, пересобрав, попробовать запустить в эмуляторе NES. Конечно, в силу особенностей железа, код запустился не сразу, и не сразу должным образом. У аркадного автомата были предусмотрены пользовательские прерывания, я же не имел возможности ими пользоваться, в силу того, что использовал простой маппер CNROM.

В процессе работы над дизассемблированным текстом я сделал и код и данные релоцируемыми, в оригинале же некоторый код был жестко приколочен к своим адресным пространствам. В оригинальном ROM«е управление первого игрока было запараллелено на второго, поэтому я разделил управление, и добился корректной работы режима с двумя игроками, но тут возникла проблема. Если за одним экраном будут играть два игрока, то за чьим персонажем должна следить камера? А камера следила за «первичным» игроком. Консольная же версия игры, являясь одноэкранной, от камеры не страдала.

Напомню, что раздельные экраны VS system dual эту проблему решали. По всей видимости это и стало причиной для снабжения автомата дополнительными CPU, PPU и дисплеями, ведь здесь вполне могли подгонять железо под код игры, чем наоборот, при консольном подходе. Так, мне пришлось отключить поддержку второго игрока.

Lobby экран VS systemLobby экран VS systemLobby экран NES портLobby экран NES порт

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

31da8b32788339f303b40cb107c0060a.png

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

Также мне пришлось отключить опрос монетоприемников и передать функцию приёма монеты кнопке select.

eda5f442b3a1595690fcbf8933bcdb99.png

Код, как и код многих игр, не самый аккуратный. Была встречена ошибка очистки общего ОЗУ при рестарте консоли. Неправильный бранч (BPL) не выполнял цикл. Его можно было бы поправить на BNE, но CNROM не имеет дополнительного ОЗУ в этом адресном диапазоне, и, как я уже отмечал выше, любые обращения к этому участку ОЗУ пришлось отключить.

Музыкально/звуковой движок игры довольно простой, и хранит мелодии в виде массивов нот и дополнительных для них параметров.

В заключении ещё раз вкратце приведу список изменений игры после порта с аркадного автомата на NES.

  1. Доступ к DIP переключателям в портированной версии был перенесён в другое место.

  2. Игра стала исключительно однопользовательской.

  3. Добавлена возможность «автоповтора» одной из кнопок джойстика для облегчения игры на консоли.

  4. Добавлен дополнительный звук для «хлопанья» вражеских шаров.

Это и многое другое найдёте в исходниках и скомпилированном ROM файле в моих githubрепозиториях.

© Habrahabr.ru