Как нарисовать денди

Обновлено: 06.07.2024

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

Хотите написать игру или демо для NES, Famicom, Денди?

Изучаем. Кладезь актуальной мудрости — NesDev Wiki. Вводные для начинающих — Nerdy Nights на английском, другая на русском. Помним, что старые описания неполны и неточны. Отдельно изучаем 6502. Книг и статей много, поиск начинаем отсюда.

Выбираем между ассемблером и C. Тысяча игр на ассемблере, десятки на C. Код на ассемблере в разы эффективнее, на C пишется в разы быстрее. С ассемлером проще получить помощь зала. Для отчаянных есть экзотика, от BASIC до минимальных Lisp и Python.

Выбираем ассемблер. Три популярных, десятки других. NESASM стар, имеет искусственные ограничения (пришёл с MS-DOS, перепилен с PCE/TG16) и мелкие глюки. Легко освоить, большинство старых уроков под него, выдержит средний проект. Современная альтернатива — ASM6, прост в освоении, но не так популярен. Выбор профессионала — CA65. Мощен и гибок, но сложен в освоении (линкер и конфигурация памяти).

Выбираем компилятор C — CC65. Для работы с железом есть библиотеки neslib и KNES, либо пишем свою. По скорости потолок чистого C — подобие Super Mario Bros. Можно писать частично на C, частично на ассемблере, переписывать фрагменты кода по ходу дела. Очень удобно для прототипирования.

Пишем код. Любимый текстовый редактор, bat или make файлы. Есть развитая IDE для CC65 — NESICIDE, но WIP и почти никем не используется.

Рисуем. Отдельные тайлы редактируем непосредственно в YY-CHR, NES Screen Tool, Tile Layer Pro и других, более сложные изображения импортируем из обычных форматов там же. Для сложных проектов может понадобиться свой велосипед. Без трюков NES не может отобразить полноценную картинку на весь экран, аналога Art Studio не ищите.

Музыка и звуки. Два основных трекера, но нужен проигрыватель, выбирается в зависимости от используемого ассемблера. Пишем в FamiTracker, играем FamiTone или Gradual Games Sound Engine. Пишем в Musetracker, играем MUSE. Штатного плеера FamiTracker хватит для простого демо, но не для игр. По желанию пишем свой плеер, оба трекера имеют текстовый экспорт. Для отчаянных есть древности и экзотика.

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

Для среднего или большого проекта наверняка понадобятся особые конвертеры и утилиты. Пишем на чём угодно, лишь бы работало. Обычно C++ или Python.

Отлаживаем в эмуляторах. Средства отладки развиты в FCEUX и NintendulatorDX. Высокая точность эмуляции в Nestopia и puNES, но отладчика в них нет. Даже самые точные эмуляторы не показывают всех глюков, проверяем во всех четырёх. Если пишем на C с готовой низкоуровневой библиотекой, на железе наверняка заработает. Выжимаем максимум на ассемблере — обязательно проверяем на железе при помощи Flash-картриджей (EverDrive N8, InviteNES, PowerPak — ищем в интернете) или самодельного картриджа и программатора ПЗУ.

Логика игры

Чтобы в игру было интереснее играть дольше пяти минут, разработчики поставили такие требования:

  1. Это будет платформер — игра, где главному герою нужно бегать и прыгать по платформам, залезать наверх и скакать через препятствия.
  2. Герой сможет ловко двигаться и стрелять по врагам.
  3. Чтобы можно было играть компанией, делают мультиплеер на четырёх человек.

Так как у нас ограничения по памяти, всю игру пишут на Ассемблере — это язык, который работает напрямую с процессором. С одной стороны, код Ассемблера исполняется очень быстро; с другой — в нём работа идёт тупо с перекладыванием данных из одной ячейки процессора в другую. Это примерно как готовить суши, работая с индивидуальными рисинками.

Память распределили так:

  • 8 килобайт на графику,
  • 32 килобайта на сам код игры и хранение данных.

Почему именно 40 килобайт

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


Два блока памяти в картриджах, 8 и 32 килобайта, в сумме — 40 килобайт.

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

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

Одна из игр, которая взорвала мозг всем в своё время, была та самая «Супер Марио»: в ней было огромное количество разнообразных уровней разной сложности, боссы, секретные уровни и непростой, очень насыщенный геймплей. Были уровни на земле, под землёй, под водой и даже на небе; у героя было несколько режимов — низкий, высокий, в белом комбинезоне. А как вам идея разрушаемого мира? А как вам атаки с воздуха? Короче, «Марио» была безумной, невероятной игрой для своего времени, а всё благодаря оптимизациям.

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


«Супер Марио» — игра, в которую играл каждый, у кого была приставка.

Добавляем в игру сложный режим

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

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

Чтобы игрок понял, что начались трудности, просто меняют палитру. Это почти столько же по памяти, но выглядит сложнее. Уровень можно поменять так: берут исходную картинку, накладывают сверху новые детали и получают сложную локацию. В среднем на это уходит по 7 байт на каждый экран.

Как писались игры на Dendy

Этой статьей я хотел бы немного пролить свет на то, как создавались игры на Dendy. Причем речь пойдет не о том, как это можно делать сейчас, а как это происходило тогда — в 80-е и 90-е годы, и о том, с какими проблемами сталкивались разработчики в то время. Если вам наскучило читать очередные воспоминания менеджеров, дизайнеров, или программистов, переквалифицировавшихся в менеджеров, которые раскрывают техническую сторону дела чуть менее чем никак, то добро пожаловать под кат.

Тогда и сейчас

В наше время разработка для игровых приставок все больше напоминает написание программ для обычных компьютеров, разница между тем что творилось тогда и тем, что имеет сегодняшний разработчик колоссальна. С одной стороны, сегодня, технологии и культура разработки шагнули далеко вперед, позволив вести разработку на языках высокого уровня, с другой — в 80-е фирмы, выпускающие приставки, еще не до конца понимали что следует дать сторонним разработчикам для создания игр. И поэтому если сейчас для очередной playstation можно получить документацию, пяток демо-дисков, а также мощную девелоперскую станцию, по сути гибрид самой приставки и компьютера общего назначения, пригодного для непосредственной разработки, то например в 80-е многие разработчики довольствовались книжечкой со спецификацией консоли. А вот за аппаратной частью приходилось идти на радиорынок (или что там было в штатах вместо них?).

Немного истории

Принято считать, что изначально была создана Nintendo Entertainment System (NES), с которой уже была спирачена наша Dendy и десятки других клонов по всему миру.


После взгляда на картинку видно, что это, возможно, не совсем так. Изначально, в Японии в 1983 году, все-таки была выпущена консоль Famicom. В любом случае существовало 2 незначительно отличавшихся консоли — NES и Famicom. И разработка для них тоже велась разными инструментами, хотя программный код игр в картриджах для обеих был одинаков. Несколько различались сами картриджи. В случае NES на картридже присутствовало несколько дополнительных контактов, которые вели к чипу, который в теории должен был быть только на лицензионных картриджах…

В далеком 1983 году Nintendo могла только мечтать о сторонних разработчиках для новоиспеченной консоли. Так что первые несколько игр были созданы самими авторами консоли. Некоторые из них были портами игр, уже существовавших на аркадных автоматах. Эти игры отличались примитивностью даже по меркам NES, не используя всех возможностей ее аппаратной начинки. Все игры того стартового периода умещались на один экран и не занимали более 32 килобайт данных на картридже. Наиболее известные игры того периода: Donkey Kong, Balloon Fighter, Mario Bros. Ирония заключалась в том, что NES имела специальную аппаратную поддержку для скроллинга уровней, но самые первые игры сайд-скроллерами не являлись, хотя и были выпущены компанией, которой сам бог велел, зная все особенности их консоли, выпускать игры, максимально подчеркивающие преимущества новой приставки.

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

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

Картриджи

Спецификации NES-картриджа до сих пор могут быть найдены в интернете, и, вообще, довольно подробно разобраны сообществом. Но сам процесс производства картриджей — это тайна покрытая мраком. Более менее достоверно известно что на территории Европы и США выпуском картриджей занималась исключительно Nintendo. В смысле, самих коробочек с микросхемами.

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

Каждый разработчик должен был явно указывать в заголовке скомпилированной игры(ROMа) перечень функций NES, которые будут использованы игрой. Некоторые функции поддерживались «обычными» картриджами — например маппер памяти, а вот за наличие сохранения или лишней оперативной памяти приходилось доплачивать Nintendo, чтобы та включила заветные чипы в ваш будущий картридж.

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

Архитектура картриджей подразумевала что сама программа и графические спрайты находятся в разных чипах. Вот например фотография картриджа Super Mario Bros.


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

Оборудование для разработки

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

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

В случае RAM-картриджей разработка шла гораздо быстрее. Можно было редактировать память прямо в процессе игры, используя для этого компьютер, на котором, собственно, и велась разработка. Чип EEPROM заменялся на банки оперативной памяти, которые с одной стороны виделись консолью как обычный картридж, а с другой стороны подключались к компьютеру разработчика и были для него обычной оперативной памятью… или диском… или устройством — все зависело от того, какой именно драйвер программист писал для своего детища.

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


На каких компьютерах проходила разработка — неизвестно, но, учитывая тот уровень возни с радиодеталями, который требовался чтобы запустить отладочную версию игры на приставке, особого значения модель компьютера не имела. Точно известно, что японские разработчики применяли компьютеры MSX. С большой долей вероятности можно сказать, что в США применялись компьютеры Apple 2, ввиду того, что они были довольно распространены, а также имели процессор, аналогичный используемому в NES.

Программное обеспечение

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

Процессор, который использовался в NES, также имелся и в компьютерах вроде Apple 2 или Commodore 64, для которых были и свои ассемблеры и даже компиляторы С. Но архитектура NES все же имела некоторые отличия, а дикие системные ограничения и наличие банкинга(необходимости выгружать старые и загружать новые куски программного кода в область доступную процессору) не давали возможности писать на С игры, которые бы использовали максимум возможностей консоли.

Ассемблер — далеко не единственная вещь, которую приходилось писать вручную: редакторы графики, программаторы, отладчики: все это было написано по несколько раз заботливыми руками программистов. Отдельной статьей можно считать редакторы карт — следует помнить, что компьютеры были слабы и малопамятны, так что, например, вся карта для Metroid была нарисована вручную на бумаге, а потом уже кусками кодировалась в игру.

Процесс разработки

В разработчики часто набирали вчерашних студентов, не видевших NES в глаза. Для львиной доли мелких компаний создававших игры как нельзя лучше подходил термин «шарашкина контора». Типовая игра занимала 3-6 месяцев времени на разработку. Команды чаще всего были небольшими — 3-10 человек. Было много контор, которые выпускали 1 игру и потом исчезали без следа.

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

Сперва дизайнер рисовал эскизы бэкграундов и персонажей, затем, после отбора подходящих рисунков, начиналась так называемая пикселизация — палитра NES поддерживала только 14 цветов на экране одновременно, так что приходилось перераскрашивать рисунки с учетом этого ограничения. Затем рисунок расчерчивался по сетке, и при необходимости растягивался или сжимался — NES аппаратно поддерживала спрайты размером 8x8 пикселей. Персонаж Марио рисовался в 4 прохода, после съедания гриба — в 8 проходов. Мелочь, но иногда из-за ее игнорирования мы видели в некоторых играх пропадающие спрайты, когда на экране становилось очень много врагов, так что программистам приходилось экономить и на спичках. Кстати видеопамяти было 2 вида — одна, в которой обычно хранились спрайты персонажей и прочая мелочевка, вторая, побольше в которой хранились карты уровней. Последняя находилась в отдельном адресном пространстве и поддерживала аппаратно ускоренные операции по скроллингу.

Работа композитора плавно перетекала в работу программиста — написать музыку это только часть дела, закодировать ее в игру — тоже дело наживное, а вот затем начиналось самое интересное. Как было сказано выше, иногда игра подтормаживала, так что если в предрелизе такие тормоза достигали небывалых показателей, то композитору давали задачу «оптимизировать» музыку — убрать лишние опкоды, чтобы ускорить работу игры в целом. Тут-то и выяснялось истинное мастерство композитора. Лишнюю монетку в копилку позора композитора добавлял тот факт, что далеко не всегда разработчик игр по фильму получал лицензию на… использование музыки из фильма. Таким образом композиторам приходилось писать что-то оригинальное, и далеко не всегда хорошее.

Среди игр для NES был распространен так называемый репэкедж — это когда на базе одной игры делают другую меняя спрайты и уровни, иногда немного меняя сам игровой процесс. Например Castlevania и Ninja Gaiden сделаны на одном движке, также как и Darkwing Duck был сделан на базе движка для серии игр Megaman(Rockman). Каковы были истинные масштабы репэкджа мы можем только догадываться, особенно учитывая тот факт, что огромный процент игр на денди — однотипные сайд-скроллеры.

Разработчики

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

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

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

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

Сегодня

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

Создание самодельных аксессуаров для Dendy

Сначала я и не думал писать статью на эту тему, но похоже, что это уже часть целого цикла статей на Денди-тематику. И да, на этот раз речь в первую очередь именно про отечественную Денди, а не про оригинальные консоли — Famicom или NES. Просто я делал устройство в подарок одному человеку, который снимает очень интересные видеоролики про Денди, и ориентировался на совместимость именно с этим клоном.

Дело в том, что и для Famicom, и для NES выходили самые разные аксессуары: 3D очки, клавиатуры, роботы, считыватели штрих-кодов, всякие игровые контроллеры и очень многое другое. До нас же дошёл только световой пистолет. Передо мной стояла задача собрать устройство, которое совмещало бы в себе разветвитель на четыре игрока (да, были такие игры) и Arkanoid-контроллер.



Порты ввода-вывода

Прежде всего стоит рассказать, как же работают с джойстиками игровыми контроллерами Famicom, NES и Dendy, и чем же они отличаются в этом плане.

С точки зрения игр порты ввода-вывода представляют из себя два регистра с адресами $4016 и $4017, которые ассоциированы соответственно с двумя портами, куда всё и подключается. Но на стандартных контроллерах для чтения данных используется только один провод — D0, данные с которого соответственно доступны через младший (нулевой) бит в каждом из регистров: $4016.0 и $4017.0. Аналогично используется один провод на запись, его обычно называют STROBE (или LATCH), который сбрасывает счётчик внутри геймпада, и который доступен через запись в $4016.0 (да, для обоих контроллеров он общий).

Проще говоря, чтобы получить состояние кнопок на первом контроллере надо сначала записать 1 в $4016.0, сразу же записать туда же 0, сбросив таким образом счётчик, а потом прочитать $4016 и $4017 восемь раз (для каждой из кнопок), получая данные о кнопках из младшего бита. Но для чего же остальные биты в этих регистрах, куда идут эти линии? Рассмотрим порт контроллера у NES:


Да, на него на самом деле идут D3 и D4! Именно они и доступны через $4016.3, $4016.4 у первого порта и $4017.3, $4017.4 у второго, и именно они используются для нестандартных контроллеров.

Что же касается его японского собрата — Famicom, там нет этих портов, да и сами игровые контроллеры не отсоединяются от консоли, но у него есть порт расширения, который представляет из себя разъём DB-15.


Знакомо выглядит, правда? Да, когда китайцы проектировали нашу Денди (я сомневаюсь, что её проектировали у нас), и им нужно было сделать отсоединяющиеся контроллеры, они решили взять за основу именно порт расширения, ведь в нём есть контакты для второго контроллера, и он на Famicom расположен чуть правее центра. Им тут даже распиновку менять не пришлось. Что же касается первого контроллера, они взяли тот же DB-15, расположили его слева и поменять распиновку так, чтобы можно было подключать первый контроллер. И только его.

Сравните сами передние порты у Famicom и у нашей Денди:


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

Но давайте посмотрим, что же выведено на этот порт расширения у Famicom?

Да, на него идут ещё $4016.1 (на ввод), $4017.0-4 (на ввод), $4017.0-2 (на вывод), внешнее прерывание и даже звук! Я был очень приятно удивлён, когда разобрал Денди и увидел, что всё это есть и там:


Правда, не во всех моделях, как выяснилось позже. Но если это есть, значит есть и полная совместимость с аксессуарами для Famicom, и их могут использовать соответствующие японские игры. Но напомню, что Денди — это очень странная смесь NES и Famicom, PAL и NTSC. Пираты выпускали для неё и японские, и американские игры, которые по сути на 100% совместимы, если не брать в рассчёт эти аксессуары и разный формат картриджей.

Итого: в некоторых Денди есть все те же выводы, что и на Фамикоме, которые при этом включают в себя часть выводов доступных на NES. Отсутствует доступ к $4016.3 и $4016.4, но они используются крайне редко. В виде таблички для наглядности:


Принцип работы аксессуаров

Американский разветвитель на четыре игрока для NES называется Four Score представляет из себя простой набор сдвиговых регистров. Т.е. первые восемь чтений из $4016.0 дают данные из первого контроллера, а вторые восемь — из третьего. Аналогично $4017.0 даёт данные о втором и четвёртом контроллерах. Помимо этого при продолжении чтения устройство выдаёт свою сигнатуру, с помощью которой игра определяет, что подключен именно Four Score, а не что-то ещё. Получается, что такое устройство можно собрать из шести сдвиговых регистров (4021 или 74165), и оно будет работать на любой Денди, ведь для него не требуются дополнительные линии данных. Само собой, только с американскими играми, которые выходили для NES.

Японский аналог для Famicom устроен гораздо проще. Третий и четвёртый контроллеры подключаются напрямую в порт расширения и доступны через $4016.1 и $4017.1. Соответственно для такого переходника нам уже нужен полноценный порт расширения у Денди, иначе поиграть вчетвером в японские игры не получится.

Arkanoid-контроллер, как ясно из названия, используется для игры Arkanoid и представляет из себя ручку-крутилку и одну кнопку. Внутри же это аналого-цифровой преобразователь и сдвиговый регистр, который так же последовательно выдаёт положение ручки. Разница между японской и американской версией только в способе подключения. Японская версия игры читает положение ручки и состояние кнопки из $4016.1 и $4017.1, а американская версия из $4016.3 и $4016.4 соответственно. Получается, что для японского Арканоида нужен полноценный порт расширения, а для американского подойдёт любая денди, где работает световой пистолет (он использует те же выводы).

Создание своего аксессуара

Хотя сами по себе вышеперечисленные устройства имеют простую схему и собираются из простейших логических компонентов, для сердца устройства типа «всё в одном» я решил использовать ПЛИС. Тем более мне было высказано пожелание сделать там ещё и простейший переключатель-свитч, а мне хотелось сделать возможность менять местами кнопки A и B. Сначала я выбрал Altera EPM3064ATC100, но вскоре выяснилось, что 64 макроячейки мне не хватит, и выбор пал на EPM3128ATC100, где уже 128 макроячеек.

Если уж на то пошло, я решил совсем не мелочиться и поставить в устройство ещё и какой-то экран, на котором показывались бы текущий режим и меню с настройками, к тому же у меня давно валялся без дела один знакосинтезирующий «16x2» дисплей. Вот для работы с ним уже нужен микроконтроллер, и я выбрал ATMEGA16.

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

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


Кнопки в ряд, порты друг над другом, ручка сбоку, кнопка для Arkanoid сзади слева.

Получается, что места внутри достаточно много. Поэтому ПЛИС с разъёмами под провода и гнёзда я решил вынести на одну плату, а микроконтроллер с экраном и кнопками — на другую. Соединяются они при этом простейшим последовательным интерфейсом.

Плата с ПЛИС (первая версия):



Код для ПЛИС я писал на Verilog. Для каждого режима он получается достаточно простым. В первую очередь для многих из них нам надо считать обращения к каждому из портов, т.е. импульсы на проводе clock:


(простите, хабр не умеет подсвечивать Verilog)

Где strobe_in — это strobe (один на оба порта), а clock1_in и clock2_in — это соответственно clock на каждом из портов. Внутри консоли стоит логика: clock = R/W nand (адрес == $4016/$4017), т.е. на clock логический ноль, когда консоль читает данные по соответствующему адресу.

Режим имитации американского разветвителя на четверых игроков выглядит так:


В режиме японского же разветвителя на четверых нужно просто соединить входы с выходами напрямую:


Самым сложным оказалось сделать возможность менять местами кнопки A и B, ведь считываются они последовательно, т.е. нужно заранее знать значение B, когда консоль запрашивает A, но оно выдаётся как раз только после A. Сначала я думал как-то ускоренно считывать данные с контроллера, используя какой-то внешний тактовый генератор, но в итоге решил просто брать значение от предыдущего считывания. Это даёт задержку, но она абсолютно незаметна. Тем более игры обычно читают состояние кнопок по несколько раз подряд.

Само собой, все эти режимы и настройки надо как-то задавать. Для этого я определил 12-битный регистр control, данные в который записываются через последовательное соединение, с дополнительным битом для проверки чётности:


Соответственно со стороны микроконтроллера код (весьма грязный) выглядит вот так:


В остальном в коде микроконтроллера нет ничего особенного: работа с дисплеем на контроллере HD44780, кнопки, светодиоды, простенькая менюшка и работа с аналого-цифровой преобразователем для определения угла поворота ручки.

Я всё отладил, убедился в работоспособности и уже начал упихивать компоненты в корпус…


Но перед закрытием крышки решил проверить на оригинальном Famicom, ведь с ним устройство тоже будет использоваться. Увы, режимы, где нужно было считать импульсы clock, работали неправильно. С помощью логического анализатора выяснилось, что с линии данных идут наводки на линию clock:


Это помеха длительностью всего в несколько десятков наносекунд всё портит. Я решил посмотреть своим простеньким осциллографом, что же происходит на линии clock у Денди:


А вот что там же у Фамикома:


Видно, что эта линия подтянута к VCC, при чём очень сильно у Денди и весьма слабо у оригинального Фамикома. Я начал экспериментировать с обвеской. Вскоре стало ясно, что на результат лучше смотреть не логическим анализатором, а самой консолью. Пришлось вспоминать ассемблер для 6502 процессора, писать простенькую программу для тестирования и записать её на картридж:


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

В итоге проблема была решена подтяжкой линий clock к VCC через резистор в 1кОм, конденсатором между clock и землёй в 22нФ и резисторами на 200 Ом в разрыв всех линий данных. Увы, пришлось травить новую плату (не фотографировал), но зато после этого сразу же всё заработало.

Итоговый вид устройства:


Во времена СССР я мог бы быть хорошим промдизайнером.

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

Большой босс и оптимизация памяти

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

Большой босс и все его варианты анимации. Если мы распределим все спрайты по таблице один в один, то у нас быстро закончится место и один кусочек не поместится. Запомните эту картинку как пример неоптимизированной работы с памятью. Для начала разработчики разбили босса горизонтально на три части, и каждая анимируется отдельно. Видно, что анимация причёски состоит из трёх картинок, каждая из которых немного отличается от остальных. Если разбить картинки с причёской на отдельные квадратики, то мы заметим, что у них есть повторяющиеся части. Поэтому достаточно нарисовать одну деталь, а потом использовать её во всех трёх вариантах причёски. Находим оставшиеся одинаковые части и тоже оставляем только одну из них. А вот тут видно, что это один и тот же спрайт, только в зеркальном виде. Компьютеру несложно нарисовать его отражённым, поэтому тоже можно смело оставить только один из них. С последними треугольничками в каждой картинке — то же самое: это отзеркаленные первые спрайты. В итоге вся верхняя часть босса вместе с анимацией поместилась в четырёх спрайтах. Это и есть оптимизация: было 16 спрайтов, стало 4. То же самое делают для средней части. Сейчас она занимает 3 × 8 = 24 спрайта. А сейчас — 7. После полной оптимизации босс занимает всего 21 спрайт. Из этих кусочков собирается итоговый вид босса. Сравните с первоначальным вариантом до оптимизации 🙂

Рисуем карты (и оптимизируем их)

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

Первый вариант — уменьшить количество памяти для отрисовки карты: сделать их симметричными, что даст нам 30 байт вместо 60. Мы рисуем одну половинку карты, а потом просто отзеркаливаем её. Сравним с картой, которую мы бы хотели получить:


Вроде всё на месте, а выглядит плохо — сразу видна симметрия и доступ наверх закрыт блоками.

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

  1. Они дают для хранения одной суперплитки один байт.
  2. Считают по картинке, сколько получилось суперплиток в прошлом разделе — 96.
  3. Так как программисты начинают считать с нуля, то самое большое число, которое получится, — 95, а это 1011111 в двоичной системе счисления.
  4. В этом длинном числе всего 7 цифр, а в байте их 8, поэтому остаётся один лишний бит из каждого числа.
  5. 4 суперплитки дадут 4 бита.
  6. Эти 4 бита можно использовать, чтобы сдвинуть по кругу ряд с зеркальным отражением и получить как бы новый ряд, уже без видимой симметрии.

Если вы не знаете, что такое двоичная система счисления, — почитайте нашу статью об этом, а потом вернитесь сюда.

4 суперплитки дают 4 бита. Посмотрим, что можно с ними сделать. Сначала делают симметричный уровень… А затем сдвигают верхнюю полосу вправо по кругу. 1100 — это 12 в десятичной системе счисления, именно столько сдвигов вправо нужно сделать, чтобы получилось как на картинке. То же самое делают с третьей строкой и получают уже приемлемое начало уровня.

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

Карта

Для карт у нас столько же памяти, сколько и на спрайты (то есть мало), поэтому разработчики будут действовать так же:

  • разбивать фон на отдельные ячейки;
  • смотреть, как можно оптимизировать эти ячейки для хранения в памяти;
  • смотреть, можно ли что-то использовать повторно, для экономии памяти.

Главная задача на этом этапе — максимальная экономия видеопамяти. Для этого каждый экран с уровнем игры разбивается не на метаплитки 2 × 2, как в примере выше, с персонажем, а на метаметаплитки или суперплитки — 4 × 4 ячейки. Вот для чего это нужно:

Если разбить просто на квадратики 8 × 8, как в памяти, то вся видимая на экране часть уровня займёт 960 байт. Это почти килобайт, и это очень много. Разбивают уровень на метаплитки 16 × 16. Теперь на одну карту нужно 240 байт, чтобы пометить каждую такую метаплитку, но это всё равно много. Уменьшаем дальше. Теперь уровень делится на супербольшие плитки по 16 ячеек в каждой. В итоге для того, чтобы пронумеровать каждую такую суперплитку, нужно всего 60 байт. Уже можно работать. Вот так собираются метаплитки — из четырёх ячеек в памяти. Теперь можно собирать такие метаплитки в виртуальные наборы и каждой присвоить какой-то код. Но и это ещё не всё. Вот теперь получилась суперплитка. Это готовый блок для уровня, и чтобы собрать такое, нужно совсем немного памяти. Коллекция виртуальных суперплиток. С ними можно сделать любые уровни и фоны.

Как писали игры для приставок: чудеса оптимизации и жёсткий кодинг

В 1980-х годах, когда приставки только появлялись, вышла NES — Nintendo Entertainment System. В Россию она попала в виде китайского клона «Денди», «Кенги» и прочих, поэтому если у вас была восьмибитная приставка, то это была NES.

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


Та самая приставка, справа пока ещё две кнопки вместо четырёх. Для разбора мы взяли видео из канала Morphcat Games — How we fit an NES game into 40 Kilobytes. Там разработчики повторяют опыт геймдизайнеров прошлого и пишут игру для старого железа. Как обычно, если знаете английский, то лучше посмотрите видео целиком, а если нет — держите наш текстовый вариант.

Персонажи

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

Каждая клеточка — это мини-квадратик 8 на 8 пикселей. В каждом таком квадратике можно что-то нарисовать, но использовать при этом только три цвета. Если объединить несколько квадратиков в один, получится метаспрайт. В нашем случае — персонаж. Приставка может использовать одновременно только 4 вида палитры, поэтому у нас получается 4 цветных главных героя и нераскрашенный злодей. Новое ограничение: на экране одновременно может быть только 8 спрайтов — на большее не хватает памяти. Поэтому для злодея места не остаётся. Можно пойти на хитрость и показывать их быстро-быстро по очереди, но тогда картинка будет мерцать и выглядеть хуже. Разработчики радикально уменьшили размеры героев и злодея до одного спрайта. Теперь они выглядят более условно, зато помещаются на экран. Меньше размер героя — больше свободного места для дизайна злодеев, боссов и спецэффектов. Сейчас в табличке собраны все варианты того, как может выглядеть персонаж в игре — и в прыжках, и на бегу.

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