تصف هذه الصفحة مشاكل الأداء الشائعة وأفضل الممارسات للتخفيف منها.
الحساب النصي
تستغرق العمليات المكلفة في كود لواو وقتًا أطول للمعالجة وبالتالي يمكن أن تؤثر على معدل الإطارات. ما لم يتم تنفيذها بالتوازي، يعمل كود لواو بشكل متزامن ويعيق الخيط الرئيسي حتى يصادف وظيفة تقوم بتعليق الخيط.
المشاكل الشائعة
العمليات المكثفة على هياكل الجداول - تتسبب العمليات المعقدة مثل التسلسل، وفك التسلسل، والاستنساخ العميق في تكلفة أداء عالية، خاصةً على هياكل الجداول الكبيرة. وهذا صحيح بشكل خاص إذا كانت هذه العمليات متكررة أو تتضمن التكرار على هياكل بيانات كبيرة جدًا.
الأحداث عالية التكرار - ربط العمليات المكلفة بأحداث تعتمد على الإطار من RunService دون الحد من التكرار يعني أن هذه العمليات تتكرر في كل إطار، مما يؤدي غالبًا إلى زيادة غير ضرورية في وقت الحساب. تشمل هذه الأحداث:
التخفيف
- استدعِ الكود في أحداث RunService بحذر، محددًا الاستخدام للحالات التي يكون فيها الاستدعاء المتكرر أمرًا ضروريًا (على سبيل المثال، تحديث الكاميرا). يمكنك تنفيذ معظم الكود الآخر في أحداث أخرى أو بشكل أقل تكرارًا في حلقة.
- قسم المهام الكبيرة أو المكلفة باستخدام task.wait() لتوزيع العمل عبر عدة إطارات.
- حدد وحقق أفضلية العمليات المكلفة بشكل غير ضروري واستخدم التعددية للمهام الحسابية المكلفة التي لا تحتاج إلى الوصول إلى نموذج البيانات.
- يمكن أن تستفيد بعض البرامج النصية من جانب الخادم من توليد الكود الأصلي، وهو علامة بسيطة تقوم بترجمة البرنامج النصي إلى كود الآلة بدلاً من بايت كود.
نطاقات MicroProfiler
| النطاق | الحساب المرتبط |
| RunService.PreRender | الكود الذي يتم تنفيذه في حدث PreRender |
| RunService.PreSimulation | الكود الذي يتم تنفيذه في حدث Stepped |
| RunService.PostSimulation | الكود الذي يتم تنفيذه في حدث Heartbeat |
| RunService.Heartbeat | الكود الذي يتم تنفيذه في حدث Heartbeat |
للحصول على مزيد من المعلومات حول تصحيح الأخطاء في البرامج النصية باستخدام MicroProfiler، راجع مكتبة debug، التي تتضمن وظائف لتوسيم كود معين وزيادة التخصيص، مثل debug.profilebegin و debug.profileend. العديد من طرق API في Roblox التي تستدعيها البرامج النصية لديها أيضًا علامات MicroProfiler مرتبطة بها والتي يمكن أن تقدم إشارة مفيدة.
استخدام الذاكرة في السكربتات
يمكن أن تحدث تسريبات في الذاكرة عندما تكتب برامج نصية تستهلك الذاكرة التي لا يمكن لجمع القمامة تحريرها بشكل صحيح عند عدم استخدامها بعد الآن. تعتبر التسريبات مشكلة كبيرة على الخادم، لأنها يمكن أن تبقى متصلة لفترة تصل إلى عدة أيام، في حين أن جلسة العميل أقصر بكثير.
يمكن أن تشير قيم الذاكرة التالية في وحدة التحكم للمطورين إلى مشكلة تحتاج إلى مزيد من التحقيق:
- LuaHeap - يشير الاستهلاك العالي أو المتزايد إلى تسريب في الذاكرة.
- InstanceCount - الأعداد المتزايدة باستمرار من الحالات تشير إلى أن المراجع لبعض الحالات في التعليمات البرمجية الخاصة بك لا تتم جمعها بواسطة نظام جمع القمامة.
- PlaceScriptMemory - يوفر تفصيلًا لاستخدام الذاكرة لكل سكربت.
المشكلات الشائعة
ترك الاتصالات متصلة - لا يجمع المحرك أحداث الاتصال المرتبطة بعنصر و أي قيم تشير إلى داخل رد الاتصال المتصل. لذلك، تظل الاتصالات النشطة للأحداث والكود داخل العناصر المتصلة، والوظائف المتصلة، والقيم المشار إليها، خارج نطاق جامع القمامة للذاكرة، حتى بعد إطلاق الأحداث.
على الرغم من فصل الأحداث عندما يتم تدمير العنصر الذي تنتمي إليه، إلا أن خطأ شائع هو الافتراض بأن هذا ينطبق على كائنات Player. بعد أن يغادر المستخدم لعبة، لا يقوم المحرك تلقائيًا بتدمير نموذج Player التمثيلي الخاص بهم وطراز الشخصية، لذا تظل الاتصالات بكائن Player والعناصر الموجودة تحت نموذج الشخصية، مثل CharacterAdded، تستمر في استهلاك الذاكرة إذا لم تقم بفصلها في البرامج النصية الخاصة بك. يمكن أن يؤدي ذلك إلى تسريبات ذاكرة كبيرة جدًا بمرور الوقت على الخادم مع انضمام مئات المستخدمين وترك اللعبة.
الجداول - إدراج كائنات في الجداول ولكن عدم إزالتها عند عدم الحاجة إليها يسبب استهلاكًا غير ضروري للذاكرة، خاصةً للجداول التي تتعقب بيانات المستخدمين عند انضمامهم. على سبيل المثال، يقوم نموذج الكود التالي بإنشاء جدول يضيف معلومات المستخدم في كل مرة ينضم فيها مستخدم:
مثالlocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- بعض المعلوماتend)إذا لم تقم بإزالة هذه الإدخالات عند عدم الحاجة إليها، يستمر الجدول في النمو في الحجم ويستهلك المزيد من الذاكرة مع انضمام المزيد من المستخدمين إلى الجلسة. يصبح أي كود يقوم بالتكرار على هذا الجدول أيضًا أكثر تكلفة حسابيًا مع زيادة حجم الجدول.
التخفيف
لتنظيف جميع القيم المستخدمة لمنع تسريبات الذاكرة:
فصل جميع الاتصالات - تحقق من قاعدة التعليمات البرمجية الخاصة بك وتأكد من تنظيف كل اتصال من خلال أحد المسارات التالية:
- الفصل يدويًا باستخدام دالة Disconnect().
- تدمير العنصر الذي ينتمي إليه الحدث باستخدام دالة Destroy().
- تدمير كائن البرنامج النصي الذي تتبع إليه الاتصال.
إزالة كائنات اللاعب والشخصيات بعد المغادرة - قم بتمكين Workspace.PlayerCharacterDestroyBehavior لتدمير كائنات اللاعب وطراز الشخصية تلقائيًا بعد مغادرة المستخدم. إذا كنت تفضل، يمكنك بدلاً من ذلك تنظيفها يدويًا:
مثال لتنظيف اللاعب والشخصيةlocal Players = game:GetService("Players")Players.PlayerAdded:Connect(function(player)player.CharacterRemoving:Connect(function(character)task.defer(character.Destroy, character)end)end)Players.PlayerRemoving:Connect(function(player)task.defer(player.Destroy, player)end)
حساب الفيزياء
يمكن أن يكون المحاكاة الزائدة للفيزياء سببًا رئيسيًا في زيادة وقت الحساب لكل إطار على كل من الخادم والعميل.
المشكلات الشائعة
التكرار الزائد لوقت فترات الفيزياء - بشكل افتراضي، يتم السلوك المتدرج في الوضع التكيفي، حيث تتدرج الفيزياء عند 60 هرتز أو 120 هرتز أو 240 هرتز، حسب تعقيد آلية الفيزياء.
يتاح وضع ثابت مع دقة محسنة للفيزياء، والذي يجبر جميع مجموعات الفيزياء على التدرج عند 240 هرتز (أربع مرات لكل إطار). وهذا يؤدي إلى مزيد من الحسابات بشكل كبير في كل إطار.
عدد أو تعقيد الكائنات التي تمت محاكاتها بشكل مفرط - كلما زاد عدد التجميعات ثلاثية الأبعاد التي يتم محاكاتها، زادت مدة الحسابات الفيزيائية لكل إطار. غالبًا ما تحتوي الألعاب على كائنات يتم محاكاتها لا تحتاج إلى محاكاة أو ستحتوي على آليات لديها قيود ومفاصل أكثر مما تحتاج.
الكشف المفرط عن التصادم - تحتوي الأجزاء الشبكية على خاصية CollisionFidelity لاكتشاف التصادم الذي يقدم مجموعة متنوعة من الأوضاع بمستويات مختلفة من تأثير الأداء. تمتلك وضعية الكشف عن التصادم الدقيقة للأجزاء الشبكية أعلى تكلفة أداء وبالتالي يستغرق المحرك وقتًا أطول للحساب.
التخفيف
تثبيت الأجزاء التي لا تتطلب المحاكاة - قم بتثبيت جميع الأجزاء التي لا تحتاج إلى التحكم الفيزيائي، مثل NPCs الثابتة.
استخدم التدرج الفيزيائي التكيفي - تقوم التدرجات التكيفية بتعديل معدل حسابات الفيزياء بشكل ديناميكي للآليات الفيزيائية، مما يسمح بتحديثات الفيزياء بشكل أقل تكرارًا في بعض الحالات.
تقليل تعقيد الآلية
- حيثما كان ممكنًا، قم بتقليل عدد القيود الفيزيائية أو المفاصل في التجميع.
- قلل من مقدار التصادم الذاتي داخل الآلية، مثل تطبيق الحدود أو القيود غير المسموح بها على الأطراف في حالة الراكب لمنعها من التصادم مع بعضها البعض.
تقليل استخدام دقة التصادم الدقيقة للأجزاء الشبكية
بالنسبة لكائنات صغيرة أو غير قابلة للتفاعل التي من المحتمل ألا يلاحظ المستخدمون الاختلاف، استخدم دقة الصندوق.
بالنسبة للكائنات ذات الحجم الصغير إلى المتوسط، استخدم دقة الصندوق أو الهيكل، حسب الشكل.
بالنسبة للكائنات الكبيرة والمعقدة جدًا، قم ببناء تصادمات مخصصة باستخدام أجزاء غير مرئية عند الإمكان.
بالنسبة للكائنات التي لا تتطلب تصادمات، قم بتعطيل التصادمات واستخدم دقة الصندوق أو الهيكل، حيث لا تزال الهندسة التصادمية مخزنة في الذاكرة.
يمكنك عرض الهندسة التصادمية لأغراض التصحيح في الاستوديو من خلال تشغيل دقة التصادم من أداة خيارات التصوير في الزاوية العليا اليمنى من نافذة العرض الثلاثية الأبعاد.
بدلاً من ذلك، يمكنك تطبيق فلتر CollisionFidelity=PreciseConvexDecomposition على المستكشف الذي يعرض عدد جميع الأجزاء الشبكية ذات الدقة الدقيقة ويسمح لك بسهولة بتحديدها.
للحصول على شرح متعمق حول كيفية اختيار خيار دقة التصادم الذي يوازن بين متطلبات الدقة والأداء، راجع ضبط معلمات الفيزياء والتصوير.
نطاقات MicroProfiler
| النطاق | الحساب المرتبط |
| physicsStepped | محاكاة فيزيائية عامة |
| worldStep | خطوات الفيزياء المنفصلة التي تتم في كل إطار |
استخدام الذاكرة في الفيزياء
تستخدم حركة الفيزياء واكتشاف التصادمات الذاكرة. تحتوي الأجزاء الشبكية على خاصية CollisionFidelity التي تحدد النهج الذي يتم استخدامه لتقييم حدود التصادم للشبكة.
المشكلة الشائعة
تستهلك أوضاع الكشف عن التصادم الافتراضي والدقيق ذاكرة أكثر بكثير من وضعيّات أخرى ذات شكل تصادم أقل دقة.
إذا رأيت مستويات عالية من استهلاك الذاكرة تحت PhysicsParts، قد تحتاج إلى استكشاف تقليل دقة التصادم للكائنات في لعبتك.
كيفية التخفيف
لتقليل الذاكرة المستخدمة لدقة التصادم:
- بالنسبة للأجزاء التي لا تحتاج إلى تصادمات، قم بتعطيل تصادماتها عن طريق تعيين BasePart.CanCollide و BasePart.CanTouch و BasePart.CanQuery إلى false.
- تقليل دقة التصادم باستخدام إعداد CollisionFidelity. يعد Box لديه أقل تحميل ذاكرة، بينما يعد Default و Precise أكثر تكلفة عمومًا.
- من الآمن عمومًا تعيين دقة التصادم لأي جزء صغير مثبت إلى Box.
- بالنسبة للتجاويف الكبيرة المعقدة جدًا، قد ترغب في بناء شبكة التصادم الخاصة بك من كائنات أصغر ذات دقة تصادم صندوق.
البشر
Humanoid هي فئة تقدم مجموعة واسعة من الوظائف للاعبين والشخصيات غير القابلة للعب (NPCs). على الرغم من قوتها، إلا أن Humanoid تأتي بتكلفة حسابية كبيرة.
المشاكل الشائعة
- ترك جميع أنواع حالات HumanoidStateTypes مُمكّنة على NPCs - هناك تكلفة أداء لترك أنواع معينة من HumanoidStateTypes مُمكّنة. قم بتعطيل أي منها غير ضروري لـ NPCs الخاصة بك. على سبيل المثال، ما لم يكن من المتوقع أن يتسلق NPC السلالم، من الآمن تعطيل حالة Climbing.
- استخدام Humanoids في الحالات التي لا تكون فيها مطلوبة - NPCs الثابتة التي لا تتحرك عمومًا لا تحتاج إلى فئة Humanoid.
- تشغيل الرسوم المتحركة على عدد كبير من NPCs من الخادم - تحتاج تحركات NPC التي تعمل على الخادم إلى المحاكاة على الخادم وتكرارها على العميل. يمكن أن يكون هذا عبئًا غير ضروري.
- إجراء تغييرات غير ضرورية في الحجم والمقياس - تتسبب تغييرات الحجم/المقياس في إعادة بناء FastCluster. حاول تقليل هذا أثناء اللعب إذا كنت ترى مشاكل في الأداء تتعلق بـ FastCluster. يمكن أن تتسبب تغييرات الخصائص الأخرى أيضاً في إعادة بناء FastCluster، لذا بشكل عام، قلل هذا التغييرات قدر الإمكان.
التخفيف
- قم بتشغيل الرسوم المتحركة لـ NPCs على العميل - في الألعاب التي تحتوي على عدد كبير من NPCs، فكر في إنشاء Animator على العميل وتشغيل الرسوم المتحركة محليًا. يقلل هذا من الحمل على الخادم وضرورة التكرار غير الضروري. كما أنه يجعل تحسينات إضافية ممكنة (مثل تشغيل الرسوم المتحركة فقط لـ NPCs القريبة من الشخصية).
- استخدم بدائل صديقة للأداء لـ Humanoids - قد لا تحتاج نماذج NPC إلى احتواء كائن Humanoid.
- بالنسبة لـ NPCs الثابتة، استخدم AnimationController بسيطة، لأنهم لا يحتاجون إلى التحرك ولكن فقط يحتاجون إلى تشغيل الرسوم المتحركة.
- بالنسبة لـ NPCs المتحركة، فكر في تنفيذ وحدة تحكم حركية خاصة بك واستخدام AnimationController للرسوم المتحركة، اعتمادًا على تعقيد NPCs الخاصة بك.
- قم بتعطيل حالات humanoid غير المستخدمة - استخدم Humanoid:SetStateEnabled() لتمكين فقط الحالات الضرورية لكل humanoid.
- تجمع نماذج NPCs التي تُعاد تجسيدها بشكل متكرر - بدلاً من تدمير NPC تمامًا، قم بإرسال NPC إلى مجموعة من NPCs غير النشطة. بهذه الطريقة، عندما يتطلب الأمر إعادة تجسيد NPC جديد، يمكنك ببساطة إعادة تنشيط أحد NPCs من المجموعة. تُعرف هذه العملية بالتجميع، مما يقلل من عدد المرات التي تحتاج فيها الشخصيات إلى أن تُجسد.
- قم بتجسيد NPCs فقط عندما يكون المستخدمون قريبين - لا تقم بتجسيد NPCs عندما لا يكون المستخدمون في نطاق، وقطعهم عند مغادرة المستخدمين للنطاق.
- تجنب جعل التغييرات على تسلسل الصورة الرمزية بعد نسخها - تؤدي بعض التعديلات على تسلسل الصورة الرمزية إلى آثار سلبية كبير على الأداء. تتوفر بعض التحسينات:
- بالنسبة للرسوم المتحركة المخصصة، لا تقم بتحديث خاصيتي JointInstance.C0 و JointInstance.C1. بدلاً من ذلك، قم بتحديث خاصية Motor6D.Transform.
- إذا كنت بحاجة إلى إرفاق أي كائنات من BasePart بالصورة الرمزية، قم بذلك خارج تسلسل الصورة الرمزية.
نطاقات MicroProfiler
| النطاق | الحساب المرتبط |
| stepHumanoid | تحكم humanoid والفيزياء |
| stepAnimation | رسوم متحركة لـ humanoid ومتحكم الرسوم المتحركة |
| updateInvalidatedFastClusters | مرتبط بتجسيد الصور الرمزية أو تعديلها |
العرض
تستغرق الجزء الأكبر من الوقت الذي يقضيه العميل في كل إطار في عرض المشهد في الإطار الحالي. لا يقوم الخادم بأي عرض، لذا فإن هذا القسم يقتصر على العميل.
مكالمات العرض
مكالمة العرض هي مجموعة من التعليمات من المحرك إلى وحدة معالجة الرسومات (GPU) لعرض شيء ما. تحتوي مكالمات العرض على تكاليف زائدة كبيرة. عمومًا، كلما قلت مكالمات العرض لكل إطار، قضى الوقت الحسابي أقل في عرض الإطار.
يمكنك رؤية عدد مكالمات العرض التيحدثت حاليًا باستخدام عنصر إحصائيات العرض ⟩ التوقيت في الاستوديو. يمكنك عرض إحصائيات العرض في العميل بالضغط على ShiftF2.
كلما كانت هناك كائنات تحتاج إلى العرض في مشهدك في إطار معين، زادت مكالمات العرض المقدمة إلى GPU. ومع ذلك، تستخدم محرك Roblox عملية تُدعى التجميع لدمج الشبكات المتطابقة ذات الخصائص الملمسية المماثلة في مكالمة عرض واحدة. بشكل خاص، تتم معالجة الشبكات المتعددة ذات MeshContent المتطابقة في مكالمة عرض واحدة عندما:
- تكون SurfaceAppearances متماثلة إذا كانت موجودة، خلاف ذلك عندما تكون TextureContents متماثلة.
- المواد متطابقة عندما لا توجد كل من SurfaceAppearance و MeshPart.TextureID.
مشكلات شائعة أخرى
كثافة الكائنات الزائدة - إذا تم تركيز عدد كبير من الكائنات بكثافة عالية، فإن عرض هذه المنطقة من المشهد يتطلب المزيد من مكالمات العرض. إذا كنت تجد أن معدل الإطارات لديك ينخفض عند النظر إلى جزء معين من الخريطة، فإن هذه يمكن أن تكون إشارة جيدة على أن الكثافة الكائنية في هذه المنطقة مرتفعة جدًا.
لا تتجمع الكائنات مثل الملصقات والقوام والجزيئات بشكل جيد وتintroduce مكالمات عرض إضافية. كن حذرًا بشكل خاص تجاه هذه الأنواع من الكائنات في المشهد. بشكل خاص، يمكن أن تؤثر تغييرات الخصائص إلى ParticleEmitters بشكل كبير على الأداء.
فرص التجميع المفقودة - عادةً، يتضمن المشهد نفس الشبكة المكررة عدة مرات، ولكن كل نسخة من الشبكة لديها معرفات أصول شبكية أو سطحية مختلفة. وهذا يمنع التجميع ويمكن أن يؤدي إلى مكالمات عرض غير ضرورية.
سبب شائع لهذه المشكلة هو عندما يتم استيراد المشهد بالكامل دفعة واحدة، بدلاً من استيراد الأصول الفردية إلى Roblox ثم تكرارها بعد الاستيراد لتجميع المشهد.
حتى يكون هناك برنامج نصي بسيط مثل هذا يمكن أن يساعدك في تحديد أجزاء الشبكة التي تحمل نفس الاسم ولكن تستخدم معرفات شبكية مختلفة:
for _,descendant in workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendقد تبدو المخرجات (مع تمكين Stack Lines) على هذا النحو. تشير الخطوط المتكررة إلى إعادة استخدام نفس الشبكة، وهو أمر جيد. الخطوط الفريدة ليست بالضرورة سيئة، ولكن اعتمادًا على نظام التسمية الخاص بك، قد تشير إلى شبكات مكررة في لعبتك:
LargeRock, rbxassetid://106420009602747 (x144) -- جيدLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- جميع التكرارات الممكنةتعقيد الكائنات المفرط - على الرغم من أنه ليس بنفس أهمية عدد مكالمات العرض، يؤثر عدد المثلثات في مشهد على مدة العرض لجعل إطار. تعتبر المشاهد ذات عدد كبير جدًا من الشبكات المعقدة جدًا مشكلة شائعة، وكذلك المشاهد ذات الخاصية MeshPart.RenderFidelity تم تعيينها إلى Precise على العديد من الشبكات.
إسقاط الظل المفرط - التعامل مع الظلال هو عملية مكلفة، ويمكن أن تتسبب الخرائط التي تحتوي على عدد وكثافة عالية من مصادر الضوء التي تسقط الظلال (أو عدد و كثافة عالية من الأجزاء الصغيرة التي تتأثر بالظلال) في مشاكل في الأداء.
كسر الشفافية الزائدة - وضع كائنات تحمل شفافية جزئية قرب بعضها البعض يجبر المحرك على رسم البكسلات المتداخلة عدة مرات، مما يمكن أن يؤثر سلبًا على الأداء. لمزيد من المعلومات حول تحديد وحل هذه المشكلة، راجع احذف الشفافية الطبقية.
حركة MeshPart مزودة بالجلد غير الضرورية - تتجمع MeshParts المزودة بالجلد التي تعد جزءًا من نموذج بدون Humanoid باستخدام FastClusters مرتبة مكانيًا. عندما تتحرك هذه MeshParts، يجب إضافتها وإزالتها باستمرار من هذه التجمعات المكانية، مما يجبر التجمعات على إعادة البناء ويؤثر على الأداء.
- يعد الحل الفعال للغاية هو إدراج Humanoid داخل النموذج. تفترض وجود Humanoid محدود سلوك التجميع الم пространства، مما يجعل من الضروري استخدام FastCluster موحد. بالتالي، لم تعد التحديثات الموقعية تتطلب إعادة بناء التجمعات، مما يقلل من عاقات الأداء. يجب الاحتفاظ بهذه التقنية حصريًا للـ MeshParts المشمولة بحركة متوقع، حيث قد تقدم حمولة ذاكرة سلبية عائدة وتلغي فوائد تحسين الأداء المكاني. نوصي دائمًا بتحليل أداء لعبتك بعد إجراء هذه الأنواع من التغييرات. راجع نصائح أداء Humanoid للحصول على معلومات إضافية.
عدد كبير جدًا من الأجزاء في Model - قد يتسبب عدد كبير جدًا من الأجزاء في نموذج إلى إعادة البناء كثيرًا نظرًا لاحتياج تغيير خصائص جزء إلى إعادة البناء بالكامل. ابحث عن التوازن الأنسب من الأجزاء في النموذج عند استخدام FastCluster.
التخفيف
التجميع لمطابقات الشبكات وتقليل عدد الشبكات الفريدة - إذا كنت تضمن أن جميع الشبكات المتطابقة تحمل نفس معرفات الأصول، يمكن للمحرك التعرف عليها وعرضها في مكالمة عرض واحدة. تأكد من تحميل كل شبكة في خريطة مرة واحدة ثم تكرارها في الاستوديو لإعادة استخدام بدلاً من استيراد خرائط كبيرة ككل، ما قد يؤدي إلى الاعتراف بمعرفات الأصول المتطابقة كأصول فريدة. تعتبر الحزم آلية جيدة لإعادة استخدام الأجزاء.
القطع - يشير القطع إلى عملية التخلص من مكالمات العرض للكائنات التي لا تدخل في الإطار النهائي المعروض. بشكل افتراضي، يتخطى المحرك مكالمات العرض للكائنات خارج مجال رؤية الكاميرا (القطع الفراغي) والأجزاء والشبكات والأرض المتخيلة من قبل كائنات أخرى (قطع الخفاء). في بعض السيناريوهات، مثل البيئات الداخلية، قد تتمكن من تنفيذ نظام غرفة أو بوابة وقص الكائنات يدويًا لتقليل مكالمات العرض أو الحمل الحسابي العام.
تقليل مستوى التفاصيل للنماذج - قم بتمكين تدفق النسخ وتعيين خاصية LevelOfDetail للنماذج الخاصة بك إلى SLIM لعرض شبكات SLIM الخفيفة الوزن المحسنة عندما تزداد المسافة من الكاميرا.
تقليل مستوى التفاصيل للشخصيات - قم بتمكين تدفق النسخ وتعيين Workspace.EnableSLIMAvatars لعرض الشخصيات كتمثيلات SLIM خفيفة الوزن محسنة مع دعم كامل للرسوم المتحركة عند زيادة المسافة عن الكاميرا.
تقليل دقة العرض - قم بتعيين MeshPart.RenderFidelity إلى Automatic أو Performance. يسمح هذا للشبكات بالعودة إلى بدائل أقل تعقيدًا، مما يمكن أن يقلل من عدد المضلعات التي تحتاج إلى أن يتم رسمها.
تعطيل إسقاط الظل على الأجزاء والأشياء الضوئية المناسبة - يقوم محرك Roblox تلقائيًا بتقليل جودة الظل مع انخفاض مستوى الرسوميات الخاص بالعميل، في النهاية مع تعطيل الظلال تمامًا عند مستويات الجودة الأدنى من 4. ومع ذلك، يمكنك تعطيل خصائص إسقاط الظل بشكل انتقائي على الأشياء الضوئية والأجزاء لتحسين الأداء أثناء تمكين الظلال وزيادة احتمالية استمرار تمكين الظلال. بعض الأمثلة على التحسينات التي يمكنك إجراؤها إما في وقت التحرير أو ديناميكيًا عند التشغيل:
استخدم خاصية BasePart.CastShadow لتعطيل إسقاط الظل على الأجزاء الصغيرة حيث من غير المحتمل أن تكون الظلال مرئية. تعتبر هذه الاستراتيجية فعالة بشكل خاص عندما يتم تطبيقها على الأجزاء التي تكون بعيدة عن كاميرا المستخدم.
قم بتعطيل الظلال على الكائنات المتحركة متى كان ذلك ممكنًا.
قم بتعطيل Light.Shadows على الكائنات الضوئية حيث لا يحتاج الكائن إلى إسقاط الظلال.
حد من نطاق وزاوية الكائنات الضوئية.
استخدم عدد أقل من الكائنات الضوئية.
قم بتعطيل الأضواء التي تقع خارج نطاق معين أو بناءً على غرفة معينة للبيئات الداخلية.
نطاقات MicroProfiler
| النطاق | الحساب المرتبط |
| Prepare and Perform | العرض العام |
| Perform/Scene/computeLightingPerform | تحديثات الشبكة والظل |
| LightGridCPU | تحديثات شبكة الضوء الثلاثي الأبعاد |
| ShadowMapSystem | تعيين الظلال |
| Perform/Scene/UpdateView | التحضير للعرض وتحديثات الجزيئات |
| Perform/Scene/RenderView | العرض وما بعد المعالجة |
الشبكات والتكرار
يصف مجال الشبكات والتكرار العملية التي يتم بها إرسال البيانات بين الخادم والعملاء المتصلين. يتم إرسال المعلومات بين العميل والخادم في كل إطار، ولكن كميات أكبر من المعلومات تتطلب مزيداً من وقت الحساب.
المشكلات الشائعة
المرور البعيد الزائد - إرسال كمية كبيرة من البيانات عبر كائنات RemoteEvent أو RemoteFunction أو استدعائها بشكل متكرر يمكن أن يؤدي إلى قضاء وقت كبير من وحدة المعالجة المركزية في معالجة حزم البيانات الواردة في كل إطار. تشمل الأخطاء الشائعة:
- تكرار البيانات في كل إطار لا يحتاج إلى التكرار.
- تكرار البيانات بناءً على إدخال المستخدم دون أي آلية للتحكم في هذا.
- نشر المزيد من البيانات من ما هو مطلوب. على سبيل المثال، إرسال المخزون الكامل للاعب عند شراء عنصر بدلاً من تفاصيل العنصر المشتراة.
إنشاء أو إزالة أشجار معقّدة من العناصر - عندما يتم إجراء تغيير على نموذج البيانات على الخادم، يتم تكراره إلى العملاء المتصلين. هذا يعني أن إنشاء وتدمير هياكل العناصر الكبيرة مثل الخرائط في وقت التشغيل يُمكن أن يكون مكلفًا للغاية على الشبكة.
يعتبر أحد الأسباب الشائعة هنا هو بيانات الرسوم المتحركة المعقدة المحفوظة بواسطة مكونات محرر الرسوم المتحركة في الهياكل. إذا لم تتم إزالتها قبل نشر اللعبة وتم استنساخ النموذج المتحرك بانتظام، فسوف يتم تكرار كمية كبيرة من البيانات بشكل غير ضروري.
TweenService على الجانب الخادم - إذا تم استخدام TweenService لتحريك عنصر على الجانب الخادم، يتم تكرار الخاصية المحركة إلى كل عميل في كل إطار. لا يؤدي هذا إلى جعل الرسوم المتحركة غير منتظمة حيث تتقلب زمن انتقال العملاء فحسب، بل يتسبب أيضًا في مرور بيانات الشبكة غير الضرورية.
التخفيف
يمكنك استخدام الأساليب التالية لتقليل التكرار غير الضروري:
- تجنب إرسال كميات كبيرة من البيانات دفعة واحدة عبر الأحداث البعيدة. بدلاً من ذلك، أرسل البيانات الضرورية فقط بتكرار أقل. على سبيل المثال، بالنسبة لحالة شخصية، كررها عند تغييرها بدلاً من كل إطار.
- قسّم أشجار العناصر المعقدة مثل الخرائط وحملها على أجزاء لتوزيع العمل المتكرر عبر إطارات متعددة.
- تنظيف بيانات الرسوم المتحركة، وخاصةً دليل الرسوم المتحركة للهياكل، بعد الاستيراد.
- تحديد تكرار عنصر البيانات غير الضرورية، خاصةً في الحالات التي لا يحتاج فيها الخادم إلى معرفة العناصر التي يتم إنشاؤها. يشمل ذلك:
- التأثيرات البصرية مثل الانفجارات أو انفجارات تعاويز السحر. يحتاج الخادم فقط إلى معرفة الموقع لتحديد النتيجة، بينما يمكن للعملاء إنشاء التأثيرات محليًا.
- نماذج عرض العناصر من منظور الشخص الأول.
- حرك الكائنات على العميل بدلاً من الخادم.
نطاقات MicroProfiler
| النطاق | الحساب المرتبط |
| ProcessPackets | معالجة حزم الشبكة الواردة، مثل استدعاءات الأحداث وتغييرات الخصائص |
| Allocate Bandwidth and Run Senders | الأحداث الخارجة المتعلقة بالخوادم |
استخدام ذاكرة الأصول
تعتبر أعلى آلية تأثير متاحة للمبدعين لتحسين استخدام ذاكرة العميل هي تمكين تدفق النسخ.
تدفق النسخ
يقوم تدفق النسخ بتحميل أجزاء من نموذج البيانات بشكل انتقائي غير مطلوب، مما يؤدي إلى تقليل أوقات التحميل بشكل كبير وزيادة قدرة العميل على منع الأعطال عند تعرضه لضغط الذاكرة.
إذا كنت تواجه مشكلات في الذاكرة ولديك تدفق النسخ معطلاً، فكر في تحديث لعبتك لدعمه، وخاصةً إذا كانت عالمك الثلاثي الأبعاد كبيرًا. يعتمد تدفق النسخ على المسافة في الفضاء الثلاثي الأبعاد، لذا تستفيد العوالم الكبيرة بشكل أكبر منه.
إذا كان تدفق النسخ مفعلًا، يمكنك زيادة تعزيز قوته. على سبيل المثال، اعتبر:
- تقليل استخدام Enum.ModelStreamingMode.Persistent حيثما كان ذلك ممكنًا. قد تحتاج إلى تحديث البرامج النصية الخاصة بك إذا كنت تستخدمه كإجراء تعويضي.
- تقليل Workspace.StreamingMinRadius و Workspace.StreamingTargetRadius.
للحصول على مزيد من المعلومات حول خيارات التدفق وفوائدها، راجع خصائص التدفق.
مشكلات شائعة أخرى
تكرار الأصول - يعتبر خطأ شائعًا هو تحميل نفس الأصل عدة مرات ما يؤدي إلى معرفات أصول مختلفة. قد يؤدي ذلك إلى تحميل نفس المحتوى في الذاكرة عدة مرات.
حجم الأصول الزائد - حتى عند عدم تطابق الأصول، هناك حالات تفوت فيها الفرص لإعادة استخدام الأصل نفسه وتوفير الذاكرة.
ملفات الصوت - يمكن أن تسهم ملفات الصوت بقدر مفاجئ في استخدام الذاكرة، خاصةً إذا قمت بتحميل جميعها إلى العميل دفعة واحدة بدلاً من تحميل ما تحتاج إليه فقط لجزء من اللعبة. للحصول على استراتيجيات، راجع أوقات التحميل.
قوام ز resolution عالية - لا يرتبط استهلاك ذاكرة الرسومات لقوام بمدى حجم القوام على القرص؛ عدد بكسل القوام يحدد استخدام الذاكرة. على سبيل المثال، يستهلك قوام بحجم 1024x1024 بكسل أربعة أضعاف المذكور ذاكرة الرسومات مقارنةً بقوام بحجم 512x512.
يتم إعادة ترميز الصور المحملة إلى Roblox إلى تنسيق ثابت، لذا لا يوجد فائدة من حيث الذاكرة لتحميل الصور في نموذج لوني مرتبط برموز أقل لكل بكسل. وبالمثل، فإن ضغط الصور قبل التحميل أو إزالة قناة ألفا من الصور التي لا تحتاج إليها يمكن أن يقلل من حجم الصورة على القرص، ولكنه لا يحسن استخدام الذاكرة.
عندما يتم تحميل اللعبة، يبدأ المحرك تلقائيًا بجودة منخفضة من القوام ثم يزيد الجودة بناءً على ذاكرة الجهاز المتوفرة، المسافة من الكاميرا، كمية مساحة الشاشة التي يحتلها القوام، وعوامل أخرى. حتى مع ذلك، يمكن أن يؤثر تحديد حجم قوامك بشكل استراتيجي على استخدام الذاكرة في لعبتك.
التخفيف
قم بتحميل الأصول مرة واحدة فقط - أعد استخدام نفس معرّف الأصل عبر الكائنات وتأكد من عدم تحميل نفس الأصول، وخاصةً الشبكات والصور، بشكل منفصل عدة مرات.
ابحث عن الأصول المكررة وقم بإصلاحها - ابحث عن أجزاء الشبكة والأنسجة المتطابقة التي تم تحميلها عدة مرات بمعرفات مختلفة.
- على الرغم من عدم وجود واجهة برمجة تطبيقات للكشف عن تشابه الأصول بشكل تلقائي، يمكنك جمع جميع معرفات أصول الصور في مكانك (يدويًا أو باستخدام سكربت)، وتحميلها، ومقارنتها باستخدام أدوات المقارنة الخارجية.
- بالنسبة لأجزاء الشبكة، فإن أفضل استراتيجية هي أخذ معرفات الشبكة الفريدة وتنظيمها حسب الحجم لتحديد التكرارات يدويًا.
- بدلًا من استخدام قوام منفصل لألوان مختلفة، قم بتحميل قوام واحد واستخدم خاصية SurfaceAppearance.Color لتطبيق تدرجات لونية متنوعة.
استيراد الأصول في الخريطة بشكل منفصل - بدلاً من استيراد خريطة كاملة دفعة واحدة، استورد وأعد بناء الأصول في الخريطة بشكل فردي. لا يقوم المستورد بإزالة تكرار الأنسجة، وبالتالي إذا قمت باستيراد خريطة كبيرة بها العديد من بلاط الأرضيات المنفصلة، فسوف يتم استيراد كل تلك البلاطات كأصول منفصلة (حتى إذا كانت مكررة). يمكن أن يؤدي ذلك إلى مشكلات في الأداء والذاكرة في المستقبل، حيث يتم التعامل مع كل شبكة بشكل فردي وتستهلك ذاكرة ومكالمات عرض.
قلل من بكسلات الصور لعدم تجاوز الكم الضروري. ما لم تحتل الصورة مساحة كبيرة من الفضاء الفعلي على الشاشة، فإن الحاجة غالبًا ما تتطلب 512x512 بكسل كأقصى حد. يجب أن تكون معظم الصور البسيطة أصغر من 256x256 بكسل.
استخدم أوراق التقليم لضمان أقصى إعادة استخدام لقوام في الخرائط الثلاثية الأبعاد. للحصول على خطوات وأمثلة حول كيفية إنشاء أوراق التقليم، راجع إنشاء أوراق تقليم.
يمكنك أيضًا التفكير في استخدام أوراق رمزية لتحميل العديد من صور واجهة المستخدم الصغيرة كصورة واحدة. يمكنك بعد ذلك استخدام ImageLabel.ImageRectOffset و ImageLabel.ImageRectSize لعرض أجزاء من الورقة.
أوقات التحميل
تقوم العديد من الألعاب بتنفيذ شاشات تحميل مخصصة وتستخدم طريقة ContentProvider:PreloadAsync() لطلب الأصول بحيث يتم تنزيل الصور والأصوات والشبكات في الخلفية.
تتمثل ميزة هذه الطريقة في أنها تتيح لك التأكد من تحميل الأجزاء المهمة من لعبتك بالكامل دون أي ظهور مفاجئ. ومع ذلك، فإن خطأً شائعًا هو الإفراط في استخدام هذه الطريقة لتحميل المزيد من الأصول مما هو مطلوب فعليًا.
مثال على ممارسة سيئة هو تحميل Workspace بالكامل. بينما يمنع هذا ظهور قوام مفاجئ، إلا أنه يزيد بشكل كبير من أوقات التحميل.
ممارسة مشابهة هي استخدام ContentProvider.RequestQueueSize للتأكد من انتهاء تحميل جميع الأصول المطلوبة. ومع ذلك، يقدم هذا نفس المشكلة المتمثلة في زيادة أوقات التحميل بشكل كبير، بينما يعد أيضًا طريقة غير موثوقة بسبب طبيعتها المتفاوتة.
بدلاً من ذلك، استخدم فقط ContentProvider:PreloadAsync() في الحالات الضرورية، والتي تشمل:
- الصور في شاشة التحميل.
- الصور المهمة في قائمة اللعبة الخاصة بك، مثل خلفيات الأزرار والرموز.
- الأصول المهمة في منطقة البداية أو التجسيد.
إذا كان من الضروري تحميل عدد كبير من الأصول، فإننا نوصي بتوفير زر تخطي التحميل.