Koala引擎是完全实施的游戏引擎,该引擎是实体组件系统(ECS)。
该引擎基于ENTT。与其他使用EnTT的软件集成应该很简单。本文档至少假定了EnTT及其术语( entity , registry , handle ...)的基本知识。

示例项目展示了一些核心功能。它应该让您了解引擎对反射和运行时可扩展性的支持。
该发动机使用git子模型,因此应递归克隆
git clone https://github.com/phisko/kengine --recursive
该发动机已在Windows上使用MSVC和MINGW进行了测试。
Linux汇编可与GCC一起使用。在撰写本文时,Clang不支持C ++ 20的constexpr std::string and std::vector 。
发动机需要C ++ 20编译器。
该引擎始于2016 - 17年度的激情/学生项目。我的朋友/同事和我从头开始实施EC。我们想要绝对的类型安全性和清晰性,尽管我们已经使用模板元编程了,但这是我们有机会了解有关它的机会。
核心ECS工作后,引擎就会变成一个操场,以了解有关游戏开发的更多信息。我学习了OpenGL渲染,如何将NavMeshes与重铸/弯路,用子弹进行设置物理学...一直在开发有用的帮助者和与ECS兼容的运行时反射设施。
在为发动机上工作了5年以上之后,我意识到核心ECS本身不再是该项目的重点。其他图书馆,尤其是EnTT ,提供了非常相似的API,具有更高级的功能。因此,我花了一些时间彻底挖出内部EC并用EnTT替换。所有功能保持不变,这将使我有更多时间在有用的帮助者上工作,这些帮助者可以与其他EnTT项目一起使用。
发动机的许多部分(例如脚本系统或IMGUI Entity Editor)利用putils的反射API。因此,以下样品中的大多数组件被定义为反射性。
发动机代码分为三类:
请注意, 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为给定实体绘制其“ parent component”的属性。以下代码将显示一个窗口以编辑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。
提供了一个generate_type_registration python脚本,该脚本可用于生成包含将在引擎上注册一组给定类型的功能的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 for kengine_core )KENGINE_CORE_EXPORT for kengine_core )由于C ++定义了宏,因此可以在编译过程中测试库的存在。这些名称与CMAKE选项相同,例如:
# ifdef KENGINE_CORE
// The kengine_core library exists
# endif一些库利用VCPKG进行依赖性管理。
由于root CMakeLists.txt会自动检测库,因此创建一个新库非常容易。
库会自动链接到kengine_core ,因为它提供了所有库应使用的助手(例如log_helper和propiling_helper)。
子图片会自动与父母联系。例如,kengine_imgui_entity_editor会自动链接与kengine_imgui。
来自库的helpers和systems子目录的源文件会自动添加。如果找不到,库将是一个CMAKE接口库。
类型注册和反射代码可以自动为组件生成。默认情况下,库的data和functions子目录中的所有标题都将传递给Generation脚本。
与源文件类似,如果在库的helpers/tests或systems/tests子目录中找到任何*.tests.cpp文件,则将自动添加Googletest可执行文件。
CMakeLists.txt基本库不需要自己的CMakeLists.txt ,因为它们的源文件将自动。但是,如果图书馆需要自定义行为(例如添加额外的资源或针对第三方库链接),则可能会添加自己的CMakeLists.txt 。 CMakeLists.txt将在呼叫add_library之后被调用。
在调用CMakeLists.txt之前,定义了以下变量和函数:
kengine_library_name :图书馆的名称kengine_library_tests_name :图书馆的Googletest Target的名称link_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) :向root CMakeLists.txt指示它不应作为kengine库处理path