700.000 строк кода и 20 лет разработки Dwarf Fortress | Интервью Тарна Адамса

В июле 2021 этого года на StackOverflow выходило интервью Тарна Адамса, программиста знаменитой игры Dwarf Fortress. Я решил сделать для вас перевод со вспомогательными ссылками. Интервью может показаться весьма интересным для интересующихся геймдевом.

700.000 строк кода и 20 лет разработки Dwarf Fortress | Интервью Тарна Адамса

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

Райан Донован, Редактор stackoverflow.blog

Разработка игры началась ещё в 2002 году. Сначала это было больше как хобби, однако после выхода в 2006, Тарн решил покинуть работу преподавателя и полностью посвятить себя разработке проекта. На сегодняшний день над проектом по-прежнему работает Тарн вместе со своим братом Заком, также помощь им оказывает издатель Kitfox Games.

В: Какими языками программирования и технологиями вы пользуетесь? Изменилось ли что-нибудь за 15-20 лет разработки?

О: DF — это некая смесь С и С++, при чём не в привычном понимании стандартизированного подчинения, а скорее это некий беспорядок, который только нарастает со временем. Я использовал Microsoft Visual Studio с MSVC 6, сейчас же я использую Visual Studio Community.

В качестве движка я использую OpenGL и SDL. Они были выбраны, так как легче всего переносят на системы OSX и Linux, хотя я, конечно, не мог сделать этого сам. Я не уверен, что использовал бы что-нибудь по типу Unity или Unreal, так как не умею использовать их . Но поддержка своего собственного движка — это настоящая боль, особенно сейчас, когда я делаю что-то кроме ASCII графики. Для звуков я использую FMOD.

Ничего не меняется на протяжении всей разработки проекта, кроме SDL, на введение которого было затрачено несколько лет. Касательно механики, то я не использую большого количества сторонних библиотек. Но иногда нахожу некоторые для генерации случайных чисел. Сначала я работал с Mersenne Twiste, а совсем недавно добавил SplitMix64, о котором я рассказывал на прошедшем Roguelike Celebration.

Обновлённая графика <a href="https://api.dtf.ru/v2.8/redirect?to=https%3A%2F%2Fstore.steampowered.com%2Fnews%2Fapp%2F975370&postId=953228" rel="nofollow noreferrer noopener" target="_blank">Источник</a>
Обновлённая графика Источник

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

О: Намного легче его забыт. При подсчёте количества «;», что является простым, но не самым точным методом, мы получим около 711 тысячи строк. Я стараюсь давать имена моим переменным и объектам, оставляю множество комментариев, чтобы легче было вспомнить, за что отвечает эта часть кода. Иногда это занимает несколько шагов, чтобы отыскать нужную нить, иногда приходится обращаться к тем участкам кода, которые я не трогал десять лет, что случается часто. Я бы сказал, что большинство изменений сфокусированы на частях кода, которые я уже знаю достаточно хорошо. Но до сих пор остаются участки, на которые я не обращал внимание с 2006 года.

Говоря о сложности работы в одиночку, то для меня, человека, который никогда не работал в команде, это верный путь. Люди хорошо научились работать в команде, например в AAA играх им необходимо иметь несколько специалистов чтобы делать всё вовремя. Я не скажу, что смогу модифицировать код быстрее, чем они, потому как никогда не работал в команде, но в чём правда, так это в том, что у меня нет никаких бюрократических преград. Я могу просто взять и сделать это. Но делать приходится в одиночку.

700.000 строк кода и 20 лет разработки Dwarf Fortress | Интервью Тарна Адамса

В: Самый крупный рефакторинг или изменение, которое вам приходилось делать?

О: Были некоторые рефакторинги, которые длились месяцами. Я переделывал определенные структуры данных, но я бы не назвал это полноценным рефакторингом, так как всё ещё мог добавлять какие-то механики параллельно.

Добавление оси Z для преобразования игры в 3D (оставаясь при этом плоской ASCII) было одним из самых ошеломляющих изменений, что я когда-либо делал. Долгие недели на то, чтобы разобраться в логике и вызовах функций, основанных на X и Y, в которые должна была вписываться ось Z.

В конечном итоге сделать систему предметов полиморфной было большой ошибкой.

В: Почему это было ошибкой?

О: Когда вы объявляете класс определённого типа «предмет», он фиксирует вас в этой структуре гораздо сильнее, чем если бы у вас были только объекты класса «элемент». Приятно иметь возможность использовать виртуальные функции и тому подобное, но компромиссов слишком много. Я начал использовать класс «инструмент» в иерархии, который начал получать различную функциональность, и теперь может поддерживать что угодно: от стремянки до улья и ступки (и пестик отдельно, ха-ха), и он просто кажется более гибким, и я хочу, чтобы каждый созданный предмет в игре находился под этим зонтиком.

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

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

700.000 строк кода и 20 лет разработки Dwarf Fortress | Интервью Тарна Адамса

В: Я видел, как другие игры, похожие на DF, тормозят из-за своих алгоритмов поиска пути. Что вы используете и как поддерживаете его эффективность?

О: Да, базовый алгоритм — это только его часть. Мы используем A*, что, конечно, быстро, но само по себе недостаточно. Мы не можем воспользоваться некоторыми нововведениями в этой области (например Jump Point Search) потому как наша карта очень сильно меняется. Как правило, разработчики используют подходы, которые добавляли различные более крупные структуры поверх карты, чтобы срезать углы,
и из-за постоянно меняющейся карты их поддержание занимает слишком много времени. Таким образом, наш подход заключался в том, чтобы просто отслеживать соединённые компоненты, до которых можно добраться пешком. Такой алгоритм легко обновляется, даже если карта меняется быстро, хотя он немного использует алгоритм заливки. Например, если вода рассекает крепость пополам, ему нужно затопить с одной стороны и обновить целую половину крепости до нового индекса. Затем это позволяет нам исключить из игры почти все неудавшиеся вызовы A*: наши агенты просто запрашивают номера компонентов и, если номера компонентов совпадают, они знают, что вызов будет успешным.

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

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

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

В: К слову, вы моделируете множество вещей одновременно: как вам удается асинхронно управлять таким количеством акторов (и вы вообще делаете это)?

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

Новые спрайты различных рас
Новые спрайты различных рас

В: Пробовали ли вы делать другие проекты помимо DF?

О: Конечно! Папка сторонних проектов, которая перемещалась между компьютерами за последние десять лет или около того, содержит около 90 проектов. Некоторые из них длились несколько дней, другие — несколько лет. В основном это другие игры, почти всегда других жанров, но есть также несколько дополнительных проектов к DF, например прототип генератора мифов. Они все далеки от завершения, но разрабатывать их достаточно интересно.

В: Изучали ли вы в своих сторонних проектах какие-либо другие языки программирования? Если да, то есть ли какие-нибудь любимые?

О: Ха-ха, нет! Я больше занимаюсь дизайном, нежели технологиями. Я уверен, что некоторые вещи действительно могут ускорить реализацию моих проектов, поэтому мне, вероятно, следует хотя бы выучить скриптинг и лучше изучить потоки. Некоторые люди предлагали библиотеки и вещи, чтобы помочь, но просто трудно остановить побочный проект для обучения, когда мое время побочного проекта — это время для отдыха.

В: У вас очень интересные описания к обновлениям. Какой ваш любимый баг и чем он был вызван?

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

А это Jojo, домашний кот Тарна :3
А это Jojo, домашний кот Тарна :3

Ещё пара интересных материалов по DF на DTF:

355355
85 комментариев

кошки были обнаружены мертвыми по всему полу таверны, и оказалось, что они глотали пролитый алкоголь, когда лизали свои лапыЯ обожаю эту игру. Вообще мне нравится что во многих старых играх (и дф) многие объекты принадлежат к одним классам и на них работают одинаковые принципы. Т.е НПС в YS (даже небоевые) могли качаться как и игрок просто потому что они объекты такого же типа, а в рогаликах например все *горящие* сущности могли поджечь любую *возгораемую* сущность, ну или в этом примере, кот - такая сущность как и дворф и у неё есть "лапы" которые могут промокать и он может слизать с них то что на них натекло.
Это куда круче чем когда у нас есть скриптовая сценка к которой нужно подкатить взрывающуюся бочку что бы сработал скрипт взрыва, при этом стенку нельзя взорвать гранатомётом или подкатить другую бочку из другой комнаты. Хотя разным играм разное, наверное.

71

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

11

До этого в ДФ коты обнаруживали что у них нет рук и спавнили сообщения об ощибке :)

5

Комментарий недоступен

10

Толсто.

54

Понимаю, если просто сказать, что такого рода игры не интересны, но зачем принижать чужой труд?

10