مشروع مرجعي للنباتات

*This content is translated using AI (Beta) and may contain errors. To view this page in English, click here.

Plant هي لعبة مرجعية حيث يزرع اللاعبون البذور ويسقونها، حتى يتمكنوا لاحقًا من حصاد النباتات الناتجة وبيعها.

لافتة مشروع النباتات

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

احصل على الملف

  1. انتقل إلى صفحة لعبة Plant.
  2. انقر على زر ثم تحرير في الاستوديو.

حالات الاستخدام

تغطي Plant حالات الاستخدام التالية:

  • بيانات الجلسة واستمرارية بيانات اللاعب
  • إدارة عرض واجهة المستخدم
  • الشبكات بين العميل والخادم
  • تجربة المستخدم للمرة الأولى (FTUE)
  • عمليات الشراء بالعملة الصعبة واللينة

بالإضافة إلى ذلك، يحل هذا المشروع مجموعات أضيق من المشكلات التي تنطبق على العديد من الألعاب، بما في ذلك:

  • تخصيص منطقة في المكان المرتبطة بلاعب
  • إدارة سرعة حركة شخصية اللاعب
  • إنشاء كائن يتبع الشخصيات
  • اكتشاف الجزء الذي تتواجد فيه الشخصية في العالم

لاحظ أن هناك العديد من حالات الاستخدام في هذه اللعبة صغيرة جدًا، أو متخصصة جدًا، أو لا تظهر حلاً لتحدي تصميم مثير؛ هذه الحالات غير مشمولة.

هيكل المشروع

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

نموذج البيانات

تصف الجدول التالي خدمات الحاويات التي يتم وضع المثيلات فيها في نموذج البيانات.

الخدمةأنواع المثيلات
Workspace

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

يوجد أيضًا Folder فارغ، سيتم إضافة نماذج المزرعة الخاصة باللاعبين إليه في وقت التشغيل.

Lighting

تأثيرات جوية وإضاءة.

ReplicatedFirst

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

  • في مجلد Instances توجد واجهة المستخدم لشاشة التحميل.
  • في مجلد Source يوجد كود شاشة التحميل والكود اللازم للانتظار حتى يتم تحميل بقية اللعبة. start LocalScript هو نقطة الدخول لجميع كود جانب العميل في المشروع.
ReplicatedStorage

يعمل كحاوية تخزين لجميع المثيلات التي يتطلب الوصول إليها على كل من العميل والخادم.

  • في مجلد Dependencies توجد بعض المكتبات الخارجية المستخدمة في المشروع.
  • في مجلد Instances توجد مجموعة واسعة من المثيلات الجاهزة.
  • في مجلد Source يوجد كل الكود غير المطلوب لعملية التحميل والذي يحتاج إلى أن يكون متاحًا من كل من العميل والخادم.
ServerScriptService

يحتوي على Script يعمل كنقطة دخول لجميع كود جانب الخادم في المشروع.

ServerStorage

يعمل كحاوية تخزين لجميع المثيلات التي لا تحتاج إلى تكرارها إلى العميل.

  • في مجلد Instances توجد نموذج Farm. يتم وضع نسخة من هذا في Workspace عندما ينضم اللاعب إلى اللعبة، حيث سيتم تكرارها لجميع اللاعبين.
  • في مجلد Source يوجد كل الكود الذي يقتصر على الخادم.
SoundService

يحتوي على كائنات Sound المستخدمة لتأثيرات الصوت في اللعبة. تحت SoundService، ليس لهذه الكائنات موضع ولا يتم محاكاتها في الفضاء ثلاثي الأبعاد.

نقاط الدخول

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

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

تصف القوائم التالية المساومات بين كلا النهجين:

  • تغطي Script واحدة وLocalScript واحدة كود الخادم والعميل على التوالي.
  • تحكم أكبر في ترتيب بدء الأنظمة المختلفة لأن كل الكود يتم تهيئته من خلال نص واحد.
  • يمكن تمرير الكائنات بالمرجع بين الأنظمة.

بنية الأنظمة على مستوى عالٍ

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

مخطط بنية أنظمة مشروع النباتات

كل من هذه الأنظمة هو "فريد"، بمعنى أنه فئة غير قابلة للتكرار يتم تهيئتها بدلاً من ذلك بواسطة نص start ذي الصلة للعميل أو الخادم. يمكنك قراءة المزيد عن نمط الفريد لاحقًا في هذا الدليل.

الخادم

الأنظمة التالية مرتبطة بالخادم.

النظامالوصف
الشبكة
  • ينشئ جميع مثيلات RemoteEvent وRemoteFunction.
  • يكشف عن طرق لإرسال والاستماع إلى الرسائل من العميل.
  • تحقق من نوع المعاملات المستلمة من العميل في وقت التشغيل.
خادم بيانات اللاعب
  • يحفظ ويحمّل بيانات اللاعب المستمرة باستخدام DataStoreService.
  • يخزن بيانات اللاعب في الذاكرة ويكرر التغييرات إلى العميل.
  • يكشف عن إشارات وطرق للاشتراك في، واستعلام، وتحديث بيانات اللاعب.
السوق
  • يتعامل مع معاملات العملة اللينة من العميل.
  • يكشف عن طريقة لبيع النباتات المحصودة.
مدير مجموعة التصادم
  • يخصص نماذج شخصيات اللاعبين إلى مجموعات التصادم.
  • يهيئ مجموعات التصادم بحيث لا يمكن لشخصيات اللاعبين الاصطدام بعربات النباتات.
مدير المزرعة الخادم
  • يعيد إنشاء نموذج مزرعة اللاعب من بيانات اللاعب عند انضمامه إلى اللعبة.
  • يزيل نموذج المزرعة عندما يغادر اللاعب.
  • يحدث بيانات اللاعب عندما تتغير مزرعة اللاعب.
  • يكشف عن طريقة للوصول إلى فئة Farm المرتبطة بلاعب معين.
حاوية كائنات اللاعب
  • ينشئ كائنات مختلفة مرتبطة بعمر اللاعب ويوفر طريقة لاسترجاع هذه الكائنات.
توسيم اللاعبين
  • يضيف علامات CollectionService إلى جميع كائنات اللاعب والشخصية.
مدير FTUE الخادم
  • خلال FTUE، ينفذ كل مرحلة وينتظر حتى تكتمل.
مُعيد الشخصيات
  • يعيد إحياء الشخصيات عندما تموت. لاحظ أن Players.CharacterAutoLoads تم تعطيله بحيث يتم إيقاف الإحياء حتى يتم تحميل بيانات اللاعب.

العميل

الأنظمة التالية مرتبطة بالعميل.

النظامالوصف
الشبكة
  • ينتظر حتى يقوم الخادم بإنشاء جميع مثيلات RemoteEvent وRemoteFunction.
  • يكشف عن طرق لإرسال والاستماع إلى الرسائل من وإلى الخادم.
  • يفرض تحقق من نوع المعاملات في وقت التشغيل.
  • ينفذ pcall() على الوظائف البعيدة.
خادم بيانات اللاعب
  • يخزن بيانات اللاعب المحلي في الذاكرة.
  • يكشف عن طرق وإشارات لاستعلام والتسجيل في التغييرات في بيانات اللاعب.
سوق العميل
  • يكشف عن طريقة لطلب من الخادم شراء عنصر مقابل عملة لينة.
مدير المشي والقفز المحلي
  • يكشف عن طرق لتعديل WalkSpeed أو JumpHeight لشخصية عبر مضاعفات لتجنب التعارض عند تعديل هذه القيم من عدة أماكن.
مدير المزرعة العميل
  • يستمع لتطبيق علامات CollectionService معينة على المثيلات وينشئ "مكونات" تضيف سلوكًا لهذه المثيلات. تشير "المكون" إلى فئة يتم إنشاؤها عندما تتم إضافة علامة CollectionService إلى مثيل ويتم تدميرها عند إزالتها؛ تُستخدم هذه لتوجيهات CTA في المزرعة وفئات مختلفة تشير إلى حالة المزرعة للاعب.
إعداد واجهة المستخدم
  • يهيئ جميع طبقات واجهة المستخدم.
  • يهيئ بعض الطبقات لتكون مرئية فقط في أقسام مادية من العالم.
  • يربط تأثير كاميرا خاص عندما يتم تمكين القوائم.
مدير FTUE العميل
  • يهيئ مراحل FTUE على العميل.
ركض الشخصية
  • يستخدم مدير المشي والقفز المحلي لزيادة WalkSpeed عندما تكون شخصية اللاعب خارج مزرعته.

التواصل بين العميل والخادم

تتضمن معظم ألعاب Roblox عنصرًا من التواصل بين العميل والخادم. يمكن أن يشمل ذلك طلب العميل من الخادم تنفيذ إجراء معين وتكرار الخادم للتحديثات إلى العميل.

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

التكرار عبر نظام بيانات اللاعب

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

على سبيل المثال، بدلاً من إطلاق UpdateCoins RemoteEvent مخصص لإخبار العميل بعدد العملات التي يمتلكها، يمكنك استدعاء ما يلي وترك العميل يشترك فيه عبر حدث PlayerDataClient.updated.

PlayerDataServer.setValue(player, "coins", 5)

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

  • المرحلة الحالية من FTUE
  • جرد اللاعب
  • كمية العملات التي يمتلكها اللاعب
  • حالة مزرعة اللاعب

التكرار عبر السمات

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

هذا مفيد بشكل خاص للمثيلات التي تم إنشاؤها في وقت التشغيل، حيث يتم تعيين السمات على مثيل جديد قبل أن يتم توصيله بنموذج البيانات ستتكرر بشكل ذري مع المثيل نفسه. هذا يتجاوز أي حاجة لكتابة كود لـ "الانتظار" حتى يتم تكرار بيانات إضافية عبر RemoteEvent أو StringValue.

يمكنك أيضًا قراءة السمات مباشرة من نموذج البيانات، سواء من العميل أو الخادم، باستخدام طريقة GetAttribute()، والاشتراك في التغييرات باستخدام طريقة GetAttributeChangedSignal(). في مشروع Plant، يتم استخدام هذا النهج، من بين أشياء أخرى، لتكرار الحالة الحالية للنباتات إلى العملاء.

التكرار عبر العلامات

تتيح لك CollectionService تطبيق علامة نصية على Instance. هذا مفيد لتصنيف المثيلات وتكرار هذا التصنيف إلى العميل.

على سبيل المثال، يتم تطبيق علامة CanPlant على الخادم للإشارة إلى العميل بأن وعاء معين قادر على استلام نبات.

الرسائل مباشرة عبر وحدة الشبكة

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

تستخدم Plant مكالمات الشبكة المباشرة لمجموعة متنوعة من طلبات العميل، بما في ذلك:

  • سقي نبات
  • زراعة بذور
  • شراء عنصر

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

الفئات والفريد

يمكن إنشاء الفئات في مشروع Plant وتدميرها، مثل المثيلات على Roblox. تستلهم صياغة فئتها من النهج اللغوي الشائع في برمجة الكائنات مع عدد من التغييرات لتمكين دعم التحقق من النوع الصارم.

التهيئة

ترتبط العديد من الفئات في المشروع بواحدة أو أكثر من Instances. يتم إنشاء كائنات من فئة معينة باستخدام طريقة new(), متسقة مع كيفية إنشاء المثيلات في Roblox باستخدام Instance.new().

يتم استخدام هذا النمط بشكل عام للكائنات حيث يكون للفئة تمثيل مادي في نموذج البيانات، وتقوم الفئة بتوسيع وظيفتها. مثال جيد هو BeamBetween الذي ينشئ كائن Beam بين كائنين Attachment محددين ويحافظ على توجيه تلك التوصيلات بحيث يكون الشعاع دائمًا موجهًا لأعلى. يمكن استنساخ هذه المثيلات من نسخة جاهزة في ReplicatedStorage أو تمريرها إلى new() كوسيلة وتخزينها داخل الكائن تحت self.

المثيلات المقابلة

كما هو مذكور أعلاه، فإن العديد من الفئات في هذا المشروع لها تمثيل في نموذج البيانات، وهو مثيل يتوافق مع الفئة ويتم التلاعب به.

بدلاً من إنشاء هذه المثيلات عند تهيئة كائن الفئة، يفضل الكود عمومًا Clone() نسخة جاهزة من Instance المخزنة تحت ReplicatedStorage أو ServerStorage. على الرغم من أنه سيكون من الممكن تسلسل خصائص هذه المثيلات وإنشائها من الصفر في وظائف new() الخاصة بالفئة، فإن القيام بذلك سيجعل تحرير الكائنات أمرًا مرهقًا للغاية ويجعل من الصعب على القارئ فهمها. بالإضافة إلى ذلك، فإن استنساخ مثيل هو عمومًا عملية أسرع من إنشاء مثيل جديد وتخصيص خصائصه في وقت التشغيل.

التركيب

على الرغم من أن الوراثة ممكنة في Luau باستخدام الجداول الميتة، يفضل المشروع بدلاً من ذلك السماح للفئات بتمديد بعضها البعض من خلال التركيب. عند دمج الفئات من خلال التركيب، يتم تهيئة الكائن "الطفل" في طريقة new() للفئة ويُدرج كعضو تحت self.

لرؤية مثال على ذلك، انظر إلى فئة CloseButton التي تغلف فئة Button.

التنظيف

على غرار كيفية تدمير Instance باستخدام طريقة Destroy(), يمكن أيضًا تدمير الفئات التي يمكن تهيئتها. طريقة المُدمّر للفئات في المشروع هي destroy() مع حرف صغير d للحفاظ على اتساق camelCase عبر طرق قاعدة الكود، وكذلك لتمييز بين فئات المشروع ومثيلات Roblox.

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

الفريد

الفريد، كما يوحي الاسم، هو فئات لا يمكن أن يوجد منها سوى كائن واحد. إنها تعادل المشروع لمصادر Roblox Services. بدلاً من تخزين مرجع إلى كائن الفريد وتمريره في كود Luau، يستفيد Plant من حقيقة أن استدعاء ModuleScript يخزن قيمته المعادة. وهذا يعني أن استدعاء نفس ModuleScript الفريد من أماكن مختلفة يوفر باستمرار نفس الكائن المعاد.

الاستثناء الوحيد لهذه القاعدة سيكون إذا كانت بيئات مختلفة (عميل أو خادم) قد وصلت إلى ModuleScript.

تتميز الفريد عن الفئات القابلة للتكرار من خلال عدم وجود طريقة new(). بدلاً من ذلك، يتم إرجاع الكائن مع طرقه وحالته مباشرة عبر ModuleScript. نظرًا لأن الفريد لا يتم تهيئته، فإن صياغة self لا تُستخدم وتُستدعى الطرق بدلاً من ذلك باستخدام نقطة (.) بدلاً من نقطتين (:).

التحقق من النوع الصارم

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

صياغة الفئة المميزة

النهج المعتمد لإنشاء الفئات في Lua موثق جيدًا، ومع ذلك فهو ليس مناسبًا جيدًا للكتابة القوية في Luau. في Luau، فإن أبسط نهج للحصول على نوع فئة هو طريقة typeof():

type ClassType = typeof(Class.new())

هذا يعمل ولكنه ليس مفيدًا جدًا عندما يتم تهيئة فئتك بقيم لا توجد إلا في وقت التشغيل، على سبيل المثال كائنات Player. بالإضافة إلى ذلك، فإن الافتراض الذي تم القيام به في صياغة فئة Lua الشائعة هو أن إعلان طريقة على فئة self سيكون دائمًا مثيلًا لتلك الفئة؛ هذا ليس افتراضًا يمكن لمحرك التحقق من النوع القيام به.

لدعم التحقق من النوع الصارم، يستخدم مشروع Plant حلاً يختلف عن صياغة فئة Lua الشائعة بعدة طرق، قد يشعر بعضها بعدم البديهية:

  • يتم تكرار تعريف self، سواء في إعلان النوع وفي المُنشئ. هذا يقدم عبئًا على الصيانة، ولكن سيتم الإشارة إلى التحذيرات إذا خرجت التعريفات عن التزامن مع بعضها البعض.
  • يتم إعلان طرق الفئة بنقطة، بحيث يمكن إعلان self بشكل صريح ليكون من نوع ClassType. لا تزال الطرق تُستدعى باستخدام نقطتين كما هو متوقع.
--!strict
local MyClass = {}
MyClass.__index = MyClass
export type ClassType = typeof(setmetatable(
{} :: {
property: number,
},
MyClass
))
function MyClass.new(property: number): ClassType
local self = {
property = property,
}
setmetatable(self, MyClass)
return self
end
function MyClass.addOne(self: ClassType)
self.property += 1
end
return MyClass

تحويل الأنواع بعد حراس المنطق

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

--!strict
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
print(optionalParameter + 1)
end

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

--!strict
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
local parameter = optionalParameter :: number
print(parameter + 1)
end

التنقل في تسلسلات نموذج البيانات

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

أحد النهج لهذه التحديات هو التحويل إلى any ثم التكرير. على سبيل المثال:

local function enableVendor(vendor: Model)
local zonePart: BasePart = (vendor :: any).ZonePart
end

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

local function enableVendor(vendor: Model)
local zonePart: BasePart = getInstance(vendor, "ZonePart")
end

مع تطور فهم محرك النوع لنموذج البيانات، من الممكن أن تصبح أنماط مثل هذه غير ضرورية.

واجهة المستخدم

يتضمن Plant مجموعة متنوعة من واجهات المستخدم ثنائية الأبعاد المعقدة والبسيطة. تشمل هذه العناصر غير التفاعلية مثل عداد العملات وقوائم تفاعلية معقدة مثل المتجر.

نهج واجهة المستخدم

يمكنك مقارنة واجهة مستخدم Roblox UI بشكل فضفاض بـ DOM في HTML، لأنها تسلسل هرمي من الكائنات التي تصف ما يجب أن يراه المستخدم. يتم تقسيم النهج لإنشاء وتحديث واجهة مستخدم Roblox بشكل عام إلى ممارسات إلزامية وإعلانية.

النهجالمزايا والعيوب
إلزامي

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

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

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

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

إعلاني

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

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

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

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

البنية المعمارية على مستوى عالٍ

مخطط بنية واجهة مشروع النباتات

الطبقة والمكونات

في Plant، جميع هياكل واجهة المستخدم إما Layer أو Component.

  • Layer يتم تعريفها كحاوية تجميعية على مستوى عالٍ تغلف هياكل واجهة المستخدم الجاهزة في ReplicatedStorage. قد تحتوي الطبقة على عدد من المكونات، أو قد تحتوي على منطقها الخاص بالكامل. من أمثلة الطبقات قائمة الجرد أو مؤشر عدد العملات في واجهة العرض.
  • Component هو عنصر واجهة مستخدم قابل لإعادة الاستخدام. عند تهيئة كائن مكون جديد، يقوم باستنساخ قالب جاهز من ReplicatedStorage. قد تحتوي المكونات في حد ذاتها على مكونات أخرى. من أمثلة المكونات فئة زر عامة أو مفهوم قائمة العناصر.

إدارة العرض

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

تتعامل Plant مع هذه المشكلة من خلال نظام UIHandler الذي يدير متى يجب أن تكون طبقة واجهة المستخدم مرئية أو غير مرئية. يتم تصنيف جميع طبقات واجهة المستخدم في اللعبة على أنها HUD أو Menu ويتم إدارة رؤيتها وفقًا للقواعد التالية:

  • يمكن تبديل حالة تمكين طبقات Menu وHUD.
  • يتم عرض طبقات HUD الممكّنة فقط إذا لم تكن أي طبقات Menu مفعلة.
  • يتم تخزين طبقات Menu الممكّنة في مكدس، ولا تكون طبقة Menu واحدة مرئية في وقت واحد. عندما يتم تمكين طبقة Menu، يتم إدراجها في مقدمة المكدس وتظهر. عندما يتم تعطيل طبقة Menu، تتم إزالتها من المكدس وتظهر الطبقة الممكّنة التالية في الطابور.

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

تسجل وحدات واجهة المستخدم الفريدة نفسها مع UIHandler ويتم تزويدها بإشارة تطلق عندما يجب أن تتغير رؤيتها.

القراءة الإضافية

من هذه النظرة الشاملة على مشروع Plant، قد ترغب في استكشاف الأدلة التالية التي تتعمق أكثر في المفاهيم والمواضيع ذات الصلة.

©2026 شركة Roblox Corporation. تُعد منصّة Roblox، وشعار Roblox وشعار "توسيع حدود المخيلة"، من ضمن علاماتنا التجارية المسجّلة وغير المسجّلة في الولايات المتحدة وبلدان أخرى.