Двигатель Koala - это игровой двигатель, полностью реализованный в качестве компонентной системы объекта (ECS).
Двигатель основан на Entt. Интеграция с другими частями программного обеспечения с использованием EnTT должна быть простой. Эта документация предполагает, по крайней мере, базовые знания EnTT и ее терминологии ( entity , registry , handle ...).

Пример проекта демонстрирует некоторые основные функции. Это должно дать вам представление о том, что может предложить поддержка двигателя для размышлений и расширяемости времени выполнения.
Двигатель использует подмодули GIT, и поэтому должен быть клонирован рекурсивно с
git clone https://github.com/phisko/kengine --recursive
Двигатель был протестирован в Windows с MSVC и Mingw.
Компиляция Linux работает с GCC. На момент написания, Clang не поддерживает CSONTEXPR constexpr std::string и std::vector .
Двигатель требует компилятора C ++ 20 .
Двигатель начался как страстный/студенческий проект в 2016-17 годах. Мои друзья/коллеги и я попытались внедрить ECS с нуля. Мы хотели абсолютного типа безопасность и ясность, и, хотя мы уже играли с шаблонами метапрограммирования, это был шанс для нас узнать больше об этом.
После того, как основной ECS работал, двигатель превратился в детскую площадку, чтобы узнать больше о разработке игр. Я выучил рендеринг OpenGL, как использовать NavMeshes с повторным/обходом, настройка физики с пулей ... все время разрабатывая полезных помощников и средств для отражения среды выполнения, совместимые с ECS.
После более чем 5 лет, работая над двигателем, я понял, что сам основной ECS больше не является центром этого проекта. Другие библиотеки и EnTT , в частности, предлагают очень похожий API с гораздо более продвинутыми функциями. Поэтому я потратил время, чтобы полностью вытащить внутреннюю ECS и заменить его на EnTT . Все функции остаются прежними, и это даст мне больше времени для работы над полезными помощниками, которые могут работать с другими проектами EnTT .
Многие части двигателя (например, системы сценариев или редактор Imgui Entity) используют API отражения putils . Таким образом, большинство компонентов в следующих образцах определяются как отражаемые.
Код двигателя организован в трех категориях:
Обратите внимание, что systems не объекты определенного класса. Системы - это просто объекты с выполнением компонента (или что -то еще, что им нужно для выполнения своей работы). Затем субъект живет в registry с остальной частью игрового состояния. Это позволяет пользователям интроспективно системы или добавлять поведение в них, как и любая другая сущность.
Эти три категории разделены на различные библиотеки, например:
Обратите внимание, что некоторые библиотеки содержат подлибрии, например:
В разделе Cmake подробно рассказывается о том, как работать с этими библиотеками.
Двигатель поставляется с (довольно большим) количеством предварительно построенных компонентов, которые можно использовать для начала игры или просто в качестве примеров, на которых вы можете основывать свои собственные реализации.
Эти компоненты вписываются в три категории:
Компоненты данных содержат данные об их организации.
Компоненты данных - это то, что впервые приходит на ум, думая о компоненте, таких как преобразование или имя.
Компоненты данных иногда могут выполнять функции:
Функциональные компоненты поддерживают функции для запроса, изменения или уведомления их сущности.
Функциональные компоненты являются просто держателями для функционирования, которые могут быть прикреплены в качестве компонентов к объектам. Этот механик может быть использован для:
Функциональные компоненты - это типы, которые наследуют от base_function, придавая ей сигнатуру функции в качестве параметра шаблона.
Чтобы вызвать функциональный компонент, можно использовать его operator() или функцию call .
entt::registry r;
const auto e = r.create();
r.emplace<main_loop::execute>(e,
[]( float delta_time) { std::cout << " Yay! " << std::endl; }
);
const auto & execute = r.get<main_loop::execute>(e); // Get the function
execute ( 0 .f); // Call it with its parameters
execute.call( 42 .f); // AlternativelyМета компоненты являются компонентами для компонентов.
Двигатель использует «объекты типа» для хранения информации об использовании различных компонентов. Каждый объект типа представляет свой тип компонента и может использоваться для запроса свойств компонента во время выполнения.
Мета -компоненты прикрепляются к этим «объектам типа» и содержат реализацию общей функции для этого конкретного типа. Поскольку они выполняют функции, они очень похожи на компоненты функций.
Пример делает это более ясным: Meta :: imgui :: Edit - это мета -компонент, который при вызове будет нарисовать свойства «родительского компонента», используя IMGUI для данной сущности. В следующем коде отобразится окно для редактирования компонента имени e
// r is a registry with the "type entity" for `name` already setup
const auto e = r.create();
r.emplace<core::name>(e);
const auto type_entity = type_helper::get_type_entity<core::name>(r);
const auto & edit = r.get<meta::imgui::edit>(type_entity);
if (ImGui::Begin( " Edit name " ))
edit ({ r, e });
ImGui::End ();Если вы обобщаете это, вы можете редактировать все компоненты для объекта со следующим кодом:
// r is a registry with the "type entities" for all used components already setup
// e is an entity with an unknown set of components
if (ImGui::Begin( " Edit entity " ))
for ( const auto & [type_entity, edit] : r.view<meta::imgui::edit>()) {
edit ({ r, e });
}
ImGui::End ();См. Cmake для инструкций о том, как включить каждую библиотеку.
Предусмотрен сценарий Python Generate_type_registration, который можно использовать для генерации файлов C ++, содержащих функции, которые будут регистрировать набор заданных типов с помощью двигателя.
Это абсолютно не обязательно .
Двигатель использует Cmake в качестве системы сборки. Была создана пользовательская структура для упрощения создания библиотек. Корневые Cmakelists повторяются над подзадаченными и автоматически добавляют их в качестве библиотек, если они соответствуют нескольким условиям.
Создана базовая библиотека интерфейса kengine , которая ссылается на все включенные библиотеки, поэтому клиенты могут просто ссылаться на это.
Следующие варианты Cmake выставлены.
KENGINE_TESTSКомпилируют тестируемые исполняемые файлы для библиотек, которые реализуют тесты.
KENGINE_NDEBUGОтключает код отладки.
KENGINE_TYPE_REGISTRATIONБудет генерировать код регистрации типа для типов двигателей. Это является центральным во многих возможностях отражения двигателя, поскольку он обеспечивает реализацию для мета -компонентов.
KENGINE_GENERATE_REFLECTIONОбновит заголовки отражения для типов двигателей. Они предварительно сгенерированы, поэтому, если вы не изменяете исходный код двигателя, вам не нужно включать это.
Все библиотеки отключены по умолчанию, чтобы избежать создания нежелательных зависимостей. Каждая библиотека может быть включена по отдельности, установив свою опцию Cmake на ON . Смотрите именование библиотеки для имени опции.
В качестве альтернативы, все библиотеки могут быть включены с помощью опции KENGINE_ALL_SYSTEMS .
Обратите внимание, что суб-либрации нуждаются в включении их родительской библиотеки: kengine_imgui_entity_editor требуется kengine_imgui.
Библиотеки названы в зависимости от их относительного пути к корне двигателя. Слошки на пути просто заменяются подчеркиванием, например:
kengine_corekengine_imgui_toolЭти имена:
KENGINE_CORE для kengine_core )KENGINE_CORE_EXPORT для kengine_core )Можно проверить наличие библиотеки во время компиляции благодаря определению макросов C ++. Они имеют то же имя, что и параметры Cmake, например:
# ifdef KENGINE_CORE
// The kengine_core library exists
# endifНекоторые библиотеки используют VCPKG для управления зависимостями.
Поскольку библиотеки автоматически обнаруживаются root CMakeLists.txt , создать новую библиотеку довольно просто.
Библиотеки автоматически связываются с kengine_core , поскольку он предоставляет помощников, которые следует использовать всеми библиотеками (например, log_helper и profiling_helper).
Суб -либрии автоматически связываются против их родителей. Например, kengine_imgui_entity_editor автоматически связывается с kengine_imgui.
Исходные файлы из helpers и systems библиотеки автоматически добавляются. Если никто не найден, библиотека будет библиотекой интерфейса Cmake.
Тип регистрации и кода отражения могут быть автоматически созданы для компонентов. По functions все заголовки в data библиотеки будут переданы в сценарии генерации.
Подобно исходным файлам, если какие -либо *.tests.cpp файлы обнаруживаются в подразделениях helpers/tests или systems/tests , будет автоматически добавлен реальный исполняемый файл Googletest.
CMakeLists.txt Основным библиотекам не должно нужны свои собственные CMakeLists.txt , поскольку их исходные файлы будут автоматически. Однако, если библиотеке нуждается в пользовательском поведении (например, для добавления дополнительных источников или для связи с сторонней библиотекой), она может добавить свои собственные CMakeLists.txt . Что CMakeLists.txt будет вызван после вызова add_library .
Следующие переменные и функции определяются перед вызовом CMakeLists.txt :
kengine_library_name : имя библиотекиkengine_library_tests_name : Имя цели библиотеки Googletestlink_type : тип ссылки библиотеки ( PUBLIC или INTERFACE , в зависимости от того, были ли найдены источники или нет)kengine_library_link_public_libraries(libraries) : ссылки против других библиотек (публично)kengine_library_link_private_libraries(libraries) : ссылки против других библиотек (в частном порядке)register_types_from_headers(headers) : добавляет заголовки, для которых могут быть сгенерированы заголовки регистрации и отражения типаsubdirectory_is_not_kengine_library(path) : указывает на корне CMakeLists.txt , что он не должен обрабатывать path как библиотека Кенгин