Godot/best practices/scene organization
سنغطّي في هذا القسم جميع المواضيع المرتبطة بالتنظيم الجيد لمحتوى المشهد، وسنجيب على بعض الأسئلة؛ ما هي العقد التي يجب أن تستخدمها؟ كيف عليك ترتيبها؟ كيف يجب على العقد أن تتفاعل مع بعضها البعض؟
كيفية بناء العلاقات بطريقة مثلى
يواجه مستخدمو جودو المشاكل التالية عندما يبدؤون بإنشاء المشاهد في مشاريعهم:
ينشؤون أولى مشاهدهم ويملؤونها بالمحتوى وينتهي بهم المطاف بحفظ فروع من المشهد إلى مشاهد منفصلة بفضل الحاجة الملحّة لفصل الأشياء، إلا أنه سرعان ما يلاحظون أن المراجع الثابتة التي كانوا سيعتمدون عليها لم تصبح ممكنةً بعد الآن، فاستخدام المشهد عدة مرات في عدة أماكن يخلق مشكلات لأن مسارات العقدة لا تستطيع إيجاد هدفها كما تتعطّل صلات الإشارات في المحرّر.
لتصحيح هذه المشكلة، يجب عليك إنشاء نسخة من مشاهد جزئية دون أن تتطلب تلك المشاهد تفاصيلًا بخصوص بيئتها، فيجب على المشهد الجزئي أن يكون قادرًا على إنشاء نفسه دون قيود حول حالة استخدامه.
من أهم الأشياء التي عليك الانتباه بشأنها بخصوص البرمجة كائنية التوجه هو المحافظة على تخصّص الأصناف وتنفيذها لغرض وحيد وتجنّب ربطها دون حاجة مع سائر أجزاء المشروع، إذ يحافظ ذلك على صغر حجم الكائنات (مما يسهّل التعديل عليها لاحقًا) وسهولة إعادة استخدامها. لممارسات البرمجة كائنية التوجه المثلى هذه تأثير كبير على الممارسات المثلى في هيكلة المشاهد واستخدام ملفات الشيفرة البرمجية.
الطريقة المثلى لتصميم المشاهد هي بتصميمها دون احتوائها على أي اعتماديات إذا أمكن، أي يجب على المشهد أن يحتوي كل شيء يستخدمه بداخله. إذا كان لا بدّ من المشهد أن يتفاعل مع كائنات أخرى خارج سياقه فالحلّ الذي ينصح به المطوّرون المتمرّسون يكمن بحقن الاعتمادية dependency injection، إذ تنضوي هذه الطريقة على وجود واجهة برمجية API عالية المستوى تقدّم الاعتماديات للواجهة البرمجية ذات المستوى الأدنى؛ لكن لم قد تفعل ذلك؟ لأنه يمكن للأصناف التي تعتمد على بيئتها الخارجية توليد أخطاء وسلوك غير متوقّع.
لفعل ذلك، عليك كشف البيانات التي تريد مشاركتها وتعتمد على كائن أب لتهيئتها:
- اتّصل بإشارة، هذه العملية آمنة لكن يجب استخدامها فقط كاستجابة لسلوك وليس لتشغيله، وتسمى الإشارات اصطلاحًا بأفعال ماضية مثل entered أو skill_activated أو item_collected.
# الأب $Child.signal_name.connect(method_on_the_object) # الابن signal_name.emit() # يشغل السلوك المعرف في الأب
- استدعاء تابع للبدء بالسلوك.
# الأب $Child.method_name = "do" # الابن بافتراض احتوائه على خاصية "method_name" من نوع سلسلة نصية وتابع "do" call(method_name) # استدعاء التابع المعرف في الأب (الذي يجب على الابن أن يمتلكه).
- تهيئة خاصية قابلة للاستدعاء callable، وهي عملية أكثر أمانًا من وجود تابع لأن بما أن ملكية التابع غير مهمة، ومن ثم استخدامها للبدء بالسلوك.
# الأب $Child.func_property = object_with_method.method_on_the_object # الابن func_property.call() # استدعاء الدالة المعرفة في الأب (يمكن الاستدعاء من أي مكان).
- تهيئة عقدة أو أي مرجع لكائن آخر.
# الأب $Child.target = self # الابن print(target) # استخدام عقدة معرفة في الأب
- تهيئة NodePath.تُخفي هذه الخيارات نقاط الوصول من العقدة الابن، مما يجعل ارتباط الابن مع بيئته إلى أدنى درجة، ويمكن إعادة استخدامها في سياق آخر دون تغيير إضافي على الواجهة البرمجية.
# الأب $Child.target_path = ".." # الابن get_node(target_path) # استخدام NodePath معرفة في الأب