من فضلك تسجيل الدخول أو تسجيل لتفعل ذلك.

أصبح جودو (Godot) أحد محركات الألعاب الأكثر شعبية في السنوات القليلة الماضية. إنه محرك مجاني ومفتوح المصدر بموجب ترخيص MIT، وصغير بما يكفي للتنزيل والبدء في الاستخدام خلال دقائق. معظم ألعاب Godot تُكتب بلغة GDScript، وهي لغة البرمجة النصية الخاصة بالمحرك.

ومع ذلك، عاجلاً أم آجلاً، تحتاج العديد من المشاريع إلى دمج وظائف موجودة بالفعل كمكتبة C أو C++، مثل مكتبة محاكاة، أو قاعدة بيانات، أو بروتوكول شبكات، أو وقت تشغيل للتعلم الآلي. لا يستطيع GDScript استدعاء الكود الأصلي مباشرةً، لكن يمكن لمحرك Godot تحميل هذا الكود من خلال GDExtension، وتوفر godot-cpp، وهي روابط C++ الرسمية، إمكانية عرض هذا الكود كفئات محرك عادية. بينما تُعد كتابة كود C++ هي الجزء السهل، يكمن التحدي الأكبر في عملية البناء: يجب أن يتطابق godot-cpp مع إصدار Godot الخاص بك، ويجب تجميع كل مكتبة إضافية لكل منصة تستهدفها في شحن مشروعك.

في هذا المنشور، نقدم جولة قصيرة حول Godot، ونشرح كيفية عمل امتدادات C++، ونعرض كيفية جلب مكتبات C++ إلى لعبة Godot باستخدام كونان (Conan) و godot-cpp 10، المتوفرين الآن في ConanCenter. كمثال عملي، سنستخدم مكتبة فليكس (Flecs)، وهي مكتبة نظام مكونات الكيان، لمحاكاة 100,000 جسيم داخل مشهد Godot، حيث تهرب هذه الجسيمات من مؤشر الماوس وترتد عن حواف النافذة.

مقدمة سريعة عن جودو

Godot هو محرك متعدد الأغراض لتطوير الألعاب ثنائية وثلاثية الأبعاد. كل شيء في مشروع Godot مبني على مفهومين رئيسيين:

  • العقد (Nodes): هي اللبنات الأساسية للمشروع. لكل عقدة نوع محدد (مثل Sprite2D، Camera3D، AudioStreamPlayer، Timer)، ومجموعة من الخصائص التي يمكن تحريرها في المفتش، بالإضافة إلى دوال استدعاء مثل _ready() أو _process() التي يستدعيها المحرك أثناء حلقة اللعبة.
  • المشاهد (Scenes): هي أشجار من العقد المحفوظة على القرص كملفات .tscn. يمكن أن يمثل المشهد شخصية، أو قائمة، أو مستوى كاملًا، ويمكن إنشاء المشاهد داخل مشاهد أخرى.

عادةً ما تتم إضافة السلوك إلى العقد عن طريق إرفاق برنامج نصي بها. GDScript هي لغة شبيهة بلغة بايثون مصممة خصيصًا للمحرك، وهي ممتازة لمنطق اللعب لأن التغييرات تظهر على الفور دون الحاجة إلى خطوة ترجمة.

ما يجعل Godot مثيرًا للاهتمام لمطوري C++ هو أن المحرك نفسه مكتوب بلغة C++، ويمكنه تحميل الامتدادات المكتوبة بلغة C++ دون الحاجة إلى إعادة تجميع المحرك بالكامل. تصبح الفئة التي تأتي من أحد هذه الامتدادات فئة محرك عادية: تظهر في المحرر بجوار العقد المضمنة، مع خصائصها في المفتش، ويمكن لـ GDScript استخدامها مثل أي عقدة أخرى. يشرح القسم التالي كيفية عمل هذه الملحقات.

توسيع جودو باستخدام C++

هناك طريقتان لإضافة كود C++ إلى Godot:

  • وحدات المحرك (Engine Modules): يتم تجميعها داخل المحرك نفسه. تتيح الوصول الكامل إلى الأجزاء الداخلية للمحرك، ولكنها تتطلب منك إنشاء نسختك الخاصة من Godot وشحنها، بما في ذلك المحرر وقوالب التصدير لكل منصة.
  • امتداد GDExtension: يقوم بتحميل مكتبة مشتركة (مثل .dll، .so، .dylib، أو .wasm على الويب) إلى إصدار Godot الرسمي غير المعدل في وقت التشغيل. يتحدث المحرك إلى هذه المكتبة من خلال واجهة C مستقرة.

يُعد GDExtension هو النهج الموصى به لمعظم المشاريع، وهو الأساس الذي تُبنى عليه العديد من المكونات الإضافية الشائعة اليوم. نظرًا لأن واجهة C المباشرة قد تكون مطولة للاستخدام، يقدم فريق Godot مكتبة godot-cpp، وهي مكتبة C++ تغلف واجهة برمجة تطبيقات (API) قريبة جدًا من تلك المستخدمة داخل المحرك. توفر godot-cpp فئة C++ لكل فئة محرك، مثل Node2D، Sprite2D، أو Input.

فئاتك المخصصة هي كود C++ عادي مشتق من هذه الفئات. على سبيل المثال، يمكن لعقدة C++ بسيطة مكتوبة باستخدام godot-cpp أن ترث من Node2D وتتضمن ماكرو GDCLASS لإدراجها في نظام أنواع Godot، بالإضافة إلى دالة _process() لتنفيذ المنطق في كل إطار.

منذ الإصدار 10.0، يعمل إصدار واحد من godot-cpp مع أي إصدار من Godot بدءًا من الإصدار 4.3 وما بعده. يمكنك اختيار الإصدار المستهدف من Godot API باستخدام خيار البناء api_version، ويقوم godot-cpp بإنشاء فئات C++ الخاصة به من واجهة برمجة التطبيقات لهذا الإصدار. يعمل الملحق المصمم لـ Godot 4.3 أيضًا في الإصدارات الأحدث، ولكن ليس في الإصدارات الأقدم، لذلك عادةً ما تختار أقدم إصدار من Godot ترغب في دعمه.

بناء الأهداف وعلامات الميزات

هناك مفهوم آخر تحتاج إلى معرفته قبل بناء أي شيء: يتم تجميع godot-cpp لواحد من ثلاثة أهداف (targets)، والتي سُميت على اسم تصميمات Godot التي تقوم بتحميل المكتبة:

  • template_debug: هو الهدف الافتراضي. يمكّن هذا الهدف عمليات التحقق من الأخطاء من خلال تعريف DEBUG_ENABLED. يتم تحميل هذه المكتبة بواسطة المحرر وأثناء تصحيح الأخطاء.
  • template_release: يُستخدم لتصديرات الإصدار، حيث تتم إزالة عمليات التحقق من الأخطاء لزيادة الأداء.
  • editor: مخصص للمكتبات التي يتم تحميلها بواسطة المحرر فقط.

يتم تحديد المكتبة التي يقوم Godot بتحميلها في وقت التشغيل بواسطة ملف .gdextension صغير. يقوم هذا الملف بربط علامات الميزة (Feature Tags) بمسارات المكتبات. على سبيل المثال، تتطابق العلامة debug مع المحرر وتصحيح الأخطاء، وتتطابق العلامة release مع صادرات الإصدار. يوضح مثال على ملف .gdextension كيف يتم ربط علامات الميزات مثل macos.debug أو windows.release بمسارات المكتبات الثنائية المناسبة، مما يضمن تحميل الإصدار الصحيح بناءً على المنصة ونوع البناء.

سير العمل المعتاد

يوصي توثيق Godot بإضافة godot-cpp إلى مستودعك كوحدة فرعية لـ Git وبنائها مع مكتبتك باستخدام SCons. يعمل هذا بشكل جيد للامتداد الأول، ولكن كل مشروع سينتهي بتجميع godot-cpp الخاص به لكل هدف ومنصة وبنية. علاوة على ذلك، يجب بيع وتجميع أي مكتبة طرف ثالث يتم تغليفها، مثل محرك فيزيائي أو وقت تشغيل للتعلم الآلي، باستخدام علامات مطابقة لكل منصة يصدرها Godot إليها.

هذه هي بالضبط نوع المشكلات التي تم بناء كونان (Conan) لحلها.

إدارة التبعيات مع كونان

مع وجود وصفة godot-cpp في ConanCenter، تصبح godot-cpp حزمة عادية يمكن إدارتها. المعلمتان اللتان تمت مناقشتهما سابقًا (api_version و target) تُصبحان خيارات Conan:

  • api_version: يحدد إصدار Godot API الذي تستهدفه الارتباطات، ويتراوح عادةً من 4.3 إلى 4.7 (وهو الافتراضي).
  • target: يحدد هدف البناء، والذي يمكن أن يكون template_debug (الافتراضي)، أو template_release، أو editor.

يتم إنشاء كل مجموعة من هذه الإعدادات مرة واحدة ثم يُعاد استخدامها بواسطة كل مشروع يحتاج إليها، بدلاً من تجميعها داخل كل ملحق بشكل منفصل.

يصبح GDExtension الخاص بك مجرد مشروع C++ آخر له تبعيات. يمكن إضافة أي من المكتبات المتوفرة في مركز كونان، أو مكتبة تقوم بحزمها بنفسك باستخدام وصفة كونان، بجانب godot-cpp، ويقوم كونان ببنائها جميعًا بشكل متسق لكل منصة تستهدفها.

مثال عملي: سرب من 100.000 جسيم

لتوضيح كيفية عمل ذلك عمليًا، سنكتب امتداد GDExtension يسجل عقدة Swarm جديدة. ستحاكي هذه العقدة 100,000 جسيم تهرب من مؤشر الفأرة وترتد عن حواف النافذة، وترسمها جميعًا في مشهد Godot.

تستند عملية المحاكاة إلى مكتبة فليكس (Flecs)، وهي مكتبة نظام مكونات الكيان (ECS) لـ C وC++. في نموذج ECS، الكيانات هي معرفات بسيطة، والمكونات هي هياكل بيانات بسيطة مرتبطة بها، والأنظمة هي وظائف تعمل على كل كيان يحتوي على مجموعة معينة من المكونات. يتم تخزين المكونات من نفس النوع معًا في الذاكرة، مما يجعل التكرار على أعداد كبيرة من الكيانات سريعًا جدًا. لهذا السبب، تُعد ECS خيارًا شائعًا لألعاب المحاكاة أو الحشود. إنه أيضًا نوع العمل الذي يؤتي فيه الكود الأصلي ثماره، نظرًا لأن تحديث هذا العدد الكبير من الكيانات في كل إطار يكون أسرع بكثير في C++ منه في GDScript.

يمكنك العثور على المثال الكامل في مستودع أمثلة كونان 2. لنسخ المشروع، يمكنك استخدام أمر git clone ثم الانتقال إلى الدليل examples2/examples/libraries/godot-cpp/gdextension.

يحتوي المجلد src على رمز الامتداد، بينما demo هو مشروع Godot العادي الذي يقوم بتحميله.

إعلان التبعيات

يتطلب ملف conanfile.py مكتبتي godot-cpp و flecs من مركز كونان. في هذا الملف، تقوم بتحديد التبعيات مثل godot-cpp/10.0.0 و flecs/4.1.6. التفاصيل الوحيدة المحددة لجودو موجودة في دالة generate()، حيث يتم قراءة خيار target الخاص بتبعية godot-cpp وتمريره إلى CMake، مما يضمن تطابق اسم المكتبة دائمًا مع الثنائي godot-cpp المرتبط به.

ملف CMakeLists.txt

ملف CMakeLists.txt الخاص بالمشروع هو ملف CMake قياسي تمامًا. الامتداد عبارة عن مكتبة مشتركة تربط godot-cpp و flecs بشكل ثابت، مما يؤدي إلى ملف مكتبة واحد ليتم شحنه. يتم إخراج هذا الملف مباشرة إلى demo/bin لكي يجده Godot دون الحاجة إلى خطوة نسخ إضافية. تُستخدم خصائص الهدف (target properties) لتحديد اسم الإخراج (مثل gdexample.${GODOTCPP_TARGET}) ودليل الإخراج.

كتابة العقدة

الطبقة Swarm مشتقة من Node2D وتمتلك عالم Flecs. مكونات كل جسيم هي بنيات بسيطة، مثل بنيات Position و Velocity التي تحتوي على إحداثيات x و y. يضيف ماكرو GDCLASS النموذج المعياري الذي يحتاجه نظام طبقات Godot، وتُعلن دالة _bind_methods() عن الخصائص التي يمكن لـ Godot رؤيتها، مثل count و flee_radius. بمجرد تسجيل الفئة، تظهر في المفتش ويمكن استخدامها من خلال GDScript.

بقية العقدة تربط بين العالمين. تقوم دالة _ready() بإنشاء كيان واحد لكل جسيم ونظام يقوم بتحديثها. كما تقوم بإعداد MultiMesh، وهي آلية تسمح برسم العديد من مثيلات نفس الشبكة في مكالمة سحب واحدة، حيث أن استخدام عقدة Godot واحدة لكل جسيم سيكون مكلفًا جدًا لـ 100,000 جسيم.

في كل إطار، تقوم دالة _process() بتسليم موضع الماوس إلى Flecs، وتشغيل الأنظمة باستخدام world.progress()، ونسخ المواضع الناتجة مرة أخرى إلى MultiMesh لتحديث عرض الجسيمات.

تسجيل الامتداد

أخيرًا، يسجل ملف register_types.cpp الفئة عندما يقوم Godot بتحميل المكتبة. يتم تسجيل Swarm باستخدام GDREGISTER_RUNTIME_CLASS. هذا يجعلها تعمل كعنصر نائب في المحرر حيث يمكنك تعيين خصائصها، ولكن الكود الخاص بها يعمل فقط عند تشغيل اللعبة.

يحدد نفس الملف دالة gdexample_library_init()، وهي نقطة الدخول المذكورة في ملف .gdextension. وهي عبارة عن بضعة أسطر من الكود النموذجي الذي يبدو متشابهًا في كل امتداد.

البناء والتشغيل

مع وجود كل شيء في مكانه الصحيح، يصبح إنشاء الامتداد أمرًا بسيطًا باستخدام Conan. يقوم Conan بحل تبعيات godot-cpp و flecs، وتنزيل الثنائيات المترجمة مسبقًا من ConanCenter (عند توفرها لتكوينك)، وإنشاء الباقي من المصدر، وإنشاء تكامل CMake، وأخيرًا بناء الامتداد.

ملاحظة: يتطلب godot-cpp C++ 17. إذا كان ملف التعريف الافتراضي الخاص بك يستخدم معيارًا أقدم (كما هو الحال بالنسبة لـ MSVC)، فستحتاج إلى إضافة -s compiler.cppstd=17 إلى الأمر عند البناء.

الآن، ابدأ تشغيل Godot 4.7، وانقر فوق ‘استيراد’ في مدير المشروع، ثم حدد ملف demo/project.godot. عندما يتم فتح المشروع، يقرأ Godot ملف bin/gdexample.gdextension، ويقوم بتحميل المكتبة، وتصبح عقدة Swarm متاحة مثل أي عقدة مدمجة. يمكنك العثور عليها في مربع الحوار ‘إنشاء عقدة جديدة’ ضمن Node2D.

باختيارها، ستظهر خصائص count و flee_radius التي ربطناها في المفتش. اضغط على تشغيل لتشغيل المشهد، وحرك الماوس فوق النافذة لدفع الجسيمات. ثم توقف، وقم بتغيير قيمة count أو flee_radius في المفتش، وقم بتشغيلها مرة أخرى لترى كيف يتصرف السرب مع المزيد من الجسيمات أو نصف قطر الطيران الأوسع.

الاستنتاج

يتيح لك GDExtension و godot-cpp كتابة فئات المحرك بلغة C++ عالية الأداء، ويهتم Conan بإدارة وبناء godot-cpp وأي مكتبة C++ أخرى تحتاجها. تعد هذه أيضًا ميزة كبيرة عند توزيع الامتداد: إن إنشائه لكل نظام أساسي تقوم بالشحن إليه لا يتطلب سوى تغيير إعدادات الإصدار، مما يبسط عملية التطوير والنشر.

ملاحظة لنظام التشغيل Linux: بشكل افتراضي، تربط الامتدادات مكتبة libstdc++ ديناميكيًا، لذا يجب أن يوفر النظام المستهدف إصدارًا حديثًا على الأقل مثل الإصدار المستخدم في بناء الامتداد. للحصول على توافق واسع النطاق، قم ببناء الامتداد وتبعياته مقابل سلسلة أدوات ومكتبات نظام متوافقة مع أقدم توزيع تنوي دعمه. بدلاً من ذلك، يمكنك ربط libstdc++ بشكل ثابت وإخفاء رموزه باستخدام البرنامج النصي لإصدار الرابط (linker version script).

جرّب المثال الكامل، وتحقق من وثائق godot-cpp لمعرفة المزيد عن كتابة الامتدادات. إذا كان لديك أي تعليقات أو واجهت أي مشكلة، فيرجى إخبارنا بذلك في مستودع كونان جيثب. نتمنى لكم تطوير ألعاب سعيد!

تمت كتابة هذا المنشور بمساعدة الذكاء الاصطناعي وتمت مراجعته من قبل البشر.

دوري برودي الترفيهي لكرة السلة يتوسع في كندا بفضل دعم الذكاء الاصطناعي
تعطل مفاجئ: Firebase SDK يتسبب في انهيار تطبيقات iOS عالميًا

Reactions

0
0
0
0
0
0
بالفعل كان رد فعل لهذا المنصب.

ردود الفعل