Эту статью я написал для своего блога в октябре 2017 года.

Речь идёт об игре Speebot, которая сейчас выпущена в Steam. Бесплатная demo версия прилагается.

Я разрабатывал эту игру с января 2016 года в своё свободное время в одиночку. Мною выполнено всё программирование, дизайн игрового процесса, создание графики и музыки. Кроме того, я написал собственный игровой движок с нуля.

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

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

Универсальные игровые движки называются так, потому что они предназначены для общего использования, и в них заложены функции, которые не всем нужны. Это неизбежно приводит к "раздуванию" кода, и к замедлению производительности игр.

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

Решение использовать собственный движок позволяет мне интегрировать мои собственные инструменты таким образом, чтобы мне было проще и быстрее создавать контент.

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

Ну и наконец: написание собственного движка — это очень интересно.

Разработка движка началась в январе 2016 года. Я назвал его YUME ("мечта" по-японски). Он написан на Haxe, C++ и OpenGL. Я использую модифицированную версию библиотеки Lime, которая включает в себя несколько полезных функций, например, позволяет загружать ресурсы и открывает доступ к OpenGL.

Вот так движок выглядел после первой недели разработки.
Вот так движок выглядел после первой недели разработки.

До начала создания движка я почти ничего не знал о разработке 3D игр. Нужно было разбираться в OpenGL читая документацию, форумы и уроки, предназначенные для других языков (Java и C++). Через пару месяцев у меня получился довольно стабильный 3D-визуализатор.

Кроме самого 3D-визуализатора, нужно было с нуля создать множество разных систем: 2D-визуализатор, машину состояний, систему временных шагов (об этом позже), систему интерфейсов, систему управления мышью, клавиатурой и джойстиками, динамические тени, 3D звуковую систему (используя OpenAL), загрузку моделей (в собственном формате, основанном на IQM), "скелетные" анимации, иерархию объектов, эффект зеркального отражения в реальном времени, отображения текста и так далее.

В конце концов, получилась 3D библиотека, которую можно использовать для чего-то конкретного. Многое из того, что я перечислил, присутствует и в других движках, но в YUME есть несколько отличий. Одно из них — система временных шагов.

Система временных шагов гарантирует, что движок обрабатывает и показывает кадры игры с определённым интервалом. В YUME нет ограничения по количеству кадров в секунду, т.е. нет привязанности к 30 или 60 кадрам в секунду. Частота кадров может быть любая, а игра всё равно будет работать с одной и той же скоростью, потому что частота обновления логики не связана с частотой обновления экрана. На компьютерах разных мощностей может быть разная производительность, и время для показа одного кадра может быть любым. А логика всегда привязана к частоте 62.5 циклов в секунду (16 миллисекунд на каждый цикл). В этом основной принцип системы временных шагов, хотя есть некоторые крайние случаи.

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

Ранняя версия YUME.
Ранняя версия YUME.

У меня была готовая библиотека, но пока ещё не движок. Пришла пора начать разрабатывать игру, и принимать решения о нужных функциях. К тому времени у меня уже было несколько идей, и я знал, что хотел попробовать поэкспериментировать с 3D "плитками".

Я начал создавать систему игровых уровней, которая использовала что-то похожее на 2D плитки (tilemaps), но с одним дополнительным измерением. Получается, что уровень можно сложить из "кубиков", как конструктор. Я создал редактор карт, чтобы ускорить процесс создания уровней. В итоге этот редактор попал в финальную версию игры и доступен каждому игроку.

Движок автоматически определяет, какую 3D модель использовать для отображения каждой плитки, в зависимости от соседних плиток. Придумал способ, как объединить все плитки в одну общую 3D модель, чтобы видеокарте не нужно было рисовать каждую плитку индивидуально. Вся карта рисуется за один раз, что очень сильно улучшает производительность.

Уровни можно редактировать и тестировать сразу. Для продуктивности — то что нужно.

Я написал простую систему игровой физики и начал экспериментировать с игровым процессом. Через несколько недель был готов первый прототип игры, в котором игрок мог перемещать цилиндр по 3D уровню.

Прототип Speebot в июле 2016 года.
Прототип Speebot в июле 2016 года.

YUME продолжал развиваться параллельно с разработкой Speebot (примерно в это время я выбрал такое название для игры). Было найдено и устранено несколько проблем с архитектурой движка, добавилось несколько новых функций: физика, частицы, отражения на поверхности воды, инструменты для анимации камеры, интерактивные объекты... Постепенно библиотека эволюционировала в игровой движок.

Я продолжал добавлять новые элементы игрового процесса, оставляя элементы, которые казались мне интересными, и избавляясь от лишнего. После некоторых экспериментов с художественным направлением графики игры я создал персонажа в Blender — маленького робота с одним колесом. Персонаж нарисован и анимирован в мультяшном стиле.

В это время я уже работал в основном над самой игрой, а не над движком. Я продолжал создавать новые уровни, декорации, персонажи и элементы игры.

В конце 2016 года я сделал паузу от разработки игры, и посвятил несколько месяцев изучению и практике написания музыки. У меня нет музыкального образования, но это — моё хобби. У меня уже был небольшой опыт в композиции музыки для моей предыдущей игры Hypnorain, но я хотел улучшить свои навыки, поэтому снова погрузился в изучение музыкальной теории. Для композиции музыки я использовал программу SunVox, которая является виртуальным модульным синтезатором. В финальной версии игры Speebot всего 23 трека, которые вместе составляют более часа оригинальной музыки. Я удовлетворён результатом, и продолжу улучшать свои навыки для следующей игры.

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

После выпуска нескольких демо версий, обработки отзывов от игроков и улучшения игры, Speebot был выпущен в октябре 2017 года. В финальной версии игры 200 уровней, 4 мира, редактор пользовательских уровней, несколько дополнительных режимов игры, и много другого дополнительного контента.

Самое сложное при разработке игры было сохранять мотивацию и интерес на протяжении всех 20 месяцев. Работать над игрой мне удавалось только по вечерам после университета и работы, и по выходным дням. Но всё равно, это было очень интересно.

Я продолжу использовать и развивать свой движок YUME в своих будущих играх, и уже начал работать над своим следующим проектом.


После написания этой статьи я разработал и выпустил ещё две игры на этом движке: сюжетная приключенческая игра Phantom Path, и игра-головоломка Pilie Pals.

Комментарии (35)


  1. pecheny
    22.04.2022 17:51
    +1

    Статью уже видел, но аккаунт только на хабре, задам накопившиеся вопросы.
    Под мобилки пробовали собирать?
    OpenAl динамически линкуете?
    Для воспроизведения музыки санвоксовский же рантайм используется? Всегда было интересно потыкать, но никогда руки не доходили попробовать. Особенно, собрать под мобилы.
    Вопрос про опенсорс уже поднимался, выскажу мнение: чтоб поделиться, причесывать и документировать совсем не обязательно. Все равно может быть полезно: взять готовые экстерны для санвокса, поэкспериментировать с IQM…


    1. kircode Автор
      22.04.2022 18:39
      +2

      • На мобильные собирать пока не пробовал, но такая возможность в теории есть, так как Haxe/Lime кроссплатформенный.

      • OpenAL-Soft входит в состав Lime, который сам по себе open source и линкуется динамически.

      • Нет, музыка и все звуки — в формате ogg.

      • Спасибо, подумаю.


  1. discipuli
    22.04.2022 18:50

    А исходники движка открыты?

    Просто увидел что в системных требованиях только винда и немного погрустнел.


    1. kircode Автор
      22.04.2022 20:13
      +4

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

      Говорят, игра работает под Wine/Proton без проблем. Может быть в будущем сделаю нативные билды для Linux.


  1. temaweb10
    22.04.2022 19:51
    +2

    Отлично !


  1. a-postx
    22.04.2022 19:54
    +1

    Отличный результат! Вот так и рождаются независимые игроделы, на которых сегодня вся надежда. Успехов!


  1. Oldshelf
    22.04.2022 20:25
    +1

    Лёгкая (в плане эмоций и нагрузки на комп) игра. Здорово, что поддерживается gamepad!


  1. da-nie
    22.04.2022 20:40

    А невидимые грани вы как отсекаете?


    1. kircode Автор
      22.04.2022 21:10
      +2

      Если Вы говорите о culling, то в данной игре этого не происходит.

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


  1. 0x131315
    22.04.2022 21:08
    +1

    А в чем преимущество привязки логики к какому-то определенному таймеру? В универсальных движках логика завязана на дельту времени, и таким образом тоже отвязывается от кадровой частоты.


    1. kircode Автор
      22.04.2022 21:22

      Я думаю, это зависит от ситуации. Но на мой взгляд, гораздо удобнее, когда логика работает с определённой частотой.

      Главное, чтобы логика была отделена от отображения.


      1. avengerweb
        24.04.2022 07:09

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


        1. Miwwa
          24.04.2022 07:27
          +1

          Если кадр не успевает обработаться за 16мс на целевом железе, то это значит, что пора заниматься оптимизацией или снизить требования к логике/графике. Уложиться в 16мс/32мс (60/30фпс) любыми средствами - это основное требование к производительности любой современной игры на любой платформе


    1. Miwwa
      22.04.2022 21:25

      Обычно в качестве аргументов приводят общий детерминизм игровой логики и стабильность физики.

      Но есть и минус, если игровая логика выполняется с частотой 62.5 гц, то на экранах с частотой 60 гц будет заметен пропуск кадров, а на экранах с высокой герцовкой изображение не меняется несколько кадров, теряется плавность анимаций. Этого можно избежать, интерполируя все видимые игроку значения (положения объектов, костей в анимациях и т.д.), что влечет значительное усложнение кода движка


      1. kircode Автор
        22.04.2022 22:49
        +2

        В моём движке применяется интерполяция, поэтому все движения остаются плавными. Возможно, стоит написать об этом отдельную статью.


        1. tbl
          23.04.2022 11:43

          То есть имеется плавающий лаг инпута до 18 мс?


          1. kircode Автор
            23.04.2022 12:44
            +3

            Интерполяция происходит между предыдущим и текущим логическим кадром, поэтому инпут лаг в 16 мс неизбежен.


    1. controlDns
      23.04.2022 12:46
      -4

      vrode ranshe osobo ne tracha resursov vsegda schutali tekushyu skorost vychesleniy zaodno ponimaya tekushuyu (obschiyu) nagruzku na ustroistvo da ot raschyota korrekturovalos to chto on nazval система временных шагов ... pro eto dazhe v knishkah iz90yh po sozdaniyu igr na pascale bylo i tam ne nazyvali timerom a imenno tekuschaya skorost vychesleniya kotoray menyala vse neobhodimye zaderzhki obespechivaya plavnost proishodyaschego


      1. Ronkosa
        23.04.2022 17:51
        +7

        Даже если у вас нет русской клавиатуры можно использовать google translate


  1. tohntobshi
    22.04.2022 21:43

    Прикольно) я как то тоже пытался сделать движок на c++, sdl, opengl. Сделал примитивный 3д рендеринг, чтоб модельки из блендера загружать, примитивнейшую физику в виде гравитации и прямоугольных хитбоксов для вычисления столкновений, пытался еще научиться рисовать. Вдохновлялся ютуберами Thomas Brush и The Cherno. Но чет забил в итоге)


  1. FD4A
    23.04.2022 02:48

    Сам недавно занялся такимже процессом. Сейчас только в начале пути для обработки ввода от игрока выбрал GLFW, а для аудио FMOD, не смотрели в их сторону? И там и там заявляется кроссплатформенность.

    Выглядит прикольно =)


    1. kircode Автор
      23.04.2022 12:45

      Спасибо, про FMOD слышал, но не использовал из-за лицензии.


      1. FD4A
        23.04.2022 13:40

        насколько я понимаю OpenAl тоже не совсем open.


        1. kircode Автор
          23.04.2022 14:52
          +1

          OpenAL-Soft — под лицензией LGPL. Библиотека Lime, которую я использую, включает в себя OpenAL-Soft.


  1. aakumykov
    23.04.2022 10:38

    До чего же круто. Успехов! Завидую вам.

    Несколько лет назад слышал в чём-то похожую историю от человека, который разрабатывал "убийцу Minecraft". Тоже рассказывал, как с нуля, ничего не зная про 3D, изучал OpenGL, делал свой движок, решал проблемы производительности. Название игры забыл, но работал он тогда в Кемеровском Goodline главным разработчиком интернет-тв.


  1. xshd
    23.04.2022 12:46

    Смотрится здорово!

    посмотрел на сайте ролик про Phantom Path и думаю многим бы зашла такая игра.

    Пару вопросов / предложений? к Phantom Path :

    - есть возможность добавить GI (global illumination) для теней и источников света? Визуально игра начала бы выглядеть еще привлекательней.

    -возможно ли многопользовательская игра? бегать компанией 3-4 человека

    -есть вариант портировать на консоли (ps/xbox)?

    Понравилась стилистика/динамика у PP, успехов!


    1. kircode Автор
      23.04.2022 12:59

      Спасибо! Ни GI, ни multiplayer в движке пока нет. Если пригодится для будущих игр, возможно, добавлю. На консоли возможность портировать есть, так как Haxe кроссплатформенный, но пока не пытался.


  1. APXEOLOG
    23.04.2022 12:51
    +1

    Многое из того, что я перечислил, присутствует и в других движках, но в YUME есть несколько отличий. Одно из них — система временных шагов

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

    Универсальные игровые движки называются так, потому что они предназначены для общего использования, и в них заложены функции, которые не всем нужны. Это неизбежно приводит к "раздуванию" кода, и к замедлению производительности игр.

    Есть и обратная сторона медали. Качественные современные движки предлагают хорошие оптимизации для конкретных случаев (например в зависимости от того, какую версию OpenGL поддерживает видеокарта будут использованы разные API - на современных системах какие-то вещи будут работать быстрее). Также, если мы говорим о высоко-реалистичной графике, то туда соваться без готового движка это вообще смерть. Люди там годами только реалистичную воду или деревья создают.

    Самое сложное при разработке игры было сохранять мотивацию и интерес на протяжении всех 20 месяцев

    Вот за это мое уважение. Хотел бы иметь такую же способность


  1. skop8
    23.04.2022 19:04

    Потрясающая работа! Люблю игры с душой...


  1. vadim100
    23.04.2022 19:04

    Игра смотрится хорошо на видео. Странно, что вы закончили разработку в 2017 и до сих пор не сделали мобильную версию игры. Зря однако. На ПК в такие казуальные игры мне кажется не играют особо.


  1. leominder
    24.04.2022 10:18

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


  1. Mihbo
    24.04.2022 20:51

    История прям мотивирует!


  1. Seruios
    24.04.2022 20:51
    -2

    Чел, ты серьезно? Извини, я вряд ли вернусь сюда, Но, ты слышал про Unreal engine 5?) Он хоть и универсальный, но с новыми разработками говорят что он вообще не лагает, автоматическая оптимизация, не важно насколько большие модели будут в плане полигонов. А ты тут свой движок писал 20 месяцев. Это все равно что написать Виндоус заново, хотя он уже есть 20+ лет и у тебя не будет лучше.


    1. vadim100
      25.04.2022 09:26
      +1

      Можно было бы критиковать, если бы автор бы начал писать движок и бросил на полпути, что постоянно происходит. Он же довёл работу до конца и выпустил уже 6 своих игр на нём. Если рождается что-то новое можно это только приветствовать.


  1. FloorZ
    25.04.2022 04:25

    а сколько весит билд со сценой без ассетов?

    Когда писал свой движок, у меня только интерпретатор рантайм-скриптов весил over 20mb.

    А когда взял исходник готового движка, того же acid или godot engine, выходной инарник выходил меньше и шустрее.

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