Godot/best practices/scenes versus scripts

من موسوعة حسوب
مراجعة 13:11، 26 أغسطس 2023 بواسطة Naser-dakhel (نقاش | مساهمات) (إضافة الصفحة)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

كيف تختار بين المشاهد وملفات الشيفرة البرمجية

تكلمنا مسبقًا أن المشاهد scenes وملفات الشيفرة البرمجية scripts أمران مختلفان، فملفات الشيفرة البرمجية تعرّف صنفًا إضافيًا ضمن المحرك باستخدام التعليمات البرمجية، بينما تستخدم المشاهد البرمجة التصريحية.


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

الأنواع المجهولة

من الممكن تعريف محتويات المشهد بالكامل باستخدام ملف شيفرة برمجية فقط، وهذا ما يفعله محرّر جودو في حقيقة الأمر، إلا أن الأمر يتم باستخدام سي بلس بلس C++ للكائنات.


عملية الاختيار فيما بينهما قد تكون معضلة، إذ أن إنشاء نسخ من ملف شيفرة برمجية مطابق لإنشاء أصناف في المحرك، بينما يتطلب معالجة المشاهد تغييرًا في الواجهة البرمجية API:

const MyNode = preload("my_node.gd")
const MyScene = preload("my_scene.tscn")
var node = Node.new()
var my_node = MyNode.new() # استدعاء للتابع نفسه
var my_scene = MyScene.instantiate() # استدعاء تابع مختلف
var my_inherited_scene = MyScene.instantiate(PackedScene.GEN_EDIT_STATE_MAIN) # إنشاء مشهد يرث من MyScene

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

الأنواع المسمّاة

يمكن لملفات الشيفرة البرمجية أن تُسجّل كنوع جديد ضمن المحرر، وهذا يجعلها متاحة كنوع جديد ضمن قائمة إنشاء مورد أو عقدة جديدة مع خيار إضافة أيقونة مناسبة للنوع، وبهذه الطريقة يمكن للمستخدم أن يستخدم ملف الشيفرة البرمجية في أكثر من موضع دون أن:

  1. يعرف النوع الأساس لملف الشيفرة البرمجية التي يريد أن يستخدمه.
  2. يُنشئ نسخة من النوع الأساس.
  3. يُضيف ملف الشيفرة البرمجية إلى العقدة.


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


هناك نوعان من الأنظمة لتسجيل الأنواع:

  • الأنواع المخصصة
    • تُستخدم من قبل المحرر فقط، ولا يمكن الوصول إلى أسماء الأنواع عند وقت التنفيذ.
    • لا تدعم أنواع مخصصة موروثة.
    • أداة للتهيئة يقتصر عملها على إنشاء العقدة مع ملف الشيفرة البرمجية.
    • لا يمتلك المحرر أي وعي بخصوص ملف الشيفرة البرمجية أو علاقته مع أنواع المحرك أو ملفات الشيفرة البرمجية الأخرى.
    • يسمح للمستخدمين بإضافة أيقونة.
    • يعمل في جميع لغات البرمجة، لأنه يتعامل مع موارد ملف الشيفرة البرمجية بشكل تجريدي.
    • يُهيّأ باستخدام EditorPlugin.add_custom_type.
  • أصناف ملفات الشيفرة البرمجية
    • يمكن الوصول إليها من المحرر وعند وقت التنفيذ.
    • تعرض علاقات الوراثة بالكامل.
    • تُنشئ العقدة في ملف الشيفرة البرمجية ولكن يمكنها أيضًا تغيير الأنواع أو الإضافة على نوع من أنواع المحرر.
    • يعي المحرر علاقات الوراثة بين ملفات الشيفرة البرمجية وأصناف ملفات الشيفرة البرمجية وأصناف سي بلس بلس الخاصة بالمحرر.
    • يسمح للمستخدمين بتعريف أيقونة.
    • يجب على مطوّري المحرك إضافة الدعم للّغات بشكل يدوي (للوصول لاسم الملف والوصول عند وقت التنفيذ).
    • موجود في إصدار 3.1 وما بعد.
    • يبحث المحرر في مجلدات المشروع ويسجّل أي اسم مكشوف (يقبل الوصول) لجميع لغات البرمجة، يجب أن تطبّق كل لغة برمجة دعمها لكشف هذه المعلومات.

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


قد تريد للنوع الخاص بك أن يكون ملف شيفرة برمجية دون مشهد نظرًا لسهولة استخدامه، وسيجد من يطوّر الإضافات أو الأدوات الخاصة بالمصممين سهولةً أكبر بهذه الطريقة، على الجانب الآخر، تعني هذه الطريقة أنه عليك كتابة تعليمات برمجية مطوّلة.

أداء ملفات الشيفرة البرمجية مقارنةً بعقدة PackedScene

أمرٌ آخر عليك أخذه بالحسبان هو سرعة التنفيذ عند الاختيار بين المشاهد وملفات الشيفرة البرمجية.


ينمو حجم ملفات الشيفرة البرمجية المطلوب لإنشاء وتهيئة الكائنات مع زيادة حجمها، وتوضح هيكلية العُقد ذلك، إذ يمكن لكل عقدة أن تكون مؤلفة من مئات الأسطر البرمجية.


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

# main.gd
extends Node

func _init():
    var child = Node.new()
    child.name = "Child"
    child.script = preload("child.gd")
    child.owner = self
    add_child(child)

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


تساعد المشاهد في تفادي مشاكل تراجع الأداء، إذ يعرّف النوع الأساس PackedScene الذي ترث المشاهد منه مواردًا تستخدم بيانات متسلسلة لإنشاء الكائنات، ويمكن للمحرك معالجة المشاهد على دفعات في الواجهة الخلفية وتقديم أداء أفضل بكثير لملفات الشيفرة البرمجية.

خلاصة

السلوك الأفضل للتحديد بين الطريقتين هو النظر إلى ما يلي:

  • إذا أردت إضافة أداة بسيطة ستعيد استخدامها مرات عدّة في مختلف المشاريع، وتعتقد أن الناس من جميع المستويات سيُعجبون بها (بما فيهم الأشخاص الذين لا يدعون أنفسهم بالمبرمجين)، فهذا يعني أنه يجب عليك غالبًا أن تستخدم ملف شيفرة برمجية وإضافة اسم وأيقونة مخصصتين له.
  • إذا أردت إنشاء مفهوم له علاقة بلعبة معينة فقط، فلربما الخيار الأفضل هنا هو إنشاء مشهد، فالمشاهد أسهل في تتبعها وتعديلها وتقدّم أمانًا أكبر من ملفات الشيفرة البرمجية.
  • إذا أردت تسمية مشهد فيمكنك فعل ذلك من خلال التصريح عن صنف ملف شيفرة برمجية وتمرير المشهد له كثابت، مما يجعل ملف الشيفرة البرمجية يتصرف كفضاء أسماء namespace:
# game.gd
class_name Game # يوسّع الصنف RefCounted, بحيث لا يظهر في قائمة اختيار العقد
extends RefCounted

const MyScene = preload("my_scene.tscn")

# main.gd
extends Node
func _ready():
    add_child(Game.MyScene.instantiate())