
Привет, Хабр!
Помню, как впервые запустил The Binding of Isaac: стартовая комната без подсказок, закрытые двери, на миникарте пусто. Пара забегов и у меня уже список технических вопросов по генерации этажей, приоритетам предметов, поведению врагов, рендеру и производительности. В тот момент я решил написать эту статью.
Сегодня я расскажу о разработке культовой инди-игры The Binding of Isaac и разберу технические нюансы: путь от Flash к C++, как собирается план этажа, как устроены большие комнаты и секретки, по каким правилам живут эффекты предметов и их синергии, как Lua-скрипты встраиваются в движок для модов, где в архитектуре сделаны осознанные компромиссы.
Начнем.
История рождения проекта и проблемы Flash
Игра The Binding of Isaac родилась как хобби-эксперимент. После успеха Super Meat Boy геймдизайнер Эдмунд Макмиллен позволил себе рискованный творческий экспромт.

Вместе с программистом Флорианом Химслом они за неделю набросали прототип небольшого рогалика в духе The Legend of Zelda, только мрачнее и страннее. План был простой: сделать игру за 7 дней и выложить на Steam без особых ожиданий. Но, как это часто бывает в разработке, семь дней почему-то превратились в три месяца. За примерно 12 недель неполного рабочего времени дуэт довёл прототип до коммерческого релиза – благо, независимый статус позволял не гнаться за жесткими дедлайнами и сертификатами. Макмиллен даже не думал о консолях или цензуре, поэтому выбрал самую доступную платформу – Adobe Flash.
В 2011 году это был быстрый способ воплотить идею в жизнь, не заморачиваясь на сложные движки. Isaac писался на ActionScript 2 – устаревшем уже тогда языке, но достаточно знакомом разработчикам флеш-игрe. В итоге проект действительно получился «без оглядки на будущее»: Макмиллен позже признавался, что ни за что не стал бы делать Isaac на Flash, если бы знал, каким популярным он станет. Ограничения платформы дали о себе знать очень быстро. Во-первых, ActionScript 2 работал медленно и мог тормозить даже на хороших ПК. Если на экране появлялось слишком много объектов – скажем, десятки слёз-снарядов, пауков и мух – флеш-движок начинал заикаться. Во-вторых, Flash не поддерживал геймпады и многие другие функции «больших» игр. Например, чтобы прикрутить достижения Steam, пришлось привлекать друга-разработчика Томми Рефенеса, который написал отдельный модуль для разблокировки ачивок. В-третьих, были жёсткие ограничения по памяти и производительности: игра не могла бесконечно расти в контенте, иначе рано или поздно уперлась бы в потолок возможностей Flash.
Тем не менее, к релизу в сентябре 2011 года The Binding of Isaac включала всё, что задумали Эд и Флориан. Игра вышла на PC и неожиданно стала хитом. Этому помогли летсплеи и сарафанное радио – мрачный сюжет про ребёнка, спасающегося от фанатичной матери, привлёк внимание, а увлекательный геймплей заставлял игроков снова и снова спускаться в процедурно сгенерированные подземелья.
Макмиллен оперативно выпустил первое крупное дополнение Wrath of the Lamb в 2012 году, расширив игру примерно на 70% контента. Но тут Flash дал о себе знать во всю силу: на создание DLC ушло целых полгода — вдвое больше, чем на саму оригинальную игру. Причиной стали технические проблемы: масштабировать флеш-игру оказалось нелегко. Эдмунд честно попытался начать работу над вторым дополнением и даже расписал идеи на бумаге, но в итоге отложил их в долгий ящик, возиться с ActionScript ещё раз ему категорически не хотелось.
Ситуацию спас случай. В 2012 году с Макмилленом связалась компания Nicalis, известная портированием инди-игр вроде Cave Story на консоли. Они предложили перенести Isaac на совершенно новый движок и выпустить на консольных платформах. Эдмунд согласился при условии, что игру перепишут с нуля, добавят всё вырезанное/задуманное и улучшат графику (оригинал использовал векторную флеш-графику, а хотелось пиксель-арт 16-битного стиля).
Так началась работа над ремейком The Binding of Isaac: Rebirth, которая заняла около двух лет и финишировала релизом в ноябре 2014-го. Код перевели на C++ с использованием собственного игрового движка Nicalis, что дало громадный прирост производительности и освободу от ограничений Flash. Игра наконец-то задышала полной грудью: 60 FPS без просадок, куча нового контента, кооперативный режим, поддержку геймпадов и выпуск на PS4/PS Vita, а позже и на Xbox, Nintendo 3DS/Switch и других платформах. Проект эволюционировал из флеш-скромняги в полноценный «roguelike of the year».
Прежде чем перейдём к техническим деталям, забавный факт из той эпохи разработки: в роли главного тестировщика оригинального Isaac выступила... жена Макмиллена, Даниэлла.

Пока Эд вручную наращивал контент, Даниэлла играла сотни часов, осваивала механики и давала честный фидбэк. Специальных QA-инженеров не нанимали – инди-разработчик предпочёл наблюдать за реакцией реального игрока за плечом, чем платить профессиональным тестерам, которые «будут чувствовать себя обязанными искать баги и не получат удовольствия». Эта философия прошла красной нитью: когда игра вышла, тысячи игроков сами стали тестерами. Макмиллен признаётся, что буквально через пару дней после релиза сообщество завалило их письмами о багах, и 90% ошибок удалось исправить в первые двое суток патчами. Такой вот интересный подход к качеству: релизнуть и быстро чинить.
Генерация подземелий: простой алгоритм с гениальными деталями
Одна из причин, почему Binding of Isaac зацепила игроков – это практически бесконечное разнообразие уровней. Каждый забег генерируется случайно, и разработчики придумали очень интересный алгоритм, который был реализован за считанные недели, но до сих пор поражает своей эффективностью. Давайте разберёмся, как игра строит свои подземелья.
Каждый этаж в Isaac представляет собой набор комнат на сетке 9×8. Можно думать о сетке координат от 11 до 79 (где десятки – Y, единицы – X).

Начальная комната героя всегда находится примерно в центре, в клетке 35. От неё во все стороны растёт лабиринт комнат. Процесс генерации упрощённо выглядит так:
Сколько комнат будет на этаже? Число рассчитывается формулой
random(2) + 5 + level * 2.6
. Проще говоря, на первом этаже обычно 7–8 комнат, и с каждым последующим этажом прибавляется ещё по 2–3 комнаты. Таким образом, игра масштабирует размер уровней по мере продвижения вниз, делая геймплей длиннее и сложнее.Раскладка комнат (floorplan). Изначально на сетке помечена только стартовая комната (35), помещённая в очередь на обработку. Алгоритм берет комнату из очереди и пытается расшириться от неё в случайные направления (вверх, вниз, влево, вправо). Для каждой из четырёх сторон проводится несколько проверок: (a) нет ли там уже комнаты; (b) нет ли у новой клетки больше одного соседя (чтобы не образовать петлю); (c) не набрано ли уже достаточно комнат по плану этажа; (d) пройдёт ли бросок монетки (50% шанс). Если все условия выполняются, на соседней клетке создаётся новая комната, и она добавляется в очередь. Затем алгоритм берёт следующую комнату из очереди и повторяет процедуру. Таким образом, генерация идёт «волной» от стартовой точки – это типичный обход в ширину (BFS) для неслучайного генератора. Ограничение «не более одного соседа для новой комнаты» фактически гарантирует, что структура подземелья получится древообразной (то есть без циклических петлей). Получается некий лабиринт-коридор с разветвлениями. Комнаты, из которых расширение не пошло (ни одна соседняя клетка не подошла под условия), считаются концовыми тупиками (dead ends) и сохраняются в списке концовок этажа. Кстати, если генерируется большой этаж (скажем, должно быть больше 16 комнат), алгоритм может несколько раз повторно добавить стартовую комнату обратно в очередь, чтобы простимулировать рост в новые стороны и не получить слишком длинную цепочку.
Проверка и коррекция плана. После того, как необходимое количество комнат набрано, генератор делает валидацию: например, убедится, что комната босса не примыкает непосредственно к стартовой (это было бы слишком легко). Если какие-то ключевые условия нарушены, план этажа отбрасывается и генерируется заново. Но обычно всё сходится.
Специальные комнаты. Когда каркас лабиринта готов, игра помечает некоторые комнаты как особые. Правила тут такие: комната босса всегда ставится в самом дальнем от старта тупике – это логично, игрок должен проделать путь через весь этаж. Комната с сокровищем (бесплатный артефакт) обычно тоже генерируется всегда и привязывается к одному из отдалённых тупиков. Магазин – в другом тупике. Кроме того, могут случайно появляться: комната-сакрификус (с шипами и алтарём), комната-проклятие (с порталом, требующим здоровья), мини-боссы, казино с автоматами и т.д. Большинство из них имеют определённый шанс или условия появления. Например, комната жертвоприношений (Sacrifice Room) генерируется примерно на одном из 7 этажей, но если у игрока полное здоровье, шанс её появления резко возрастает до ~30% – очевидно, чтобы соблазнить полного здоровья игрока рискнуть лишними сердцами. Такие мелочи геймдизайна прошиты прямо в генератор. Секретная комната – отдельная история: она всегда должна быть на этаже, но она не вписывается в общую древовидную структуру (ведь секретки обычно смежны с 2–4 другими комнатами сразу). Поэтому алгоритм делает пост-процесс: он случайным образом ищет подходящую пустую клетку, которая граничит минимум с тремя уже существующими комнатами (и при этом не граничит с тупиками). Найдя такую точку, он вставляет туда секретную комнату, даже если у неё несколько соседей – это исключение из правила без циклов. Если за 300 попыток подходящее место не найдено, условия чуть смягчаются, а после 600 попыток – ещё сильнее, так что в конечном счёте секретка разместится гарантированно, пусть иногда и не идеально. В результате секретные комнаты обычно оказываются «втиснуты» в перекрёстки коридоров, где вокруг них 3-4 других комнаты – самое логичное место с точки зрения ощущения игрока.
Наполнение комнат. Последний этап – выбрать, что именно находится внутри каждой комнаты. Здесь Isaac тоже применяет простой, но эффективный подход: у игры есть заранее подготовленный пул шаблонов комнат. Шаблон определяет и схему препятствий (камни, ямы, шипы, огоньки), и набор врагов, и возможные бонусы. Для обычных комнат существует три категории сложности шаблонов: лёгкие, средние и сложные. На первых этажах используются в основном лёгкие и средние варианты, на более глубоких – средние и сложные. Например, для первой главы (Basement) в оригинальном Isaac было подготовлено 174 варианта планировки комнаты. При генерации каждая непустая комната случайно берет один из подходящих шаблонов соответствующей главы и категории сложности. Чтобы не было повторений, могут быть проверки «не использовать дважды один и тот же шаблон на этаже». Кроме того, на этапе наполнения применяются дополнительные случайные модификации: может появиться пара чемпионов среди монстров (усиленные версии), могут покраснеть некоторые камни (скрытые сундуки), огоньки иногда генерируются синими (стреляющими) и т.д. В сумме эти случайности добавляют разнообразия даже внутри одного шаблона.
Стоит подчеркнуть, насколько изящно отделены друг от друга этапы генерации плана лабиринта и наполнения комнат. Сначала формируется топология уровня (граф комнат), а потом в него вкладывается контент. Благодаря этому подходу разработчики могут легко менять обе части независимо. Именно поэтому The Binding of Isaac так любит моддеры и исследователи: алгоритм сравнительно простой, его можно воссоздать и улучшать под свои нужды. Сам Флориан Химсл, программист оригинального Isaac, написал генератор буквально за пару дней, но заложил прочный фундамент для всех будущих расширений.
Rebirth: расширенные комнаты и новые фишки генерации
Ремейк Rebirth в 2014 году не стал кардинально переделывать алгоритм генерации – а и не было нужды. Вместо этого разработчики из Nicalis аккуратно дополнили его новыми возможностями. Главное новшество: появились комнаты нестандартного размера. Если в оригинальном Isaac все комнаты были одинаковыми квадратами 13x7 тайлов, то в Rebirth добавили большие комнаты: двойные (2×1 или 1×2 на сетке), огромные (2×2), Г-образные и длинные коридоры. Это сильно разнообразило геймплей – большие открытые пространства или извилистые залы требуют иной тактики боя. Но с точки зрения генератора пришлось внести изменения.

Реализация больших комнат была выполнена программистом Никалис Саймоном Парцером, тщательно и бережно по отношению к исходному коду Химсла.
В оригинале при росте лабиринта рассматривались четыре направления (вверх/вниз/влево/вправо) из каждой комнаты. Теперь же комната могла иметь до 8 выходов (представьте 2×2 зал – дверь может быть в каждой из 4 сторон и по центру каждой из сторон, ведущая в примыкающие малые комнаты). Поэтому алгоритм расширения был обобщён: вместо фиксированных четырёх направлений он проходит по всем потенциальным дверям текущей комнаты. Если комната большая, у неё больше соседних клеток, которые она может занять. При добавлении новой комнаты алгоритм случайно решает, сделать ли её большой: с определённой вероятностью пытается занять сразу блок 2×2 или 2×1 клеток вместо одной.
Конечно, он проверяет, что место свободно для всего размера, иначе попробует другой вариант или сдастся. Интересно, что большие комнаты вносят редкие нарушения в прежнее правило «без петель»: например, две 2×2 комнаты могут сгенерироваться по соседству и автоматически получат две двери друг к другу, формируя небольшое кольцо. Но в контексте игры это не проблема, а скорее бонус – небольшие петли из двух залов встречаются и добавляют разнообразия. Босс-комнаты тоже научились быть большими: генератор может заменить обычный тупик босса на зал 2×2, если далеко от стартовой комнаты есть место под такого монстра. Правда, он следит, чтобы огромная комната босса не прилегала сразу к нескольким путям, оставаясь концом лабиринта. Если где-то нельзя разместить большого босса, игра всё равно откатится к стандартной маленькой комнате – лишних циклов генерации на эту проверку уходит немного.
Добавление крупных комнат потребовало переработать и стадию наполнения: теперь при выборе шаблона комнаты нужно учитывать размер и форму. На каждую новую форму уровней дизайнеры нарисовали наборы макетов (например, комнаты Г-формы с разным расположением препятствий). Также некоторые шаблоны теперь отмечены тэгами, что, скажем, для L-образной комнаты, к которой фактически примыкают две другие комнаты, не стоит генерировать лишние двери в тупики. Эти детали в основном были реализованы на этапе DLC Afterbirth+, когда с ростом количества контента потребовалась тонкая настройка генератора.
В остальном же принципы остались прежними – мощь Rebirth была скорее в производительности. C++-движок позволил без проблем увеличить количество уникальных комнат, врагов и предметов на порядки. Если оригинал (с DLC) имел ~198 предметов, то к 2021 году с финальным дополнением их стало около 700. Количество возможных комбинаций выросло экспоненциально – и тут мы подходим к ещё одной знаковой фиче Binding of Isaac: системе предметов и их взаимодействий.
Предметы и сумасшедшие комбинации
В The Binding of Isaac герой по ходу игры находит десятки всевозможных предметов, меняющих его характеристики, атаки и способности. Это сердце игры: рогалик затягивает тем, что каждый ран совершенно не похож на предыдущий благодаря разным наборам артефактов. Но с точки зрения разработчика, реализация такой системы – тот ещё вызов. Нужно учесть сотни эффектов и их пересечение друг с другом. Как сделать так, чтобы любые два (и более) предмета логично сочетались, не ломая игру? Признаюсь, я был впечатлён тем, как это реализовано.

Начнём с базового: у персонажа есть параметры (здоровье, скорость, урон, дальность, скорость атаки и т.д.) и тип стрельбы (по умолчанию – слёзы, летящие по дуге). Каждый предмет может изменять параметры или заменять способ атаки, накладывать какие-то статусы и правила. Некоторые предметы простые: +1 к здоровью, +0.3 к скорости, всё ясно.
А некоторые полностью меняют геймплей – например, Brimstone превращает ваши слёзы в мощный лазер, заряжаемый перед выстрелом; Dr. Fetus заменяет слёзы на бомбы; The Lost Contact делает слёзы щитами, которые могут отражать вражеские снаряды. Таких радикальных модификаторов много, и естественно возникает вопрос: что если игрок возьмёт несколько подобных? Что, если у вас и лазер, и бомбы одновременно? Или две разные модификации слёз?
Ответ: в Isaac реализована система приоритетов и специальных сочетаний, так называемые synergy. По сути, код игры проверяет ключевые предметы и решает, как они взаимодействуют. Иногда один модификатор просто заменяет другой (например, если у героя одновременно лазер Brimstone и бомбы Dr. Fetus, игра отдаст приоритет лазеру или сделает лазер, стреляющий бомбами – точно не помню конкретно эту комбинацию, но принцип понятен). Однако в многих случаях разработчики специально прописали уникальные эффекты для комбинаций. Классический пример – сочетание Brimstone (кровавый лазер) и Technology (беспрерывный лазер): изначально в ранних версиях эти два предмета плохо работали вместе, но позже, в одном из патчей, их заставили дружить. Теперь если собрать оба, вокруг вашего основного лазерного луча Brimstone будет обвиваться спираль из технологических лазеров, что не только выглядит круто, но и дает бонус к урону. Другой пример – Tech X (заряжаемые кольца-лазеры) плюс Brimstone: вместо того чтобы просто заменить один снаряд другим, игра выпускает гигантские кольца огненного лазера. Таких синергий десятки, если не сотни – и с каждым дополнением разработчики добавляли новые.
Честно говоря, просчитать все комбинации заранее нереально. Макмиллен признавался, что на этапе первого релиза они выпустили игру практически без балансового тестирования всех сочетаний – слишком много вариантов, «нужно сотни тестеров, чтобы все пройти». Поэтому многие взаимодействия выяснялись уже после выхода. Где-то баг фиксили, где-то, наоборот, обнаружив забавную комбинацию, её превращали в фичу. Сообщество энтузиастов и датамайнеров проделало огромную работу, документируя все предметные взаимодействия (на фанатских вики есть целые таблицы, что с чем сочетаетcя). Например, известно, что если у персонажа одновременно несколько модификаторов слёз, игра применяет их в определённом порядке при расчёте выстрела. Некоторые эффекты могут складываться, некоторые – нет. Если принести на боссов Chaos Card (убивает с одного попадания) и Blank Card (копирует эффект карт), то, возможно, вы ожидаете бесконечный запас инста-киллов. Но нет – разработчики предусмотрели такой абьюз и сделали так, что Blank Card перестаёт работать с Chaos Card после одного использования, чтобы не ломать баланс. Подобных нюансов масса.
Технически реализация системы предметов – это, по сути, большое количество условных проверок в коде, которые применяются при различных событиях: подбор предмета, выстрел, попадание по врагу, получение урона и т.д. В объектно-ориентированном мире можно представить, что у героя есть список модификаторов, и каждый из них подписывается на определённые события игрового цикла. Когда событие происходит, модификаторы либо меняют параметры героя, либо создают особый эффект. Если несколько модификаторов пытаются изменить одно и то же (например, форму слёз), срабатывает либо последний собранный, либо особый обработчик, комбинирующий их. Например, знаменитое сочетание Chocolate Milk (заряжаемые выстрелы) и Brimstone (лазер) приводит к тому, что лазер тоже становится заряжаемым – это явно запрограммированный сценарий, а не случайность. Игра фактически содержит множество специальных случаев, написанных руками разработчиков или добавленных в патчах по просьбам фанатов.
При этом часть удовольствия Isaac – это именно экспериментирование. Разработчики не считают нужным разжёвывать игроку механики. Долгое время в игре вообще не было официального описания предметов – только картинки и догадки. Лишь в 2022 году, спустя 11 лет после выхода, патч наконец добавил внутриигровую энциклопедию артефактов (до того все бегали на внешний вики-сайт). Это, кстати, тоже заслуга комьюнити: фанаты столько лет просили подсказки, что Макмиллен смягчился.
В общем, система предметов в Binding of Isaac – пример хаоса, возведённого в абсолют. Но, как ни странно, этот хаос держится на довольно прочном каркасе из правил и исключений. И каждый новый контент (а дополнений у игры несколько) встраивался в эту систему с некоторыми жертвами – иногда старые комбинации приходилось менять или нерфить. Зато к 2021 году игру довели до состояния своеобразного идеального безумия, когда одновременно могут работать десятки эффектов, а игрок буквально превращается в ходячий адский смерч – и это нормально.
Моды и фанатские улучшения
Не будет преувеличением сказать, что долгую жизнь The Binding of Isaac поддерживает его сообщество. Разработчики с самого начала наблюдали, что фанаты копаются в файлах, придумывают свои режимы и даже находят способы модифицировать флеш-версию. В ремейке Rebirth на старте модов не было, но после выхода второго DLC (Afterbirth+) в 2017 году игра получила официальную поддержку моддинга. Технически это вылилось в интеграцию языка Lua: разработчики добавили скриптовый API, через который можно создавать новые предметы, врагов, комнаты, ивенты и прочее.
Основная игра по-прежнему написана на C++, но при загрузке модов движок просто исполняет дополнительный Lua-код, реагируя на события. Это очень похоже на то, как устроены моды в World of Warcraft или Garry’s Mod: игра предоставляет функции типа OnUpdate, OnEnemyKilled, SpawnEntity и т.п., а любительский скрипт уже делает с этим что хочет. Макмиллен пошёл дальше – он стал регулярно включать лучшие фанатские модификации в официальные обновления. Каждый месяц он просматривал топовые моды и некоторые из них перенимал в штат, слегка дорабатывая. По сути, часть контента Afterbirth+ и особенно финального DLC Repentance – это работы сообщества.

Repentance вообще изначально был крупным фанатским модом Antibirth, чьи авторы в итоге официально присоединились к команде и вместе с Nicalis интегрировали весь свой мод в игру. Представьте, не проходило и дня релиза Repentance, а в нём уже были сотни часов геймплея, созданного фанатами – случай почти беспрецедентный в индустрииm.
Конечно, не обошлось без технических хитростей. Фанатский мод Antibirth был сделан ещё до появления Lua-API, поэтому умельцы написали собственные инструменты для модификации бинарника Rebirth. Существовала библиотека LibZHL, позволявшая расширять игру на низком уровне (через injection в исполняемый код). С её помощью моддеры добавили новые механики, интерфейсы и даже кооперативный режим задолго до официального. Многие идеи Antibirth казались настолько крутыми, что Макмиллен решил: нужно брать их в канон. Команде Nicalis пришлось частично переписывать и рефакторить свой же код, чтобы совместить две ветки – официальную и моддерскую. Но результат того стоил: Repentance стал, по сути, ультимативной версией The Binding of Isaac, вобравшей всё лучшее из 10 лет разработки, дополнений и фанатского творчества.
Заключение
История Binding of Isaac – это история о том, как маленький инди-проект перерос свои рамки и эволюционировал вместе с технологиями. От флеш-прототипа, собранного на коленке за несколько месяцев, до масштабной платформы, живущей больше десятилетия – во многом благодаря удачным техническим решениям, заложенным с самого начала. Простая и модульная генерация уровней позволила игре сохранять свежесть даже после сотен часов. Гибкая система предметов, хоть и хаотичная на первый взгляд, дала простор для сотен безумных комбинаций и ситуаций. Переход на C++-движок открыл дорогу к стабильной работе и росту контента без страха «сломать флеш». А открытость к моддингу и сотрудничество с сообществом привели к тому, что фанаты сами стали частью разработки, буквально вписав свои идеи в официальную версию.
The Binding of Isaac – отличный пример, как грамотная техническая архитектура (разделение генерации и контента, использование скриптов, продуманные ограничения) позволяет игре расти и усложняться, не превращаясь в неподдерживаемый комок кода. Конечно, не обошлось без курьёзов.
Спустя годы Isaac всё ещё ощущается живым. Каждый патч, каждый мод продолжают расширять грани этой игры. И, оглядываясь на её путь, невольно вдохновляешься: даже из самого маленького джем-проекта может вырасти нечто великое. Достаточно капли таланта, горстки технических ухищрений и тонны страсти к своему делу. Игре, начавшейся с истории про жертвоприношение, удивительно идёт такой хэппи-энд.
Если вам интересно, как строятся миры и истории в играх, обратите внимание на курс «Сценарист игр» и Нарративный дизайнер». Вы познакомитесь с принципами создания сюжетов, персонажей и диалогов, а также научитесь превращать идеи в игровые сценарии, которые работают вместе с механиками.
На странице курса можно записаться на бесплатные открытые уроки, которые проведут преподаватели курса.
А тем, кто настроен на серьезное системное обучение, рекомендуем рассмотреть Подписку — выбираете курсы под свои задачи, экономите на обучении, получаете профессиональный рост. Узнать подробнее