Quad-engine. Свой 2д движок. Когда приперло со всех сторон
Предисловие. Было начало 2010 года, когда я расстроился при просмотре очередного фреймворка с поддержкой Delphi. В тот момент я искал замену уже сильно устаревшему и заброшенному PowerDraw. Как говорится, тоже самое, только с перламутровыми пуговицами. Пересмотрев всё, что было из 2Д, я так и не нашел искомого. То не было шейдеров, то черезчур нагроможденный с точки зрения кода, то вообще какой-то убогий. А душа просила простоты использования и шейдеров.Поэтому я сел, и начал изобретать свой велосипед. Первое собранное приложение выглядело, конечно, не сильно впечатляюще:
Под катом прилично картинок.
В Марте был забронирован домен quad-engine.com, было нарисовано лого моим хорошим знакомым Weilard’ом и началась работа. На тот момент «движок» писался под игру типа собери-три, и одним из условий было обязательное наличие красивого бамп-меппинга с цветным спекуляром. В первых интерпретациях попытка сделать его была предпринята через мультитекстурирование, но результат оставлял желать лучшего. Так я лишний раз удостоверился что мне нужен мощный 2Д фреймворк с поддержкой шейдеров.
Как только с текстурированием, загрузкой и отрисовкой было покончено, сразу же все силы были брошены на прикручивание шейдеров (и пробы деллались с бамп-меппингом и спекуляром): По завершению реализации шейдеров (пока еще не в том виде, что сейчас), сразу стало понятно, что без поддержки вывода текста движком это будет назвать ну вообще никак невозможно. Поэтому я написал утилиту для генерации текустур и служебной информации из шрифтов. А с полученным результатом уже и поддержку вывода текста в движке.Кстати, вот она эта утилита:
Со шрифтами вышла история долгая, так как качество буковок, рендерящееся через DrawText на канву меня разочаровало быстро. В связи с этим было решено отказаться от такого подхода и рисовать каждую буковку самостоятельно, сглаживая грани так, как хотелось бы мне. Поэтому тут пришлось углубиться в получение векторного представления буковок от системы и растеризовать самостоятельно, получая в итоге карту символов:
В реальном приложении выглядело на тот момент это так:
С игрой три-в-ряд довольно быстро всё не сложилось и решили от проекта отказаться, но «движок» потихоньку рос и обзаводился новым функционалом. Мыслей было больше чем реализованных фич, а ядро пришлось пару раз серьезно переписать.
Шейдеры Под то, чтобы сделать их использование удобным и достаточно гибким ушло времени много, а еще больше ушло на то, чтобы разбираться и «играться» с шейдерами, писать свои. Например реализация вот такого эффекта была ограничена только умением писать шейдеры и фантазией. Обращу внимание, что это всё 2Д, как я и говорил. Однако, шейдеры, делают всё объемным, хотя в кадре только 2 треугольника: Шаг 1: Рисуем диффузную текстуру
Шаг 2: Рисуем тени на диффузной текстуре:
Шаг 3: Рисуем в рендертаргет карту высот, соотвествующую месту:
Шаг 4: Рисуем в другой рендертаргет карту нормалей:
Шаг 5: Накладываем parallax oclussion mapping шейдер:
Шаг 6: Увеличиваем и обрезаем картинку, чтобы избавиться от артефактов на краях:
Симпатично, правда? Но на этом можно не останавливаться и сделать всё еще интереснее (используя при этом всё еще один только шейдер). Добавим еще немного шагов?
Шаг 7: Добавим воду, с корректировкой цвета по глубине (из карты высот)
Шаг 8: Добавим текстурку с облаками и отражения на воде, а воде добавим рябь:
Шаг 9: Сделаем воде отражающую способность пропорциональную глубине:
О шейдерах можно писать долго и много, можно расписать в детялях, с алгоритмами и кодом. Но так, как цель статьи не в этом, а в рассказе истории развития движка, технические детали я опущу.
После реализации пары таких вот красивых эффектов, было решено, что работа с шейдерами уже более чем удобная и можно отложить этот блок до лучших времен.
Псевдовекторные шрифты Суть псевдовекторных шрифтов в том, что все данные хранятся в текстуре особым образом. А рендер букв происходит с помощью шейдера. Настолько простого, что он практически не замедляет отрисовку сцены. Однако шейдер позволяет делать антиалиасинг, обводку и свечение у букв, а также масштабировать буквы не теряя при этом четкости и не размыливая изображение.Да, они есть. И о них очень хочется рассказать, но тема настолько большая, что тянет на отдельную статью, как я, пожалуй, и поступлю. Поэтому прошу меня извинить, но этот раздел мы откладываем до следующей статьи.Крик души А давайте чтобы избежать непонимания и холиваров, я попрошу просто принять тот факт, что движок писался и продолжает писаться на Delphi. Начинал писаться на Delphi 2007, сейчас поддерживается на XE5. API выбрано DirectX и никакие OpenGL мне не нужны, я с ним работал и знаю что это. На момент начала меня интересовала только платформа Windows.Так о чем же, собственно речь? Многие скажут, мол что же, надо брать С++ или C# и писать на нем. Здраво, но цель статьи не холивары, поэтому примем за должное. Движок начал писать для Delphi, позже адаптировав и под другие языки. Именно под Delphi недоставало такого инструмента, коим всё стало сейчас. Просто, удобно и прозрачно. И позвольте называть мои наработки «движком», это слово более русское, нежели фреймворк и мне нравится больше, хотя я и понимаю, что это только фреймворк.Движок стоился на DirectX9 таким образом, чтобы не тащить за собой никаких *d3dx* библиотек. Иными словами — кроме dll самого движка ничего не надо больше. ООП, да, всё определенно хотелось на объектах. Слабые машины, а именно поддержка интегрированного видео. Что ёще? Шейдеры, без них вообще бесполезно было и начинать.
На кроссплатформенность мне откровенно было наплевать, потому что я уверен, что нет ничего лучше, чем хороший инструмент, а сделать хороший, да еще и кроссплатформенный несколько сложнее и требует больше времени, а его у меня нет, разработка идет 4fun, для удовольствия, то есть.
Что мне помогло? Помогли, совершенно однозначно, игры, которые я или мои друзья писали с использованием quad-engine. Каждый раз выползала какая-то необходимость, которая не была тем или иным образом учтена в движке. На текущий момент на нем пишется один большой игровой проект (разумеется большой в понятиях и рамках инди-разработчиков), и он также помогает развивать мне движок вширь, править ошибки и всячески улучшать.Когда с шейдерами было покончено встал вопрос куда же развиваться дальше. А дальше развиваться было и остаётся куда. Я решил делать те вещи, на которые обычно закрывают глаза другие разработчики. А именно — мелочи. Мелочи пошли уже немного за грань фреймворка для рисования. Появился функционал создания окна, автоматической обработки потери Direct3D устройства и его восстановления, вместе со всеми потерянными рендертаргетами (этой проблемы уже нет в более старших версиях DirectX). Были добавлены такие вещи, как определение разрешений, аппаратные курсоры. Даже такой маленький нюанс, как убирание рамки вокруг окна, если оконное разрешение совпадает с экранным (так называемый borderless window). Иными словами всё, чтобы было удобно и просто. Все эти удобства как раз и рождались в процессе разработке игр. В частности последний вал обновлений связан с разработкой моей игры долгостроя Blast-off. Но о ней я раскажу в другой раз.
IGDC IGDC, или если писать полностью Independent Games Developers Contests помог мне в развитии моего движка. Участники ни раз и ни два использовали разные версии движка для конкурсных работ, писали на разных языках, в том числе помогли отточить заголовочные файлы для C#. Многие из этих работ, кстати, доступны для скачивания у меня с сайта с полными исходными кодами и указанием версии библиотеки, которая была использована.Немного видео Лучше один раз увидеть, чем сто раз услышать, верно? http://www.youtube.com/embed/nt_eM88ZNHk[embedded content]Зачем это всё? Зачем же я написал этот пост? Рассказать как всё было, возможно кому-то окажется полезным моё творение, а кто-то может быть поможет и подскажет что сделать еще. В любом случае я буду рад любым комментариям и готов написать статью на любую заинтересовавшую вас из этого повествования тему. Раскрыть её, так сказать, полнее.