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

تركز المشروع على حالات الاستخدام الشائعة التي قد تواجهها عند تطوير تجربة على Roblox. حيثما كان ذلك مناسباً، ستجد ملاحظات حول المفاضلات، والتسويات، والأسس المنطقية لخيارات التنفيذ المختلفة، حتى تتمكن من اتخاذ أفضل قرار لتجاربك الخاصة.
احصل على الملف
- انتقل إلى صفحة تجربة Plant.
- انقر على زر … ثم تحرير في الاستوديو.
حالات الاستخدام
Plant تغطي حالات الاستخدام التالية:
- بيانات الجلسة واستمرارية بيانات اللاعب
- إدارة واجهة المستخدم
- الشبكات بين العميل والخادم
- تجربة المستخدم الجديدة (FTUE)
- عمليات شراء العملة الصلبة واللينة
بالإضافة إلى ذلك، يحل هذا المشروع مجموعة من المشاكل الضيقة التي تنطبق على العديد من التجارب، بما في ذلك:
- تخصيص منطقة في المكان مرتبطة باللاعب
- إدارة سرعة حركة شخصية اللاعب
- إنشاء كائن يتبع الشخصيات
- اكتشاف أي جزء من العالم تتواجد فيه الشخصية
لاحظ أنه هناك عدة حالات استخدام في هذه التجربة تعتبر صغيرة جداً، نادرة، أو لا تُظهر حلاً لتحدٍ تصميمي مثير للاهتمام؛ هذه الحالات ليست مغطاة.
هيكل المشروع
القرار الأول عند إنشاء تجربة هو تحديد كيفية هيكلة المشروع، والذي يتضمن أساساً مكان وضع مثيلات محددة في نموذج البيانات وكيفية تنظيم وهيكلة نقاط الدخول لكل من كود العميل والخادم.
نموذج البيانات
تصف الجدول التالي خدمات الحاويات التي يتم وضع المثيلات فيها في نموذج البيانات.
| الخدمة | أنواع المثيلات |
|---|---|
| Workspace | يحتوي على نماذج ثابتة تمثل العالم 3D، وبالتحديد أجزاء من العالم التي لا تخص أي لاعب. لا تحتاج إلى إنشاء أو تعديل أو تدمير هذه المثيلات بشكل ديناميكي في وقت التشغيل، لذا فمن المقبول تركها هنا. يوجد أيضًا Folder فارغ، حيث ستتم إضافة نماذج مزارع اللاعبين فيه أثناء وقت التشغيل. |
| Lighting | التأثيرات الجوية وإضاءة. |
| ReplicatedFirst | يحتوي على أصغر مجموعة ممكنة من المثيلات اللازمة لعرض شاشة التحميل وتهيئة التجربة. كلما زادت المثيلات الموجودة في ReplicatedFirst، زادت مدة الانتظار لتكرارها قبل أن تتمكن التعليمات البرمجية في ReplicatedFirst من العمل.
|
| ReplicatedStorage | يعمل كحاوية تخزين لجميع المثيلات التي تحتاج إلى الوصول لها على كل من العميل والخادم.
|
| ServerScriptService | يحتوي على Script يعمل كنقطة دخول لكل كود الخادم في المشروع. |
| ServerStorage | يعمل كحاوية تخزين لكل المثيلات التي لا تحتاج إلى أن يتم تكرارها للعميل.
|
| SoundService | يحتوي على كائنات Sound المستخدمة لتأثيرات الصوت في التجربة. تحت SoundService، ليس لهذه الكائنات موضع ولا يتم محاكاتها في الفضاء ثلاثي الأبعاد. |
نقاط الدخول
تنظم معظم المشاريع الشيفرة داخل ModuleScripts قابلة لإعادة الاستخدام والتي يمكن استيرادها عبر قاعدة الشيفرة بالكامل. ModuleScripts قابلة لإعادة الاستخدام ولكنها لا تنفذ بمفردها؛ تحتاج إلى أن يتم استيرادها بواسطة Script أو LocalScript. عادةً ما تحتوي العديد من مشاريع Roblox على عدد كبير من كائنات Script و LocalScript، كل منها يتعلق بسلوك أو نظام معين في التجربة، مما يخلق عدة نقاط دخول.
في Plant الميكروجويم، يتم تنفيذ نهج مختلف من خلال LocalScript واحد يعمل كنقطة دخول لجميع كود العميل، و Script واحد يعمل كنقطة دخول لجميع كود الخادم. يعتمد النهج الصحيح لمشروعك على متطلباتك، ولكن نقطة دخول واحدة توفر تحكمًا أكبر في ترتيب تنفيذ الأنظمة.
تصف القوائم التالية إما المفاضلات لكل من النهجين:
- تغطي Script واحدة وLocalScript واحدة كود الخادم والعميل على التوالي.
- تحكم أكبر في ترتيب بدء الأنظمة المختلفة لأن كل الشيفرة يتم تهيئتها من خلال نص واحد.
- يمكن تمرير الكائنات بالإشارة بين الأنظمة.
هندسة الأنظمة عالية المستوى
الأنظمة الرئيسية في المشروع مفصلة أدناه. بعض هذه الأنظمة أكثر تعقيداً من غيرها، وفي العديد من الحالات يتم تجريد وظائفها عبر تسلسل هرمي من الفئات الأخرى.

كل من هذه الأنظمة هو "حيد"، بمعنى أنه فئة غير قابلة للتكرار يتم تهيئتها بدلاً من ذلك بواسطة نص start الخاص بالعميل أو الخادم. يمكنك قراءة المزيد عن نمط الحيد لاحقًا في هذا الدليل.
الخادم
الأنظمة التالية مرتبطة بالخادم.
| النظام | الوصف |
|---|---|
| Network |
|
| PlayerDataServer |
|
| Market |
|
| CollisionGroupManager |
|
| FarmManagerServer |
|
| PlayerObjectsContainer |
|
| TagPlayers |
|
| FtueManagerServer |
|
| CharacterSpawner |
|
العميل
الأنظمة التالية مرتبطة بالعميل.
| النظام | الوصف |
|---|---|
| Network |
|
| PlayerDataClient |
|
| MarketClient |
|
| LocalWalkJumpManager |
|
| FarmManagerClient |
|
| UISetup |
|
| FtueManagerClient |
|
| CharacterSprint |
|
التواصل بين العميل والخادم
تشمل معظم تجارب Roblox بعض عناصر التواصل بين العميل والخادم. يمكن أن يشمل ذلك طلب العميل من الخادم تنفيذ إجراء معين وتكرار التحديثات إلى العميل.
في هذا المشروع، يتم الحفاظ على التواصل بين العميل والخادم بشكل عام من خلال تقليل استخدام كائنات RemoteEvent و RemoteFunction من أجل تقليل عدد القواعد الخاصة التي يجب تتبعها. يستخدم هذا المشروع الطرق التالية، حسب الأفضلية:
- التكرار عبر نظام بيانات اللاعب.
- التكرار عبر السمات.
- التكرار عبر العلامات.
- الرسائل مباشرة عبر وحدة Network.
التكرار عبر نظام بيانات اللاعب
يتيح نظام بيانات اللاعب ربط بيانات باللاعب الذي تستمر بين جلسات الحفظ. يوفر هذا النظام تكرارًا من العميل إلى الخادم ومجموعة من واجهات برمجة التطبيقات التي يمكن استخدامها لاستعلام البيانات والاشتراك في التغييرات، مما يجعله مثاليًا لتكرار التغييرات في حالة اللاعب من الخادم إلى العميل.
على سبيل المثال، بدلاً من إطلاق UpdateCoins RemoteEvent مخصص لإخبار العميل بعدد العملات الموجودة لديه، يمكنك استدعاء ما يلي وترك العميل يشترك فيه عبر حدث PlayerDataClient.updated.
PlayerDataServer.setValue(player, "coins", 5)
بالطبع، هذا يكون مفيداً فقط لتكرار الخادم إلى العميل وللقيم التي تريد أن تستمر بين الجلسات، ولكن هذا ينطبق على عدد مفاجئ من الحالات في المشروع، بما في ذلك:
- المرحلة الحالية من FTUE
- مخزون اللاعب
- كمية العملات التي يملكها اللاعب
- حالة مزرعة اللاعب
التكرار عبر السمات
في الحالات التي يحتاج فيها الخادم إلى تكرار قيمة مخصصة إلى العميل تتعلق بمثيل Instance معين، يمكنك استخدام السمات. يقوم Roblox بتكرار قيم السمات تلقائيًا، لذا لا تحتاج إلى الحفاظ على أي مسارات شيفرة لتكرار الحالة المرتبطة بكائن ما. ميزة أخرى هي أن هذا التكرار يحدث جنبا إلى جنب مع المثيل نفسه.
هذا مفيد بشكل خاص للمثيلات التي يتم إنشاؤها في وقت التشغيل، حيث ستتكرر السمات التي تم تعيينها على مثيل جديد قبل أن يتم إدخاله في نموذج البيانات بشكل ذري مع المثيل نفسه. وهذا يتجنب الحاجة إلى كتابة شيفرة لـ "انتظار" تكرار بيانات إضافية عبر RemoteEvent أو StringValue.
يمكنك أيضًا قراءة السمات مباشرة من نموذج البيانات، سواء من العميل أو الخادم، باستخدام GetAttribute() ، والاشتراك في التغييرات باستخدام GetAttributeChangedSignal() . يتم استخدام هذا النهج في مشروع Plant من بين أمور أخرى، لتكرار الحالة الحالية للنباتات إلى العملاء.
التكرار عبر العلامات
تسمح لك CollectionService بتطبيق علامة نصية على Instance. يكون هذا مفيدًا لتصنيف المثيلات وتكرار هذا التصنيف إلى العميل.
على سبيل المثال، يتم تطبيق علامة CanPlant على الخادم للإشارة إلى العميل بأن وعاءًا معينًا قادرًا على استلام نبات.
الرسائل مباشرة عبر وحدة الشبكة
في الحالات التي لا تنطبق فيها الخيارات السابقة، يمكنك استخدام استدعاءات شبكة مخصصة عبر وحدة Network. هذه هي الخيار الوحيد في المشروع الذي يسمح بالتواصل من العميل إلى الخادم، وبالتالي فهو الأكثر فائدة لنقل طلبات العميل واستلام رد الخادم.
يستخدم Plant استدعاءات الشبكة المباشرة لمجموعة متنوعة من طلبات العميل، بما في ذلك:
- سقي نبات
- زراعة بذور
- شراء عنصر
العيب في هذا النهج هو أن كل رسالة فردية تتطلب بعض التهيئة المخصصة مما قد يزيد من تعقيد المشروع، على الرغم من أنه تم تجنبه كلما أمكن ذلك، خصوصًا للتواصل من الخادم إلى العميل.
الفئات والحيدات
يمكن إنشاء الفئات في مشروع Plant وتدميرها مثل المثيلات على Roblox. يعتمد بناء الجملة للفئة على نهج Lua التقليدي في البرمجة الكائنية مع عدد من التغييرات لدعم تحقق الأنواع المفصل.
إنشاء المثيلات
ترتبط العديد من الفئات في المشروع بواحد أو أكثر من Instances. يتم إنشاء كائنات من فئة معينة باستخدام new() طريقة، متماشية مع كيفية إنشاء المثيلات في Roblox باستخدام Instance.new().
عادةً ما يُستخدم هذا النمط للأشياء التي تملك الفئة تمثيلاً ماديًا في نموذج البيانات، وتقوم الفئة بتوسيع وظيفتها. مثال جيد هو BeamBetween الذي ينشئ كائن Beam بين اثنين من كائنات Attachment المعطاة ويحتفظ بهذين التعلقين موجهين بحيث تكون الشعاع دائماً موجهًا لأعلى. يمكن نسخ هذه المثيلات من إصدار مُعد مسبقاً في ReplicatedStorage أو تمريرها إلى new() كمعامل وتخزينها داخل الكائن تحت self.
المثيلات المقابلة
كما هو موضح أعلاه، تحتوي العديد من الفئات في هذا المشروع على تمثيل نموذج البيانات، وهو مثيل يتوافق مع الفئة ويتم التلاعب به.
بدلاً من إنشاء هذه المثيلات عند تهيئة كائن الفئة، تختار الشيفرة عمومًا Clone() نسخة مُعدة مسبقًا من Instance المخزنة تحت ReplicatedStorage أو ServerStorage. على الرغم من أنه سيكون من الممكن تسلسل خصائص هذه المثيلات وإنشائها من الصفر في وظائف new() للفئة، إلا أن القيام بذلك سيجعل تحرير الكائنات أمراً مرهقاً جداً ويجعلها أصعب على القارئ لفهمها. بالإضافة إلى ذلك، يكون نسخ المثيل عمومًا عملية أسرع من إنشاء مثيل جديد وتخصيص خصائصه في وقت التشغيل.
التركيب
على الرغم من أنه من الممكن وجود وراثة في Luau باستخدام المتغيرات، يختار المشروع بدلاً من ذلك السماح للفئات بتوسيع بعضها البعض عبر التركيب. عند دمج الفئات عبر التركيب، يتم تهيئة "كائن الطفل" في new() طريقة الفئة ويكون مدرجًا كعضو تحت self.
لرؤية مثال على هذا في العمل، انظر إلى فئة CloseButton التي تغلف فئة Button.
التنظيف
مماثل لكيفية يمكن تدمير مثيل باستخدام Destroy() طريقة، يمكن أيضاً تدمير الفئات القابلة للتكرار. أن تكون طريقة المدمرة لفئات المشروع هي destroy() باستخدام حرف صغير d من أجل الحفاظ على تناسق camelCase عبر أساليب قاعدة الشيفرة، وكذلك لتمييز بين فئات المشروع ومثيلات Roblox.
دور الطريقة destroy() هو تدمير أي مثيلات تم إنشاؤها بواسطة الكائن، وفصل أي اتصالات، واستدعاء destroy() على أي كائنات فرعية. هذا مهم بشكل خاص للاتصالات لأن المثيلات ذات الاتصالات النشطة لا يتم تنظيفها بواسطة جامع القمامة Luau، حتى لو لم تبقَ أي مراجع للمثيل أو اتصالات بالمثيل.
الحيدات
الحيدات، كما يوحي الاسم، هي فئات لا يمكن أن توجد كائنات متعددة منها. إنها تعادل المشروع خدمات Roblox. بدلاً من تخزين مرجع للكائن الحيد ونقله في شيفرة Luau، يستفيد Plant من حقيقة أن استخدام ModuleScript يخزن قيمة ردها. هذا يعني أن استخدام نفس ModuleScript الحيد من أماكن مختلفة يقدم دائمًا نفس الكائن المعاد.
الاستثناء الوحيد لهذه القاعدة سيكون إذا دخلت بيئات مختلفة (عميل أو خادم) إلى ModuleScript.
تتميز الحيدات عن الفئات القابلة للتكرار بقلة وجود طريقة new(). بل يتم إرجاع الكائن مع أساليبه والدولة مباشرة عبر ModuleScript. بما أن الحيدات ليست مُهيأة، فإن بناء جملة self لا يستخدم وتُستدعى الأساليب بدلاً من ذلك باستخدام نقطة (.) بدلاً من نقطتين (:).
تحقق الأنواع الصارمة
يدعم Luau الكتابة التدريجية، مما يعني أنك حر في إضافة تعريفات نوع اختيارية إلى بعض أو كل الشيفرة الخاصة بك. في هذا المشروع، يتم استخدام تحقق الأنواع strict لكل نص برمجي. هذه هي الخيار الأقل تسامحًا بالنسبة لأداة تحليل الشيفرة الخاصة بـ Roblox وبالتالي من المرجح أن تكشف عن أخطاء الأنواع قبل وقت التشغيل.
بناء جملة الفئة المعينة
النهج المحدد لإنشاء الفئات في Lua موثق بشكل جيد، ومع ذلك، لا يتناسب بشكل جيد مع كتابة Luau القوية. في Luau، فإن أبسط نهج للحصول على نوع الفئة هو الطريقة typeof():
type ClassType = typeof(Class.new())
يعمل هذا لكن ليس مفيدًا جدًا عندما يتم تهيئة فئتك بقيم لا توجد إلا في وقت التشغيل، على سبيل المثال، كائنات Player. بالإضافة إلى ذلك، فإن الافتراض الذي تم القيام به في بناء جملة الفئات idiomatic Lua هو أن تعريف طريقة على self سيكون دائماً مثيلاً لهذه الفئة؛ هذا ليس افتراضًا يمكن لمحرك استدلال الأنواع القيام به.
من أجل دعم تحقق الأنواع الصارمة، يستخدم مشروع Plant حلاً يختلف عن بناء جملة الفئات idiomatic 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 مجموعة متنوعة من واجهات المستخدم المعقدة والبسيطة ثنائية الأبعاد. تشمل هذه عناصر عرض رأسية غير تفاعلية (HUD) مثل عداد العملات وقوائم تفاعلية معقدة مثل المتجر.
نهج واجهة المستخدم
يمكنك المقارنة بين واجهة مستخدم Roblox UI وهي تشبه تطوير HTML DOM، لأنه أيضًا تسلسل هرمي من الكائنات التي تصف ما يجب أن يراه المستخدم. يتم تقسيم النهج لإنشاء وتحديث واجهة مستخدم Roblox بشكل عام إلى ممارسات إلزامية و إعلانية.
| النهج | المزايا والعيوب |
|---|---|
| إلزامية | في النهج الإلزامي، يتم التعامل مع واجهة المستخدم كأي تسلسل هرمي آخر على Roblox. يتم إنشاء هيكل واجهة المستخدم قبل وقت التشغيل في الاستوديو ويضاف إلى نموذج البيانات، عادةً مباشرة في StarterGui. ثم، في وقت التشغيل، تقوم الشيفرة بتعديل أجزاء معينة من واجهة المستخدم لتعكس الحالة المطلوبة من قبل المنشئ. يأتي هذا النهج مع بعض المزايا. يمكنك إنشاء واجهة المستخدم من الصفر في الاستوديو وتخزينها في نموذج البيانات. هذه تجربة تحرير بسيطة ومرئية يمكن أن تسرع من إنشاء واجهة المستخدم. لأن كود واجهة المستخدم الإلزامي يتعلق فقط بما يحتاج إلى التغيير، فهو يجعل التغيرات البسيطة في واجهة المستخدم سهلة التطبيق. عيب بارز هو أنه، نظرًا لأن نهج واجهة المستخدم الإلزامية يتطلب تنفيذ الحالة يدويًا في شكل تحويلات، فإن التمثيلات المعقدة للحالة يمكن أن تصبح صعبة جدًا للعثور عليها وتصحيحها. من الشائع أن تظهر أخطاء عند تطوير كود واجهة المستخدم الإلزامية، خاصةً عندما تصبح الحالة وواجهة المستخدم غير متزامنة بسبب التفاعلات المتعددة التي تحدث بترتيب غير متوقع. تحدٍ آخر مع النهج الإلزامي هو أنه من الأصعب تقسيم واجهة المستخدم إلى مكونات ذات معنى يمكن إعلانها مرة واحدة وإعادة استخدامها. نظرًا لأن شجرة واجهة المستخدم بالكامل تُعلن في وقت التحرير، يمكن أن تتكرر الأنماط المشتركة في عدة أجزاء من نموذج البيانات. |
| إعلانية | في النهج الإعلاني، يتم إعلان الحالة المطلوبة لمثيلات واجهة المستخدم بشكل صريح، ويتم تجريد التنفيذ الفعال لهذه الحالة عبر مكتبات مثل Roact أو Fusion. ميزة هذا النهج هي أن تنفيذ الحالة يصبح تافهًا ولا تحتاج إلا لوصف كيف تريد أن تبدو واجهة المستخدم الخاصة بك. يجعل هذا من السهل تحديد الأخطاء وحلها بشكل ملحوظ. العيب الرئيسي هو الحاجة إلى إعلان شجرة واجهة المستخدم بالكامل في الشيفرة. تحتوي مكتبات مثل Roact و Fusion على بناء جملة يجعل هذا أسهل، لكنها لا تزال عملية تستغرق وقتًا طويلاً وتجربة تحرير أقل بديهية عند تجميع واجهة المستخدم. |
يستخدم Plant نهجًا إلزاميًا تحت مفهوم أن عرض التحويلات مباشرة يوفر نظرة عامة أكثر فعالية عن كيفية إنشاء واجهة المستخدم والتلاعب بها على Roblox. لم يكن ذلك ممكنًا عبر نهج إعلاني. تم أيضًا تجريد بعض الهياكل والمنطق المتكررة في واجهة المستخدم إلى مكونات قابلة لإعادة الاستخدام لتجنب فخ شائع في تصميم واجهة المستخدم الإلزامي.
البنية العالية المستوى

الطبقة والمكونات
في Plant، فإن جميع هياكل واجهة المستخدم إما Layer أو Component .
- Layer تعرف كحاوية مجموعة علوية تعمل على إحاطة هياكل واجهة المستخدم المُعدة مسبقًا في ReplicatedStorage. قد تحتوي الطبقة على عدد من المكونات، أو قد تضم منطقها الخاص تمامًا. من أمثلة الطبقات قائمة الجرد أو عداد كمية العملات في واجهة العرض الرئيسية.
- Component عنصر واجهة مستخدم قابل لإعادة الاستخدام. عندما يتم تهيئة كائن مكون جديد، فإنه ينسخ نموذج مُعد مسبقًا من ReplicatedStorage. قد تحتوي المكونات في حد ذاتها على مكونات أخرى. من أمثلة المكونات فئة زر عامة أو مفهوم قائمة العناصر.
إدارة العرض
تعتبر مشكلة شائعة في إدارة واجهة المستخدم هي إدارة العرض. يحتوي هذا المشروع على مجموعة من القوائم وعناصر HUD، يقوم بعضها بالاستماع إلى إدخال المستخدم، ويتطلب إدارة دقيقة عند رؤيتها أو تفعيلها.
يتعامل Plant مع هذه المشكلة من خلال نظام UIHandler الخاص به الذي يدير متى يجب أن تكون طبقة واجهة المستخدم مرئية أو لا. يتم تصنيف جميع طبقات واجهة المستخدم في التجربة على أنها HUD أو Menu وإدارة رؤيتها تتم من خلال القواعد التالية:
- يمكن تبديل حالة التفعيل لـ Menu و HUD.
- يتم عرض طبقات HUD المفعلة فقط إذا لم تكن أي طبقة Menu مفعلة.
- يتم تخزين طبقات Menu المفعلة في كومة، ولا تكون إلا واحدة من طبقات Menu مرئية في نفس الوقت. عند تفعيل طبقة Menu، يتم إدراجها في مقدمة الكومة ويتم عرضها. عند تعطيل طبقة Menu، تتم إزالتها من الكومة وتظهر الطبقة المفعلة التالية في الطابور.
هذا النهج بديهي لأنه يتيح التنقل عبر القوائم مع التاريخ. إذا تم فتح قائمة واحدة من قائمة أخرى، فإن إغلاق القائمة الجديدة سيظهر القائمة القديمة مرة أخرى.
تسجل وحدات واجهة مستخدم الحيدات نفسها مع UIHandler ويتم تزويدها بإشارة تطلق عندما يجب أن تتغير رؤيتها.
مزيد من القراءة
من هذا العرض الشامل لمشروع Plant، قد ترغب في استكشاف الأدلة التالية التي تتعمق أكثر في المفاهيم والمواضيع ذات الصلة.
- نموذج العميل-الخادم — نظرة عامة على نموذج العميل-الخادم في Roblox.
- الأحداث البعيدة والردود — كل شيء عن الأحداث البعيدة لشبكة و الردود للتواصل عبر حدود العميل والخادم.
- واجهة المستخدم — تفاصيل حول كائنات واجهة المستخدم والتصميم في Roblox.