Сегодня — десятилетняя годовщина релиза VVVVVV!

Хотя, возможно, и завтра — строго говоря, впервые игра стала доступной 3 часа утра по GMT 11 января 2010 года, спустя очень долгий день устранения каждого найденного мной бага, создания сборок последней минуты и попыток медленно закачать всё на сервер по чрезвычайно ненадёжному Интернет-соединению, которое постоянно разрывалось. Но я всегда живу девизом "завтра не настало, пока ты не проснулся", поэтому считаю настоящей датой релиза 10 января <3

Боже мой, десять лет.

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

[Исходный код VVVVVV на github]

В репозитории содержится две версии — десктопная, в 2011 году портированная Саймоном Ротом на C++, и более поздняя, которую обновлял и поддерживал Итан Ли, а также мобильная версия, написанная на Actionscript для Adobe AIR, основанная на первоначальной флеш-версии игры v1.0.

Хочу сказать огромное спасибо Итану Ли, сильно мне помогавшему, в том числе в подготовке репозитория для сообщества и организации объявления об этом на AGDQ (привет, спидраннеры!)! Спасибо, Итан!


Краткий обзор исходного кода


Здесь логично будет задать вопрос: “Что вообще интересного в исходном коде VVVVVV?”.

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

Потенциально интересные заметки/объяснения того, почему всё выглядит именно так, как есть:

  • В версии на C++ есть куча странных вещей, которые становятся логичными, только если вспомнить, что сначала игра создавалась на флеше, а затем напрямую портировалась со всеми её недостатками. Например, вероятно, худшей моей программистской привычкой является объявление временных переменных наподобие i, j и k как членов каждого класса, чтобы их не приходилось объявлять внутри функций (что по скучным причинам во флеше делать занудно). Это привело к появлению нескольких гадких и сложных в отлове багов, если не сказать большего. В частности, некоторые функции вычислений коллизий сущностей имеют общую переменную i. Поэтому возможны бесконечные циклы.
  • Если вы ищете тексты игры, то бОльшая их часть (но не все) находится в классах Scripts.cpp и TerminalScripts.cpp. По сути, эти функции загружают данные в очень простой парсер скриптов, управляющий логикой катсцен. Забавный факт: моддеры много лет назад выполнили реверс-инжиниринг этого “внутреннего скриптинга”, чтобы проделать потрясающие вещи с самодельными уровнями, возможность существования которых я даже не мог вообразить.
  • На каком-то этапе процесса разработки я решил, что хорошей привычкой является разделение кода на ввод, логику и рендеринг, и принял это близко к сердцу. Основная часть критического кода игры находится в трёх файлах — input.ccp, logic.cpp и некорректно названном titlerender.cpp. Каждое состояние игры упаковано в эти три файла под такими названиями функций, как teleporterrender и towerlogic. Там есть куча копипасты.
  • Все уровни жёстко прописаны в огромных массивах, сгенерированных в моём собственном редакторе файлов, который экспортирует уровни в исходный код, из которого я могу выполнять считывание. Примерно так я работал при создании флеш-игры в 2009 году — доступ к внешним ресурсам данных был сложной задачей, поэтому в то время было логичнее скомпилировать их в саму игру. Все по-настоящему большие файлы (например, Spacestation2.cpp, Finalclass.cpp и так далее) были созданы таким способом. Для полноты кода я загрузил код редактора сюда, но, честно говоря, он теперь не особо применим (для компиляции он требует Allegro и Mingw). Для изменения схемы последних уровней я написал похожий инструмент!
  • Когда я писал код, то не очень понимал, как работают статические классы и почему их использование является хорошей идеей. Кажется, я прочитал где-то, что статические классы и глобальные переменные ПЛОХИ во флеше, поэтому стремился полностью избегать их. Что же в результате получилось? Буквально каждая функция в игре передаёт следующие аргументы: “Graphics& dwgfx, Game& game, mapclass& map, entityclass& obj, UtilityClass& help”.
  • По сути, в VVVVVV нет временных объектов, и при первой инициализации игры она заполняет все свои массивы сущностей (и большинство других массивов данных) сотнями пустых сущностей. Она поступает так, потому что я прочитал где-то, что удаление объектов во флеше вызывает странные торможения, потому что в дело вступает сборщик мусора и замедляет всё, и это в какой-то степени является правдой. Я продолжал придерживаться этой странной привычки и в новых проектах до последнего времени — в Dicey Dungeons я наконец от неё отказался.
  • И ещё один момент: наряду с парсером катсцен у меня был ещё один способ управления логикой игры в процессе прохождения — монолитный конечный автомат, который к концу проекта совершенно выбился из-под контроля! Его можно найти в Game::updatestate, и я рекомендую прочитать его, даже если вы не хотите читать никакой другой код. Он управляет такими аспектами, как запуск начала сложных катсцен, точки, в которые игрока отправляют телепорты, тайминги анимации завершения уровня и множеством других вещей, которые я хотел запихнуть в игру быстро. Состояния пронумерованы и наибольшее имеет значение 4099 (есть неиспользуемые номера). При разработке игры рядом со мной был блокнот, в который записывались самые важные номера — номер 1 000 запускал подбирание «блестящей побрякушки» (shiny trinket), номер 3 040 запускал завершение одного конкретного уровня, номер 3 500 запускал конец игры. Эта тупая система стала причиной потрясающего спидрана игры за 50,2 секунды в категории any%.

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

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


Вечеринка-сюрприз на годовщину!


Пока я готовился к публикации статьи, Серхио Корнага объявил о проведении геймджема в честь десятилетия VVVVVV!

VVVVVV’s 10th birthday eVVVVVVent!

Я так рад этому, ха-ха, и я люблю сайт glorious trainwrecks, проводивший регулярные джемы Klik of the Month, в которых я постоянно участвовал примерно во время разработки VVVVVV. Кажется, он идеально подходит для этого джема!

Мне очень не терпится увидеть после завершения джема, что придумают люди, и я напишу в своём блоге большой пост с подведением итогов в стиле старых постов про пользовательские уровни VVVVVV, которые я когда-то писал <3

Ещё до того, как я зарелизил исходный код игры, я открыл бесплатный доступ к инструментам для создания и прохождения уровней VVVVVV в версии Make and Play 2014 года! Её можно скачать отсюда! Если вам интересно было бы создавать уровни в редакторе VVVVVV, то можете начать с этого топика! Удачи!



Немного сентиментальности


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

Спустя десять лет я по-прежнему чувствую то же самое. Я невероятно горд VVVVVV и благодарен за всё. Хочу поблагодарить всех, кто помогал мне на моём пути — Магнуса за его невероятный саундтрек, Итана и Саймона за всю их работу, сделавшую игру доступной широкой публике, Беннетта за названия комнат, Стивена за помощь в создании в сборке для Mac в день выпуска. Эта игра для меня особенная, спасибо всем, кто играл в неё и поддерживал меня на протяжении десяти лет. Это многое для меня значит. <3