1.1. Введение

Бывает такое чувство, что ты изучаешь что-то не то. Вроде интересно, а вроде и нет. Именно такое чувство у меня и было, когда я изучал Unreal Engine — мощный движок, можно сделать от шутера в открытом мире до платформера, но интереса нет. До Unreal Engine я испробовал Ren’Py, Unity, Java и C#, но, как и с Unreal Engine, у меня не было интереса. Мне хотелось чего-то одновременно интересного и сложного.

Именно в декабре 2020 года я и решил — хочу написать собственный движок для визуальных новелл на C++. Почему для визуальных новелл? Мне они просто нравятся, вот и весь ответ.

1.2. Немного обо мне

Зовут Никита, проживаю в Красноярске. С 13 лет занимаюсь программированием, успел выпустить 2 визуальные новеллы на собственных движках, 5 раз собирал команду для разработки своих проектов. Изучал C#, Java, Python, Kotlin.

Сейчас мне 16 лет, программирую на C++, пишу собственный движок — Oneiro Engine.

1.3. От идеи к коду

Взяв первый попавшийся плейлист с видеоуроками по C++, я приступил к его изучению. Каждый день я выделял минимум 4 часа на уроки, чтобы как можно быстрее начать писать движки.

Извиняюсь:)
Извиняюсь:)

Кстати, для каждого урока я создавал отдельный проект, чтобы можно было потом вернуться для повторения материала. Как итог у меня набралось около 200 проектов весом 5-10 Гб (точные цифры не помню, так как проекты удалил).

Спустя около 4 месяцев я уже знал основы C++: ООП, STL, многопоточность, алгоритмы и так далее. Хоть знания и были поверхностными их всё равно хватило на попытку написания движка.

Первым же делом я начал искать нужные мне библиотеки и информацию о том, как написать движок для визуальных новелл. В итоге была найдена библиотека для 2D графики — SFML. А вот информация о том, как написать движок для визуальных новелл — не была найдена, но я не отчаивался.

Из-за нулевой (или около нулевой) информации о том, как создать движок для визуальных новелл мне пришлось идти на GitHub и искать там уже готовые/wip движки. Поняв, как можно написать движок, я создал проект в Visual Studio и пошёл писать код, точнее — копипастить его. Пересказывать, как я копипастил код, думаю, не надо — это будет неинтересно.

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

1.4. Поверхностное изучение архитектуры движков и OpenGL

Когда я пытался писать движок на SFML, я понял одну вещь: данная библиотека весьма ограничена. Как минимум изменение размера окна работало не так, как нужно было, мало возможностей в 3D и так далее. Поискав информацию в интернете о замене SFML, я наткнулся на OpenGL.

Увидев треугольник на OpenGL, который я сам вывел, я получил массу дофамина. Тогда я решил — я хочу быть программистом графики. Потом я вывел 3D куб, сделал базовый свет, попробовал ImGui, но было одно “но” — я не понимал базовых вещей в OpenGL. Именно это одно “но” мне помешало в дальнейшем написании движка на Anivisual Jam #3.

1.5. Вторая попытка написания движка.

11 июля 2021 года я увидел пост на Anivisual о новом джеме под номером 3. До этого я и сценарист команды, в которой я состоял как кодер, пытались поучаствовать во 2-ом Anivisual джеме, но из-за нехватки ресурсов мы всё забросили. А на 3-ем Anivisual джеме у нас были шансы, так как я знал художницу, которая точно не откажется рисовать нам спрайты. Все остальные ассеты (например музыку и бэкграунды) мы могли найти в интернете. До анонса 3-его Anivusal джема я уже писал второй движок, который как раз таки был использован для новеллы на джеме.

После начала джема и анонса темы мы почти сразу же определились с сюжетом, персонажами и так далее. Потом опубликовали тему в специальном разделе на форуме анивизы и начали кранчить.

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

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

На релизе большинство багов было исправлено, но костылями. К примеру, для решения проблемы со спрайтами и текстом было запрещено изменять размер окна, но на других мониторах (не 16:9) всё плыло.

Что касается кода, то он очень и очень плох. Я не задумывался над оптимизацией, да и над качеством кода тоже, так что если сейчас взглянуть на код, к примеру, показа спрайта, то можно в прямом смысле умереть от ужаса. Хотя не всё так плохо:)

1.5.1. “Коротко” о том, как я реализовал базовые функции визуальных новелл.

К примеру, у нас есть две команды:

1. Покажи спрайт sprite;
2. Выведи текст “Hello World!”.

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

Вернёмся к примеру, мы зашли в игру, потом движок автоматически пропарсил наши команды до вывода текста. В начале игры мы увидим сам спрайт “sprite” и текст “Hello World”. Если дальше есть команды и игрок нажал пробел, то логика идёт таким же образом до показа текста:

show bg — it++ и разбор команды
show sprite — it++ и разбор команды
me “Hello, World!” — ждём нажатие кнопки мыши или чего-то другого
me “Next command.”  — it++ и разбор команды
hide sprite  — it++ и разбор команды
hide bg  — it++ и разбор команды
me “Goodbye!” — следующих команд нет, ожидаем выход из игры

1.5.2. И немного про костыли

Из-за того что я не был знаком с кодировками текста и библиотекой freetype, мне пришлось делать костыли для загрузки русских символов (глифов). Для того чтобы написать русские символы, надо было сменить кодировку файла на windows 1251. При этом кодировку не простого скриптового файла, а C++ исходника, так как у движка не было скриптового языка.

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

Про кривые спрайты и кнопки, я думаю, не надо рассказывать, так как тут и так всё понятно.

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

1.6. Улучшение навыков

Точно не помню, как и когда я наткнулся на канал The Cherno, но именно от Яна Черникова я впервые познал, что такое движки и с чем их едят. Тогда он только начинал писать свой движок — Hazel Engine. Посмотрев парочку видео Яна, у меня появилось представление о том, как можно написать ядро движка, нормальный рендер на OpenGL и так далее. Именно по его видео я пытался писать движок в третий раз.

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

Перед разработкой 3-его движка я решил испробовать Vulkan API, при этом не зная как устроена графика внутри. Как итог спустя 2 недели я решил бросить изучение Vulkan API.

1.7. Третья попытка написания движка

Где-то в сентябре 2021 года было решено начать разработку третьего движка — Rebirth Engine 2.0.

Как и всегда, представления о том, как будут работать и взаимодействовать компоненты движка, не было. Зато была идея использовать скриптовый язык lua для написания скриптов новелл с похожим на синтаксис Ren’Py.

В принципе, движок был написан по той же самой схеме, как и все прошлые, но были добавлены анимации (простой dissolve эффект), синхронизация с разными разрешениями и соотношениями сторон и так далее. Основным нововведением был скриптовый язык Lua через который я пытался реализовать похожий на Ren’Py синтаксис скриптинга новелл.

Кстати, схема разбора скрипта новелл была такая же.

1.8. Конец?

Вместо полноценной статьи получилось сочинение на тему “Чем вы занимались весь год?” :D

Кстати, после изучения Vulkan API я пошёл пилить демки на OpenGL (OGLD), но там ничего интересного нет, а после разработки Rebirth Engine 2.0 я решил впервые в жизни зайти на реддит и сделать пост по поводу следующего движка (ссылка на пост будет в конце).

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

1.9. Ссылки

GitHub
Движок, который использовался как пример в разработке первого движка
Первый движок (Simple Visual Novel Engine)
Второй движок (использовался на Anivisual Jam #3)
Новелла созданная на втором движке
Проект для изучения Vulkan API
Третий движок
Пост на реддите

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


  1. MentalBlood
    17.10.2022 11:45
    +1

    А вот информация о том, как написать движок для визуальных новелл — не была найдена

    Хех. Так и не надо, интереснее же самому сделать


    1. Dezlow Автор
      17.10.2022 15:07

      Так и не надо, интереснее же самому сделать

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


  1. domix32
    17.10.2022 19:55
    +2

    Vulkan API я пошёл пилить демки на OpenGL

    Я чет не очень понимаю - учил вулкан, но писал в итоге на OpenGL? А зачем тогда его упоминать в статье если в итоге нигде не используется?

    А что насчёт использования готовых движков с имеющимися примитивами для рисования всего на экране - love2d, cocos2d-x/js и иже с ними? Внутренний код там конечно то ещё произведение китайских умов, но на этом с давних лет делают игры в том числе и на ПК.

    Если умеешь слушать на английском то можно посмотреть про движкостроение вот у этого чувака. Код он тоже выкладывает на github, только смотри на детали лицензии, если будешь копипастить что-то.


    1. Dezlow Автор
      18.10.2022 07:47
      +1

      Я чет не очень понимаю - учил вулкан, но писал в итоге на OpenGL? А зачем тогда его упоминать в статье если в итоге нигде не используется?

      Не обязательно писать что-то используя апи, которое ты изучал. Я изучал вулкан ради понимания как устроен пайплайн, рендерпассы, сэмплеры и так далее. Довольно полезные знания получил, хоть и использую всё это время OpenGL.

      В статье упомянул потому что это тоже важное событие в моём пути программиста.

      А что насчёт использования готовых движков с имеющимися примитивами для рисования всего на экране - love2d, cocos2d-x/js и иже с ними?

      Про такие тулзы я не знал, когда только начинал изучать программирование движков. Однако, в настоящее время я уже знаком с этими тулзами и пытался их использовать, но честно говоря, мне такое просто не интересно:) Интреснее ведь самому написать класс для отрисовки круга, чем просто использовать что-то готовое. Хотя в реальности "интересно" не сработает.

      Если умеешь слушать на английском то можно посмотреть про движкостроение вот у этого чувака. Код он тоже выкладывает на github, только смотри на детали лицензии, если будешь копипастить что-то.

      Про него я уже давно знаю, но не смотрю. Мне интереснее смотреть The Cherno:)

      Код я стараюсь не копипастить, а если уж копирую, то пытаюсь его переписать под свой стиль и понять как работает код.