Когда ты много лет руководишь командами, легко забыть, каково это - просто сесть и закодить что-то самому.

Эта статья о том, как я сделал фэнтези-консоль под DOS, и снова влюбился в программирование.

Введение

Первый компьютер появился у меня в самом раннем детстве. Он включался долго, шумел, как старый пылесос, и запускал DOS-версию "Поля чудес", Scorched Earth, Doom и десятки странных игрушек с дискет (а потом и с дисков типа “200 лучших игр всех жанров”)

Свело одскулы? :)
Свело одскулы? :)

Потом пришёл интернет, рецензии и коллекционные карты ag.ru, журналы про компьютерные игры с постерами, игра “Full Throttle”, после которой я решил, что хочу делать игры, и рассказы Дани Шеповалова в журнале Хакер, после которых я в 10 классе устроился тестировать шутер “Невский Титбит” (кто знает - тот знает :). Как вы поняли, игры меня окончательно захватили.

В процессе я немного учился программировать: мы с отцом делали проекты на Delphi и Flash для слабослышащих детей (IBM SpeechViewer в то время стоил совершенно негуманных денег и был недоступен для наших школ), но в отличие от многих, программировать ради удовольствия я по-настоящему полюбил не с детства.

По-настоящему меня торкнуло в 2006-м, когда ВКонтакте открыл API. Это был портал в другой мир. Потому что теперь можно было за ночь сделать проект, которым будут пользоваться сотни тысяч людей и понеслось: сервисы, игры, клиент, бэкенд…

Мой первый проект выглядел страшненько, представлял из себя один файл >1000 строк, но это не помешало ему начать быстро набирать популярность
Мой первый проект выглядел страшненько, представлял из себя один файл >1000 строк, но это не помешало ему начать быстро набирать популярность

И вот на дворе 2022 год.

Роль программиста давно сменилась на менеджерскую.

Команды, метрики, воронки, фичи, баги, ответственность, итерации, стратегические цели.

Мы с командой только что запустили наш долгожданный проект. Пережили ковид. Перешли на удалёнку.

Но, по моему опыту, в жизни каждого менеджера рано или поздно наступает переломный момент.

В голову закрадываются мысли: "Я собираю команду, задаю цели, подбадриваю, подталкиваю, поддерживаю...", "Но в итоге - все делает моя команда.", "А что делаю я?", "В чём продукт моего труда?"

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

Но…

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

Но тут вышел ChatGPT и изменил все. Немного поэкспериментировав с ним я понял, что снова могу кодить и создавать.

Спецификация

За прошедшие годы накопилось много мыслей:

  • Я прочитал Crafting Interpreters Боба Найстрома - и загорелся идеей плотнее поработать с интерпретаторами и виртуальными машинами.

  • Выход GB Studio заставил меня впервые серьёзно попробовать pixel-art. И оказалось, что в в таких рамках я реально могу рисовать!

  • PICO-8 и TIC-80 открыли глаза на то, как кайфово делать игры в жестко очерченных рамках: маленький экран, ограниченный код и просто офигенные игры.

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

Джон Кармкак программирует по-старинке
Джон Кармкак программирует по-старинке

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

Итак, внутри должны быть

  • псевдо-операционная система с терминалом

  • редактор кода

  • редактор графики

  • редактор карт

  • редактор звуков и музыки

Вооружившись ChatGPT я взялся за дело…

Архитектура

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

  • backend - код на С, эмулирующий аппаратное обеспечение несуществующей 8-битной консоли и дающий API для интерпретируемого ЯП

  • adapter - по-сути связка с платформой, реализующей вывод звука, график работу с вводом и другие необходимые платформоспецифичные функции

  • frontend - интерпретируемый код, реализующий всю “операционную систему” и программы

Благодаря этому подходу после отладки всего функционала на SDL адаптере реализация DOS версии прошла практически безболезненно.

В роли стека для DOS выступили:

  • DJGPP (порт GCC для DOS), последняя версия вышла в 2015 году

  • Allegro(в качестве адаптера на замену SDL) - последняя версия 4.2 с поддержкой DOS вышла в 2007 году

DOS по-умолчанию - 16-битная ОС, но DJGPP запускает программы в 32-битном защищённом режиме через DPMI (DOS Protected Mode Interface).  

Именно на DJGPP id Software собирала первый Quake под DOS.

Похожую роль играл компилятор Watcom в связке с загрузчиком DOS4GW.EXE, который пребывал в каждом втором дистрибутиве игр 90-х.  

Графика

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

Legend of Zelda: Links Awakening для GameBoy, Celeste для Pico-8, EMUUROM для TIC-80
Legend of Zelda: Links Awakening для GameBoy, Celeste для Pico-8, EMUUROM для TIC-80

Fun Fact: Celeste изначально вышла как мини-игра на PICO-8 и только потом из нее развернулся хитовый Steam проект

Как я уже говорил, мне очень понравилось рисовать GameBoy графику (можете сами попробовать, воспользовавшись, например, этим тутором). Спрайт 16x16 рисуется быстро, а 4 цвета не требуют понимания теории цвета.

Немного моего pixel art для GameBoy
Немного моего pixel art для GameBoy

Еще мне всегда нравились янтарные CRT мониторы (есть в них что-то магическое)

Источник

Так что я сделал 4х цветную палитру вдохновленную ими

4 цветов хватит каждому! (впрочем авторы PlayDate могут сказать, что и это излишество)
4 цветов хватит каждому! (впрочем авторы PlayDate могут сказать, что и это излишество)

В памяти консоли графика хранится в 2bit формате (00, 01, 10, 11) для 4 цветов палитры. Для спрайтов один из цветов помечается как прозрачный.

В качестве разрешения я выбрал 160x120 пикселей:

  • это разрешение дает хороший integer-scaling для 4:3 мониторов

  • оно близко к оригинальному GameBoy (160×144)

  • меньше пикселей для обработки уменьшают нагрузку на отрисовку

Вот как выглядит 160x120 пикселей с нашей палитрой
Вот как выглядит 160x120 пикселей с нашей палитрой

Шрифт

Поскольку размер экрана очень маленький, то чтобы вместить максимум информации, нужен подходящий шрифт. Я сделал много экспериментов со своими и чужими шрифтами, но по итогу лучше распространяющегося по CC-0 лицензии шрифта PICO-8 с размером глифа 3x5 ничего не получилось.

Тот самый шрифт 3x5
Тот самый шрифт 3x5

Работа со шрифтами сразу разблокировала воспоминание: когда я учился в универе, масса материалов по программированию была в формате Lexicon, так что практически каждое поколение студентов делало свой просмотрщик Lexicon, благо у него был моноширинный шрифт 8x8 и один байт обозначал одну строчку пикселей в глифе.

Редактор кода с максимумом информации, втиснутой в маленькое разрешение
Редактор кода с максимумом информации, втиснутой в маленькое разрешение

Язык программирования

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

API функции я решил сделать похожими на PICO-8 и TIC-80, чтобы можно было использовать существующие туториалы (например Nerdy Teachers и LazyDevs)

Звук

Насчет звука я долго думал, хотел сделать свои FM синтезаторы с блэкджеком осцилляторами и ADSR

Прототип редактора синтезаторов
Прототип редактора синтезаторов

Но потом, посмотрев классное видео про трекерную музыку, я понял, что именно это мое ретро :) Демо-сцена, моя коллекция музыки из кейгенов, которую я много лет собирал. Да хотя бы трек Space Debris, который сразу телепортирует в детство.

Fun fact: автор классического трека “Space Debris” Markus Captain Kaarlonen является клавишником группы Poets of the Fall, написавшей песни к Max Payne 2, Alan Wake 1/2 и Control 

Так что я взял MOD-формат и сделал интерфейс в духе ProTracker - 4 дорожки, сэмплы, эффекты.

интерфейс трекера
интерфейс трекера

Для работы с MOD я использовал легковесную библиотеку pocketmod.

Для каждой новой игры создается копия пустого MOD файла с предустановленным наборов сэмплов.

Для DOS-версии я споткнулся об формат потока аудио. Pocketmod рендерит звук как AUDIO_F32 (32-бит float), а Allegro под DOS ждёт 8-бит unsigned. Если подать что-то «не то» - получите кошмарный громкий шум (интересно, сколько программистов работающих со звуком повредили слух в процессе обучения тому, как это работает ?)

Так что пришлось немного доработать напильником библиотеку, чтобы она выдавал сэмплы в нужном формате.

Компьютерный звук - это просто поток чисел, а процесс превращение звука в этот поток называется дискретизацией. Каждое число - сэмпл, фиксированная запись амплитуды волны; чем выше частота дискретизации (например 22 050 или 44 100 Гц), тем больше таких снимков в секунду и качественнее звук. Программа заполняет аудиобуфер этими сэмплами в нужном формате (8-бит/16-бит, signed/unsigned, mono/stereo) и передаёт драйверу. Дальше буфер циклично «съедает» звуковая карта - и мы слышим музыку.

Картридж

Как могли бы выглядеть дискеты с играми для NIBBLE8
Как могли бы выглядеть дискеты с играми для NIBBLE8

Для распространения игр фэнтези консоли как правило используют некий формат, включающий Lua код, атлас, карту и музыку со звуками.

Чтобы не усложнять, я решил просто сделать формат n8 в виде zip архива, содержащий:

  • app.lua - весь код, скленный в один файл

  • map.bin - карту из редактора карт

  • spriteFlags.bin - спрайт флаги

  • music.mod - файл содержащий все звуки, музыку и дефолтный набор сэмплов

Название и маскот

Как известно, слово BYTE звучит похоже на BITE - в переводе “укус”, поэтому полубайт называется NIBBLE - “грызть”

Поскольку один пиксель в игре занимает полбайта я решил выбрать название NIBBLE8

А маскотом стал пиксельный пес Ниббл из незаконченной мной JRPG для GameBoy.

Жизнерадостный Ниббл во всей своей красе
Жизнерадостный Ниббл во всей своей красе

Итог

В итоге NIBBLE8 можно собрать под веб, на любой системе поддерживающей SDL 1 или 2 и под DOS (наилучший перформанс на процессорах Pentium MMX и выше)

На Toshiba Libretto 70ct работает хуже чем на Thinkpad 760xl, но работает!
На Toshiba Libretto 70ct работает хуже чем на Thinkpad 760xl, но работает!

У меня было много разных идей (к примеру превратить это в своего рода альтернативный интернет в духе FidoNet и BBS ), но со временем меня немного попустило.

Макет не вошедшего в проект двухпанельного файлового менеджера
Макет не вошедшего в проект двухпанельного файлового менеджера

Первая версия получилась неидеальной, сейчас бы я сделал все совсем по-другому, есть многое, что стоило бы доработать и оптимизировать (к примеру мне дали хороший совет реализовать компиляцию Lua в C, чтобы можно было получать очень быстрый код для DOS).

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

? Код на GitHub: https://github.com/jenissimo/NIBBLE8

? API Reference: https://github.com/jenissimo/NIBBLE8/wiki/API-Reference

? Попробовать онлайн: https://nibble8.com/try.html

Буду рад увидеть, как вы запускаете NIBBLE8 на своих ретро-компах (или эмуляторах!)

✉️ Пишите фидбек, делитесь своими историями.

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

Также если понравилась статья, возможно тебе будет интересно подписаться на мой Telegram

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