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