الفرق بين المراجعتين لصفحة: «Godot/best practices/scenes versus scripts»
Naser-dakhel (نقاش | مساهمات) ط تعديل تنسيق |
Naser-dakhel (نقاش | مساهمات) لا ملخص تعديل |
||
(1 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:كيف تختار بين المشاهد وملفات الشيفرة البرمجية}}</noinclude> | |||
تكلمنا مسبقًا أن المشاهد scenes | تكلمنا مسبقًا أن المشاهد scenes والسكربتات scripts أمران مختلفان، فالسكربتات تعرّف صنفًا إضافيًا ضمن المحرك باستخدام التعليمات البرمجية، بينما تستخدم المشاهد البرمجة التصريحية. | ||
كنتيجة لذلك، تكون إمكانيات كل نظام مختلفة، إذ تعرّف المشاهد كيفية تهيئة الصنف المُضاف ولكن لا تعرّف سلوكه، إذ تُستخدم المشاهد عادةً مع ملفات الشيفرة البرمجية بحيث يعرف المشهد مجموعة من العقد ويُضيف عليها السكربت سلوكًا باستخدام التعليمات البرمجية. | |||
== الأنواع المجهولة == | |||
من الممكن تعريف محتويات المشهد بالكامل باستخدام سكربت فقط، وهذا ما يفعله محرّر جودو في حقيقة الأمر، إلا أن الأمر يتم باستخدام سي بلس بلس C++ للكائنات. | |||
عملية الاختيار فيما بينهما قد تكون معضلة، إذ أن إنشاء نسخ من سكربت مطابق لإنشاء أصناف في المحرك، بينما يتطلب معالجة المشاهد تغييرًا في الواجهة البرمجية API:<syntaxhighlight lang="py"> | |||
من الممكن تعريف محتويات المشهد بالكامل باستخدام | |||
عملية الاختيار فيما بينهما قد تكون معضلة، إذ أن إنشاء نسخ من | |||
const MyNode = preload("my_node.gd") | const MyNode = preload("my_node.gd") | ||
const MyScene = preload("my_scene.tscn") | const MyScene = preload("my_scene.tscn") | ||
سطر 15: | سطر 12: | ||
var my_node = MyNode.new() # استدعاء للتابع نفسه | var my_node = MyNode.new() # استدعاء للتابع نفسه | ||
var my_scene = MyScene.instantiate() # استدعاء تابع مختلف | var my_scene = MyScene.instantiate() # استدعاء تابع مختلف | ||
var my_inherited_scene = MyScene.instantiate(PackedScene.GEN_EDIT_STATE_MAIN) # إنشاء مشهد يرث | var my_inherited_scene = MyScene.instantiate(PackedScene.GEN_EDIT_STATE_MAIN) # إنشاء مشهد يرث من MyScene | ||
</syntaxhighlight>تعمل | </syntaxhighlight>تعمل السكربتات بشكل أبطئ بقليل من المشاهد نظرًا إلى فرق السرعة بين المحرك والشيفرة بداخل هذه الملفات، كلما كبرت العقدة وزاد تعقيدها، زادت الحاجة لبنائها كمشهد. | ||
== الأنواع المسمّاة == | |||
يمكن | يمكن للسكربتات أن تُسجّل كنوع جديد ضمن المحرر، وهذا يجعلها متاحة كنوع جديد ضمن قائمة إنشاء مورد أو عقدة جديدة مع خيار إضافة أيقونة مناسبة للنوع، وبهذه الطريقة يمكن للمستخدم أن يستخدم السكربت في أكثر من موضع دون أن: | ||
# يعرف النوع الأساس | # يعرف النوع الأساس للسكربت الذي يريد أن يستخدمه. | ||
# يُنشئ نسخة من النوع الأساس. | # يُنشئ نسخة من النوع الأساس. | ||
# يُضيف | # يُضيف السكربت إلى العقدة. | ||
يصبح نوع السكربت المسجّل خيارًا عند إنشاء العُقد والموارد في النظام، وتحتوي القائمة على صندوق بحث يمكنك استخدامه لكتابة اسمه والبحث عنه. | |||
هناك نوعان من الأنظمة لتسجيل الأنواع: | هناك نوعان من الأنظمة لتسجيل الأنواع: | ||
سطر 34: | سطر 29: | ||
** تُستخدم من قبل المحرر فقط، ولا يمكن الوصول إلى أسماء الأنواع عند وقت التنفيذ. | ** تُستخدم من قبل المحرر فقط، ولا يمكن الوصول إلى أسماء الأنواع عند وقت التنفيذ. | ||
** لا تدعم أنواع مخصصة موروثة. | ** لا تدعم أنواع مخصصة موروثة. | ||
** أداة للتهيئة يقتصر عملها على إنشاء العقدة مع | ** أداة للتهيئة يقتصر عملها على إنشاء العقدة مع السكربت. | ||
** لا يمتلك المحرر أي وعي بخصوص | ** لا يمتلك المحرر أي وعي بخصوص السكربت أو علاقته مع أنواع المحرك أو السكربتات الأخرى. | ||
** يسمح للمستخدمين بإضافة أيقونة. | ** يسمح للمستخدمين بإضافة أيقونة. | ||
** يعمل في جميع لغات البرمجة، لأنه يتعامل مع موارد | ** يعمل في جميع لغات البرمجة، لأنه يتعامل مع موارد السكربت بشكل تجريدي. | ||
** يُهيّأ باستخدام <code>EditorPlugin.add_custom_type</code>. | ** يُهيّأ باستخدام <code>EditorPlugin.add_custom_type</code>. | ||
* أصناف ملفات الشيفرة البرمجية | * أصناف ملفات الشيفرة البرمجية | ||
** يمكن الوصول إليها من المحرر وعند وقت التنفيذ. | ** يمكن الوصول إليها من المحرر وعند وقت التنفيذ. | ||
** تعرض علاقات الوراثة بالكامل. | ** تعرض علاقات الوراثة بالكامل. | ||
** تُنشئ العقدة في | ** تُنشئ العقدة في السكربت ولكن يمكنها أيضًا تغيير الأنواع أو الإضافة على نوع من أنواع المحرر. | ||
** يعي المحرر علاقات الوراثة بين | ** يعي المحرر علاقات الوراثة بين السكربتات وأصناف class السكربتات وأصناف سي بلس بلس الخاصة بالمحرر. | ||
** يسمح للمستخدمين بتعريف أيقونة. | ** يسمح للمستخدمين بتعريف أيقونة. | ||
** يجب على مطوّري المحرك إضافة الدعم للّغات بشكل يدوي (للوصول لاسم الملف والوصول عند وقت التنفيذ). | ** يجب على مطوّري المحرك إضافة الدعم للّغات بشكل يدوي (للوصول لاسم الملف والوصول عند وقت التنفيذ). | ||
سطر 49: | سطر 44: | ||
** يبحث المحرر في مجلدات المشروع ويسجّل أي اسم مكشوف (يقبل الوصول) لجميع لغات البرمجة، يجب أن تطبّق كل لغة برمجة دعمها لكشف هذه المعلومات. | ** يبحث المحرر في مجلدات المشروع ويسجّل أي اسم مكشوف (يقبل الوصول) لجميع لغات البرمجة، يجب أن تطبّق كل لغة برمجة دعمها لكشف هذه المعلومات. | ||
تُضيف الطريقتان أسماءً إلى قائمة إنشاء العُقد، إلا أن أصناف | تُضيف الطريقتان أسماءً إلى قائمة إنشاء العُقد، إلا أن أصناف السكربتات تحديدًا تسمح للمستخدمين بالوصول إلى اسم النوع دون تحميل مورد السكربت. يمكن إنشاء نسخ والوصول إلى الثوابت أو التوابع الساكنة من أي مكان. | ||
قد تريد للنوع الخاص بك أن يكون | قد تريد للنوع الخاص بك أن يكون سكربت دون مشهد نظرًا لسهولة استخدامه، وسيجد من يطوّر الإضافات أو الأدوات الخاصة بالمصممين سهولةً أكبر بهذه الطريقة، على الجانب الآخر، تعني هذه الطريقة أنه عليك كتابة تعليمات برمجية مطوّلة. | ||
== أداء ملفات الشيفرة البرمجية مقارنةً بعقدة PackedScene == | |||
أمرٌ آخر عليك أخذه بالحسبان هو سرعة التنفيذ عند الاختيار بين المشاهد | أمرٌ آخر عليك أخذه بالحسبان هو سرعة التنفيذ عند الاختيار بين المشاهد والسكربتات. | ||
ينمو حجم السكربتات المطلوب لإنشاء وتهيئة الكائنات مع زيادة حجمها، وتوضح هيكلية العُقد ذلك، إذ يمكن لكل عقدة أن تكون مؤلفة من مئات الأسطر البرمجية. | |||
نُنشئ في المثال أدناه عقدة جديدة <code>Node</code> ونغيّر من اسمها ومن ثم نُسند سكربت إليها، ونضبط أباها المستقبلي كمالكها بحيث تُحفظ على قرص التخزين معه، وأخيرًا، نضيفها كعقدة ابن للعقدة <code>Main</code>: | |||
نُنشئ في المثال أدناه عقدة جديدة <code>Node</code> ونغيّر من اسمها ومن ثم نُسند | |||
<syntaxhighlight lang="py"> | <syntaxhighlight lang="py"> | ||
سطر 75: | سطر 67: | ||
</syntaxhighlight>الشيفرات البرمجية المماثلة لما سبق أبطأ بكثير من شيفرة المحرك المكتوبة بلغة سي بلس بلس، إذ أن كل تعليمة تستدعي الواجهة البرمجية الخاصة بالمحرك مما يؤدي إلى وجود الكثير من الاستدعاءات في الواجهة الخلفية للمحرك للعثور على المنطق المناسب لتنفيذه. | </syntaxhighlight>الشيفرات البرمجية المماثلة لما سبق أبطأ بكثير من شيفرة المحرك المكتوبة بلغة سي بلس بلس، إذ أن كل تعليمة تستدعي الواجهة البرمجية الخاصة بالمحرك مما يؤدي إلى وجود الكثير من الاستدعاءات في الواجهة الخلفية للمحرك للعثور على المنطق المناسب لتنفيذه. | ||
تساعد المشاهد في تفادي مشاكل تراجع الأداء، إذ يعرّف النوع الأساس <code>PackedScene</code> الذي ترث المشاهد منه مواردًا تستخدم بيانات متسلسلة لإنشاء الكائنات، ويمكن للمحرك معالجة المشاهد على دفعات في الواجهة الخلفية وتقديم أداء أفضل بكثير من السكربتات. | |||
تساعد المشاهد في تفادي مشاكل تراجع الأداء، إذ يعرّف النوع الأساس <code>PackedScene</code> الذي ترث المشاهد منه مواردًا تستخدم بيانات متسلسلة لإنشاء الكائنات، ويمكن للمحرك معالجة المشاهد على دفعات في الواجهة الخلفية وتقديم أداء أفضل بكثير | == خلاصة == | ||
السلوك الأفضل للتحديد بين الطريقتين هو النظر إلى ما يلي: | السلوك الأفضل للتحديد بين الطريقتين هو النظر إلى ما يلي: | ||
* إذا أردت إضافة أداة بسيطة ستعيد استخدامها مرات عدّة في مختلف المشاريع، وتعتقد أن الناس من جميع المستويات سيُعجبون بها (بما فيهم الأشخاص الذين لا يدعون أنفسهم بالمبرمجين)، فهذا يعني أنه يجب عليك غالبًا أن تستخدم | * إذا أردت إضافة أداة بسيطة ستعيد استخدامها مرات عدّة في مختلف المشاريع، وتعتقد أن الناس من جميع المستويات سيُعجبون بها (بما فيهم الأشخاص الذين لا يدعون أنفسهم بالمبرمجين)، فهذا يعني أنه يجب عليك غالبًا أن تستخدم سكربت مع إضافة اسم وأيقونة مخصصتين له. | ||
* إذا أردت إنشاء مفهوم له علاقة بلعبة معينة فقط، فلربما الخيار الأفضل هنا هو إنشاء مشهد، فالمشاهد أسهل في تتبعها وتعديلها وتقدّم أمانًا أكبر من | * إذا أردت إنشاء مفهوم له علاقة بلعبة معينة فقط، فلربما الخيار الأفضل هنا هو إنشاء مشهد، فالمشاهد أسهل في تتبعها وتعديلها وتقدّم أمانًا أكبر من السكربتات. | ||
* إذا أردت تسمية مشهد فيمكنك فعل ذلك من خلال التصريح عن صنف | * إذا أردت تسمية مشهد فيمكنك فعل ذلك من خلال التصريح عن صنف سكربت وتمرير المشهد له كثابت، مما يجعل السكربت يتصرف كفضاء أسماء namespace: | ||
<syntaxhighlight lang="py"> | <syntaxhighlight lang="py"> | ||
# game.gd | # game.gd | ||
class_name Game # يوسّع | class_name Game # يوسّع الصنف RefCounted, بحيث لا يظهر في قائمة اختيار العقد | ||
extends RefCounted | extends RefCounted | ||
سطر 96: | سطر 86: | ||
add_child(Game.MyScene.instantiate()) | add_child(Game.MyScene.instantiate()) | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== مصادر == | |||
* [https://docs.godotengine.org/en/stable/tutorials/best_practices/scenes_versus_scripts.html صفحة Scenes Versus Scripts في توثيق جودو الرسمي.] | |||
[[تصنيف:Godot|{{SUBPAGENAME}}]] | |||
[[تصنيف:Godot Best Practices|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 17:15، 26 أغسطس 2023
تكلمنا مسبقًا أن المشاهد 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
تعمل السكربتات بشكل أبطئ بقليل من المشاهد نظرًا إلى فرق السرعة بين المحرك والشيفرة بداخل هذه الملفات، كلما كبرت العقدة وزاد تعقيدها، زادت الحاجة لبنائها كمشهد.
الأنواع المسمّاة
يمكن للسكربتات أن تُسجّل كنوع جديد ضمن المحرر، وهذا يجعلها متاحة كنوع جديد ضمن قائمة إنشاء مورد أو عقدة جديدة مع خيار إضافة أيقونة مناسبة للنوع، وبهذه الطريقة يمكن للمستخدم أن يستخدم السكربت في أكثر من موضع دون أن:
- يعرف النوع الأساس للسكربت الذي يريد أن يستخدمه.
- يُنشئ نسخة من النوع الأساس.
- يُضيف السكربت إلى العقدة.
يصبح نوع السكربت المسجّل خيارًا عند إنشاء العُقد والموارد في النظام، وتحتوي القائمة على صندوق بحث يمكنك استخدامه لكتابة اسمه والبحث عنه.
هناك نوعان من الأنظمة لتسجيل الأنواع:
- الأنواع المخصصة
- تُستخدم من قبل المحرر فقط، ولا يمكن الوصول إلى أسماء الأنواع عند وقت التنفيذ.
- لا تدعم أنواع مخصصة موروثة.
- أداة للتهيئة يقتصر عملها على إنشاء العقدة مع السكربت.
- لا يمتلك المحرر أي وعي بخصوص السكربت أو علاقته مع أنواع المحرك أو السكربتات الأخرى.
- يسمح للمستخدمين بإضافة أيقونة.
- يعمل في جميع لغات البرمجة، لأنه يتعامل مع موارد السكربت بشكل تجريدي.
- يُهيّأ باستخدام
EditorPlugin.add_custom_type
.
- أصناف ملفات الشيفرة البرمجية
- يمكن الوصول إليها من المحرر وعند وقت التنفيذ.
- تعرض علاقات الوراثة بالكامل.
- تُنشئ العقدة في السكربت ولكن يمكنها أيضًا تغيير الأنواع أو الإضافة على نوع من أنواع المحرر.
- يعي المحرر علاقات الوراثة بين السكربتات وأصناف class السكربتات وأصناف سي بلس بلس الخاصة بالمحرر.
- يسمح للمستخدمين بتعريف أيقونة.
- يجب على مطوّري المحرك إضافة الدعم للّغات بشكل يدوي (للوصول لاسم الملف والوصول عند وقت التنفيذ).
- موجود في إصدار 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())