เอ็นจิ้นโคอาล่าเป็นเครื่องมือเกมที่ใช้งานทั้งหมดเป็นระบบองค์ประกอบเอนทิตี (ECS)
เครื่องยนต์ขึ้นอยู่กับ Entt การรวมเข้ากับซอฟต์แวร์ชิ้นอื่น ๆ ที่ใช้ EnTT ควรตรงไปตรงมา เอกสารนี้ถือว่าอย่างน้อยความรู้พื้นฐานของ EnTT และคำศัพท์ ( entity , registry , handle ... )

ตัวอย่างโครงการแสดงคุณสมบัติหลักบางอย่าง ควรให้ความคิดเกี่ยวกับสิ่งที่เครื่องยนต์สนับสนุนสำหรับการสะท้อนและการขยายเวลาการทำงานของรันไทม์มีให้
เครื่องยนต์ใช้ submodules git และควรถูกโคลนซ้ำกับ
git clone https://github.com/phisko/kengine --recursive
เครื่องยนต์ได้รับการทดสอบบน Windows ด้วย MSVC และ MINGW
การรวบรวม Linux ทำงานร่วมกับ GCC ในช่วงเวลาของการเขียน Clang ไม่รองรับ C ++ ของ constexpr std::string และ std::vector
เครื่องยนต์ต้องการคอมไพเลอร์ C ++ 20
เครื่องยนต์เริ่มต้นจากโครงการ Passion/Student ในปี 2559-2560 เพื่อน/เพื่อนร่วมงานของฉันและฉันได้ไปใช้ ECS จากพื้นดิน เราต้องการความปลอดภัยและความชัดเจนประเภทแน่นอนและในขณะที่เราได้เล่นกับแม่แบบ metaprogramming นี่เป็นโอกาสที่เราจะได้เรียนรู้เพิ่มเติมเกี่ยวกับเรื่องนี้
เมื่อ Core ECS ทำงานแล้วเครื่องยนต์ก็กลายเป็นสนามเด็กเล่นเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับการพัฒนาเกม ฉันเรียนรู้การแสดงผล OpenGL วิธีการใช้ Navmeshes ด้วย recast/Detour, Setup Physics พร้อมกระสุน ... ในขณะที่พัฒนาผู้ช่วยที่มีประโยชน์และสิ่งอำนวยความสะดวกการสะท้อนกลับของรันไทม์ที่เข้ากันได้กับ ECs
หลังจากนั้นกว่า 5 ปีที่ทำงานกับเครื่องยนต์ฉันรู้ว่า Core ECS นั้นไม่ได้เป็นจุดสนใจของโครงการนี้อีกต่อไป โดยเฉพาะอย่างยิ่งห้องสมุดอื่น ๆ และ EnTT นำเสนอ API ที่คล้ายกันมากพร้อมคุณสมบัติขั้นสูงมากขึ้น ดังนั้นฉันจึงใช้เวลาในการออก ECs ภายในอย่างสมบูรณ์และแทนที่ด้วย EnTT คุณสมบัติทั้งหมดยังคงเหมือนเดิมและสิ่งนี้จะทำให้ฉันมีเวลามากขึ้นในการทำงานกับผู้ช่วยที่มีประโยชน์ซึ่งสามารถทำงานกับโครงการ EnTT อื่น ๆ ได้
หลายส่วนของเครื่องยนต์ (เช่นระบบสคริปต์หรือตัวแก้ไขเอนทิตี IMGUI) ใช้ประโยชน์จาก API สะท้อนแสงของ putils ส่วนประกอบส่วนใหญ่ในตัวอย่างต่อไปนี้จึงถูกกำหนดให้สะท้อนได้
รหัสเครื่องยนต์ถูกจัดระเบียบในสามประเภท:
โปรดทราบว่า systems ไม่ใช่วัตถุของคลาสเฉพาะ ระบบเป็นเพียงเอนทิตีที่มีส่วนประกอบดำเนินการ (หรือสิ่งอื่นใดที่พวกเขาต้องทำงาน) เอนทิตีจากนั้นอาศัยอยู่ใน registry กับส่วนที่เหลือของสถานะเกม สิ่งนี้จะช่วยให้ผู้ใช้ระบบการไตร่ตรองหรือเพิ่มพฤติกรรมให้กับพวกเขาเช่นเดียวกับเอนทิตีอื่น ๆ
ทั้งสามหมวดหมู่นี้แบ่งออกเป็นห้องสมุดต่าง ๆ เช่น:
โปรดทราบว่าห้องสมุดบางแห่งมีห้องสมุดย่อยเช่น:
ส่วน CMake จะมีรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการทำงานกับห้องสมุดเหล่านี้
เครื่องยนต์มาพร้อมกับส่วนประกอบที่สร้างไว้ล่วงหน้าจำนวนมาก (ค่อนข้างใหญ่) ซึ่งสามารถใช้ในการบูตเกมหรือเป็นตัวอย่างที่คุณสามารถใช้งานได้
ส่วนประกอบเหล่านี้พอดีเป็นสามประเภท:
ส่วนประกอบข้อมูลเก็บข้อมูลเกี่ยวกับเอนทิตีของพวกเขา
ส่วนประกอบข้อมูลเป็นสิ่งที่นึกถึงเป็นครั้งแรกเมื่อคิดถึงองค์ประกอบเช่นการแปลงหรือชื่อ
ส่วนประกอบข้อมูลบางครั้งสามารถเก็บฟังก์ชั่น:
ส่วนประกอบของฟังก์ชั่นถือฟังก์ชั่นเพื่อสอบถามปรับเปลี่ยนหรือแจ้งเอนทิตีของพวกเขา
ส่วนประกอบของฟังก์ชั่นเป็นเพียงผู้ถือสำหรับ functors ที่สามารถแนบเป็นส่วนประกอบของเอนทิตี ช่างนี้สามารถใช้เพื่อ:
ส่วนประกอบของฟังก์ชั่นเป็นประเภทที่สืบทอดมาจาก 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 เป็นระบบสร้าง กรอบการทำงานที่กำหนดเองได้ถูกนำมาใช้เพื่อทำให้การสร้างห้องสมุดง่ายขึ้น Root 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
ประเภทการลงทะเบียนและรหัสสะท้อนอาจถูกสร้างขึ้นโดยอัตโนมัติสำหรับส่วนประกอบ โดยค่าเริ่มต้นส่วนหัวทั้งหมดใน data และ functions ของไลบรารีจะถูกส่งผ่านไปยังสคริปต์การสร้าง
ในทำนองเดียวกันกับไฟล์แหล่งที่มาหากมีไฟล์ *.tests.cpp พบใน helpers/tests หรือ systems/tests ย่อยของไลบรารีหรือไดเรกทอรีย่อยระบบจะถูกเพิ่มเข้ามาโดยอัตโนมัติ
CMakeLists.txt ไลบรารีพื้นฐานไม่จำเป็นต้องใช้ CMakeLists.txt ของตัวเองเนื่องจากไฟล์ต้นฉบับของพวกเขาจะเป็นไปโดยอัตโนมัติ อย่างไรก็ตามหากห้องสมุดต้องการพฤติกรรมที่กำหนดเอง (เช่นเพื่อเพิ่มแหล่งข้อมูลเพิ่มเติมหรือเชื่อมโยงกับไลบรารีของบุคคลที่สาม) มันอาจเพิ่ม CMakeLists.txt ของตัวเอง CMakeLists.txt นั้นจะถูกเรียก หลังจาก การโทรไปยัง add_library
ตัวแปรและฟังก์ชั่นต่อไปนี้ถูกกำหนดก่อนที่จะเรียก CMakeLists.txt :
kengine_library_name : ชื่อไลบรารีkengine_library_tests_name : ชื่อเป้าหมาย googleTest ของไลบรารี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 ว่าไม่ควรประมวล path เป็นห้องสมุด kengine