Всем привет! Я хочу рассказать историю разработки игры на Delphi от идеи до релиза.
Статья больше носит характер истории, без вникания в подробности реализации. Честно говоря, очень хочется написать про то, как мы строим картинку в игре, или локализуем её, как мы делали GUI, но это я выделю в отдельную статью, больше техническую, с кодом. Иначе эта окажется слишком большой. Кода тут не будет, но детали под катом. Прошу!
Application.Initialize;
Итак. Игра наша придумана была давно для конкурса разработки игр (джема) IGDC №77 — джампер Это было начало 2012 года. Игру мы делали в состоянии перманентного кранча аж две недели. Код вышел ужасным. Расширять было невозможно, порой возникали необъяснимые глюки, но в целом игра работала и некоторые товарищи умудрялись проводить в ней дни, недели. Пара человек залипали в течение месяца. Стало понятно, что реиграбельность у неё хорошая и надо бы её доделывать. Но, как я сказал выше, код был ужасен из-за скомканных сроков, так что доделок было сделано не очень много и всё благополучно забыто.
Выглядело это тогда так:
Для сравнения сейчас это выглядит так:
While true do
Забыто было почти до 2014 года. Тогда мы собрались и начали делать всё снова. С капитальным подходом к архитектуре. Были заложены такие вещи как менеджер игровых режимов, система динамической локализации, поддержка любых разрешений, достижения и прочее, прочее, прочее… Всё на классах, всё унаследовано, перекрыто. Что не в классах, а глобально, то в статических классах. Вообщем подошли к вопросу очень отвественно. Про игру, правда, около года благополучно забывали. Было там что-то, отдаленно напоминающее давний прототип, но до него не дотягивало ни по контенту, ни по интересности. Прокрастинировали активно и долго, короче. Вот меню именно тогда собрали, я сделал планеты и даже статью по ним на Хабре.
Польза от такой прокрастинации, тем не менее, была. Позже все эти вещи помогли избежать вороха проблем, поскольку были реализованы в фундаменте. Локализация, например, была решена посредством XML файлов, прямо перед релизом к нам постучался итальянец, Франческо и предложил перевести игру. Сделал всё сам, мы нарисовали нужные символы в шрифте и игра за неделю обзавелась итальянским. Легко и просто. Из этого как минимум один вывод сделать стоит — не забивайте на локализацию, сделайте её пораньше. И желательно не в ущерб геймплею.
For feature in coolthings do
Когда мы начали делать игру, мы смотрели, на лучшие моменты в разных играх, но больше всего оглядывались на Blizzard. О да, это очень крутая контора, они делают крутые игры и каждая хит. А еще каждая проработана до мелочей. И это нас безумно цепляло. Поэтому я, как поклонник Diablo и мой коллега как поклонник WarCraft и StarCraft смотрели на них часто. Так было решено что, например, достижения или друзей надо иметь возможность просматривать прямо из игры, без оверлеев или выхода. Так и появились такие мелочи, как часы в углу, как затухающая музыка при alt+tab, возможность прослушать любой трек из меню, в любой момент подключить геймпад и играть не перезапуская, показывать достижения прямо в игре и многое другое.
Игру мы делали почти всё время вдвоем. Два программиста. Графику или рисовал сам, или генерировал спрайты с помощью FilterForge Под конец разработки мы заказали графику для врагов, купили иконки в ассетсторе, звуки. Музыку нам делали на заказ и музыка появилась еще год назад. Музыку не просто написали нам, так еще и сводили на проф. оборудовании в студии. Треки получились отличные, и очень в настроение игры.
Case build of release
Код. Код мы пишем на Delphi 10.1 на текущий момент, а движок используем свой Quad-engine, тоже написанный на делфи с открытым исходным кодом. Разработка игры, кстати, безумно помогает сделать движок действительно полезным и удобным. Мы давно работаем в делфи и нам удобен этот инструмент, но даже тут не обошлось без косяков. В одном из модулей GUI сборка под релиз и дебаг работала по разному. Внезапно оказалось, что пункт «оптимизация» в релизной версии почему-то делает одну из переменных True в случаях, когда она должна быть False. И GUI начинает вести себя неадекватно. Ассемблерный код разный и результат тоже. Решение выбрано не самое лучшее было, но мы отключили пункт «оптимизация» воимя одинакового с дебагом результата.
Во время разработки мы столкнулись с тем, что пришлось выкинуть почти все наработки по геймплею за почти что год, и переделать все заново. Отказаться пришлось и от Box2D, сильно осложняющим решение наших задач. Одна из проблем была в том, что Box2D всё считает в мировых координатах, а у нас скорости и вектора могут быть очень большими. На потерях точности возникали проблемы. Например пушка босса могла отставать от босса. Его расчеты проходили итеративно, как бы мы не старались (возможно плохо старались), но нам не удавалось достаточно синхронизировать картинку с физикой. Поэтому мы взяли и воспользовались своей физикой из прототипа, разумеется с доработками. Например все расчеты физики у нас происходят в экранных координатах, что решает проблему огромных скоростей и значений. Физика из прототипа умела работать только с горизонтальной линией и кружочками. Здесь же физику научили и другим фигурам. соединениям, слоям, типам объектов и пр.
Также мы сделали хорошую систему частиц, но она не пригодилась. Не пригодился и наикрутейший редактор в стиле Warcraft3, позволяющий мышкой делать всё что угодно. В меру своей сложности и запутанности связывать его с достижениями, например оказалось сущим адом. Так было выкинуто суммарно около года разработки моего коллеги ZblCoder. И он начал писать весь геймплей снова. Но на удивление наверстали мы всё менее чем за месяц, а дальше пошел рост.
В итоге, в сухом остатке, можно сказать, что где-то из трёх лет разработки (были перерывы довольно длительные, так что реально затрачено было 1.5-2 года свободных вечеров) можно было бы игру сделать вдвое быстрее, не делай мы ненужных вещей. Но без граблей обойтись невозможно, поэтому времени ушло много. Основа графического движка к тому моменту была уже вовсе не основой. Я реализовал огромное количество шейдерных эффектов, и безшейдерных трюков для достижения сочной, динамичной картинки. Игра у нас, к слову сказать полностью двумерная.
Game.Draw;
Нормалмаппинг, объемное освещение, искажения пространства, параллакс маппинг и куча более мелких, но не менее важных шейдеров. Шейдерами делается практически всё. От цветокоррекции до переливания щитов. Многие эффекты вы можете и не заметить, или подумать что они нарисованы заранее, но нет. Они делаются «на лету».
Вот, например, скриншот без цветокоррекции:
function IsThereTroubles: Boolean; abstract;
Многие из тех, кто играли, утверждали потом, что скриншоты и видео не передают вообще никак настроение и увлекательность процесса, пускай и довольно простого. И эту проблему мы так и не смогли решить. Как же показать что оно интереснее, чем выглядит?
Основной проблемой до сих пор остаётся баланс. Для одних игра достаточно проста, для других невообразимо сложна. В большинстве случаев сложной она кажется оттого, что люди начинают без разбора стрелять во всё что движется, игнорируя подсказки и пытаясь действовать интуитивно, но неверно. Некоторое время спустя приходит осознание и человек начинает понимать как играть, получать удовольствие и снимать стресс.
Для подогрева интереса к игре, чтобы игрок не разочаровался в себе и не бросил сразу, если дела идут не очень круто, мы добавили в игру соревновательную составляющую. Определенные виды статистики сохраняются и друзья могут сравнить свои результаты с вами, а вы с друзьями. Кроме того опыт и открывание новых умений с каждым «левелапом» тоже помогает посидеть в игре чуточку дольше.
Target platforms (Win32)
После запуска игры в ранний доступ мы столкнулись с проблемами, о которых даже и представить не могли во время разработки. Первый же стример, который собрался стримить игру не смог этого сделать, так как обладал довольно особенной конфигурацией ПК. У него было 2 монитора с разным разрешением и подключены они были в разные видеокарты. В дискретную nVidia и интегрированную Intel. Наш движок не смог осилить такого хаоса и рушился при старте. Проблему, конечно, победили, но время было упущено.
Другой интересной проблемой стало падение Steamworks API при попытке получения информации о друзьях. На наших аккаунтах с 40-50 друзей все было «ОК», но вот у стримеров и летсплееров, где друзей было по 500+ оно где-то посередине списка падало по необъяснимым причинам. Так мы чуть не упустили еще пару стримеров, но поправить удалось очень быстро. В тот же день был сделан хотфикс.
Дальнейшая судьба игры — доработка, расширение. Крайне с удовольствием слушаем любую обратную связь, предпринимаем действия, помогающие сделать всё еще лучше. Сделаем Делфи снова великим!
Я добавил небольшой опрос в конце, буду благодарен за честный ответ.
Автор: Darthman