جولة في الهيكل الأساسي
يوضح هذا القسم البنية الأساسية لتكامل LightScript، ويغطي المتطلبات التقنية الرئيسية، وأمثلة من الواقع، واصطلاحات التسمية، ونصائح الكفاءة. ويشرح حلقة التحديث، وسلوك العدّادات، ومنطق تشغيل التأثيرات، ويسلّط الضوء على الأخطاء الشائعة. وسواء كنت تصحح الأخطاء، أو تبني من الصفر، أو تصون شيفرة كتبها شخص آخر، فإن هذا الدليل يؤكد على الوضوح والاستقرار والأداء باعتبارها المعايير الأساسية للتكاملات عالية الجودة.
التخطيط الأساسي
Section titled “التخطيط الأساسي”يقدم هذا القسم نظرة عامة سريعة على إعداد LightScript من منظور الصيانة، مع التركيز على المواضع التي تحدث فيها المشكلات عادةً وكيفية اكتشاف الأخطاء وإصلاحها. سنبدأ بجولة موجزة في البنية المثالية لـ LightScript لتتعرف على الشيفرة، ثم نتناول استكشاف الأخطاء وإصلاحها، ونختم بالأسئلة الشائعة.
يتطلب الهيكل الأساسي وجود <head> و**<body>** و**<script>**. توضع جميع تعريفات العدّادات وعناصر تحكم المستخدم داخل <head>. وتنتمي جميع تعريفات canvas إلى <body>. أما كل ما عدا ذلك فيجب وضعه في قسم <script>.
<head>
Section titled “<head>”يُعدّ <head> من أهم أجزاء أي LightScript وأكثرها تعقيدًا. فعنصر تحكم مستخدم أو عدّاد معيب هنا يمكن أن يسبب حلقات تعطل متكررة، أو يعطّل نفسه وأي عدّادات مُعرَّفة بعده.
عند إنشاء العدّادات، يجب أن تتأكد من:
- صياغة مثالية (لتجنب الأعطال والعدّادات المعطلة)
- عدم تكرار أسماء العدّادات (فالمكررة تُستبدل)
- عدم امتداد أي عدّاد خارج حدود الشاشة (يسبب أعطالًا وأخطاء)
- عدم وجود خيارات مفقودة أو زائدة في العدّادات (يؤدي إلى أعطال)
- تضمين جميع العدّادات لتعديلات الدقة (يضمن سلوكًا متسقًا)
فيما يخص الدقات، فإن نسب العرض إلى الارتفاع الأكثر شيوعًا هي:
- 16:9 (3840x2160, 2560x1440, 1920x1080, 1600x900, 1366x768, 1360x768, 1280x720)
- 16:10 (2560x1600, 1920x1200, 1680x1050, 1440x900, 1280x800)
- 21:9 (5120x2160, 3440x1440)
افتراضيًا، نستخدم الدقة 2560x1440.
يجب أن تدعم جميع LightScripts نسب العرض إلى الارتفاع 16:9 و16:10 و21:9. وعلى الرغم من أن نسبة 4:3 لا تمثل جزءًا كبيرًا من قاعدة مستخدمينا، فإنه لا يزال ينبغي مراعاتها من أجل التوافق المستقبلي.
إليك مثالًا على بنية عدّاد بإعدادات دقة متعددة:

ينطبق الموقع والحجم الافتراضيان لعدّاداتك على كل دقة أخرى ضمن نسبة العرض إلى الارتفاع نفسها. على سبيل المثال، إذا ضبطت عدّاداتك في الأصل لتعمل مع 1600x900، فيجب أن يعمل ذلك العدّاد بشكل صحيح عبر جميع دقات 16:9 الأخرى. ومع ذلك، هناك استثناءات. فلعبة Fortnite لديها مواضع عدّادات مختلفة متعددة حتى ضمن نسبة العرض إلى الارتفاع نفسها، كما أن بعض نسب العرض إلى الارتفاع نفسها قد تكون مضللة. على سبيل المثال، غالبًا ما تُصنَّف الدقة 1366x768، وهي دقة شائعة عالميًا، على أنها 16:9، لكنها ليست في الواقع نسبة 16:9 حقيقية، وهذا ليس أمرًا غير معتاد. وبالمثل، نادرًا ما تتطابق النسب فائقة الاتساع مثل 21:9 مع أبعادها الاسمية. ومن واقع خبرتي كمطوّر تكاملات، لم أصادف أبدًا دقة 21:9 دقيقة على الرغم من تصنيفها على هذا النحو. ولهذا السبب، يجب إنشاء كل دقة فائقة الاتساع واختبارها وتهيئتها بشكل فردي.
يجب وضع جميع التعديلات بين وسم الفتح <meta> ووسم الإغلاق </meta>؛ وإلا فلن تعمل. إذا كان عدّادك الافتراضي مبنيًا على 16:9 ويعمل باتساق عبر تلك الدقات، فلن تحتاج إلى إضافة تعديلات لدقات 16:9 الأخرى. ومع ذلك، يجب عليك إضافة إدخالات لكل دقة في نسب العرض إلى الارتفاع الأخرى (مثل 16:10 و21:9)، حتى لو كانت النسبة متسقة.
أخيرًا، يتطلب كل عدّاد باستثناء عدّادات OCR نطاق HSL ليعمل. ويمكن أن تتعقد هذه النطاقات بسبب عوامل مثل:
- عناصر واجهة المستخدم الشفافة
- التدرجات في المناطق الملونة
- تأثيرات تشويه الشاشة
- فتح القوائم داخل اللعبة
- تعديلات واجهة المستخدم حسب الدقة
- استخدام وحدة التحكم مقابل لوحة المفاتيح
- تسجيل الفيديو، الذي قد يُدخل أخطاء في البكسلات ناتجة عن الضغط
التعليمات الأساسية حول HSL والإحداثيات المُسوّاة مشروحة في وثائق المطورين لدينا ولن تُكرر هنا. سيُناقش اختبار هذه العدّادات في قسم “تحديد المشكلات”، لكن من المهم التأكيد على ما يلي: يُحسب مقدار الاختبار اللازم للتحقق من جميع العدّادات بشكل مثالي على النحو التالي: (عدد العدّادات) × (عدد تعديلات الدقة) × (عدد أوضاع اللعب) × (عدد الشخصيات القابلة للعب) × (مدة المباراة المتوسطة). وقد يصل هذا بسهولة إلى ساعات من التحقق لكل لعبة، خاصةً إذا لم تتوفر أوضاع التدريب أو حلول بديلة أخرى.
حافظ على كفاءة عدّاداتك، فمعيارنا هو الكمال.
<body>
Section titled “<body>”وسم <body> هو المكان الذي يُعرَّف فيه عنصر canvas الفعلي. ويجب أن يبدو دائمًا مشابهًا إلى حد ما للمثال التالي. يمكنك تغيير id الفعلي لـ canvas إذا أردت، لكن تأكد من جلبه بشكل صحيح في السكربت.

<script>
Section titled “<script>”يجب أن تحدث أربعة أمور داخل هذا الوسم في كل تكامل
- جلب canvas واستخدامه لإنشاء السياق ثنائي الأبعاد (2D context).
- تعيّن حلقة التحديث الأولية قيم العدّادات، ثم تستدعي نفسها إلى ما لا نهاية للحفاظ عليها.
- تُبقي حلقة التحديث متغيرات عناصر تحكم المستخدم محدّثة.
- تنفّذ العدّادات دوال الاستدعاء الراجع الخاصة بها عندما تكون مستقرة.
الإجراء العام
Section titled “الإجراء العام”لقد أعددنا بالفعل الهيكل الأساسي للشيفرة. والخطوة التالية هي استعراض حلقة التنفيذ التي تشغّل التأثيرات من البداية إلى النهاية.
- تعرض واجهة مستخدم لعبة الفيديو المعلومات على شكل أشرطة ملونة، وأزرار، ومربعات نص، وما إلى ذلك. يلتقط SignalRGB هذه البيانات عدة مرات في الثانية، لكن معدل الالتقاط الفعلي يعتمد بشكل كبير على كفاءة شيفرتك. ولكي نكون واضحين، حلقة واحدة أو متغير واحد غير مُعرَّف يمكن أن يعطّل السكربت بالكامل، بل ويتسبب في تعطل SignalRGB. والأسوأ من ذلك، أنه من السهل كتابة شيفرة تعمل من الناحية التقنية، لكنها غير فعّالة لدرجة أنها تلتقط المعلومات بمعدل 1-2 FPS فقط.
- يجب أن يكون كل عدّاد مُعرَّف في <head> صغيرًا وفعّالًا قدر الإمكان لتقليل الحمل الزائد. أجرِ حساباتك مبكرًا وبشكل متكرر؛ فالعدّاد الذي يشغل 25% من الشاشة لا يكون فعّالًا أبدًا. مع عدّادات OCR، التقط أحرفًا فردية بدلًا من كلمات كاملة. وبالنسبة لأشرطة الصحة والمانا، راقب الأجزاء الأساسية فقط. اجعل عدّاداتك صغيرة قدر الإمكان.
- تلتقط العدّادات معلومات تتحدّث مع كل حلقة.
- تناولنا سابقًا تعريف صنف Meter، الذي يخزّن بيانات العدّاد ويشغّل استدعاءً راجعًا عندما تصبح مصفوفة المعلومات مستقرة. في أعلى السكربت، عرّف جميع نسخ Meter في كتلة واحدة. يمكنك تنظيمها أو ترتيبها أبجديًا؛ فقط لا تدفنها عبر آلاف الأسطر. فستحتاج في النهاية إلى تعديل قيم الاستقرار، ومن إضاعة الوقت محاولة تذكّر أين وضعتها.
- داخل دالة update، ستتلقى هذه العدّادات القيم من منطق قراءة الشاشة في كل حلقة. ويقيّم منطقها الداخلي الاستقرار، وعند الاستقرار، يشغّل دالة الاستدعاء الراجع المرتبطة بها.
- يجب تعريف دوال الاستدعاء الراجع هذه في السكربت ولكن خارج دالة update. وداخلها، تحقق من حالة قيم Meter (value، decreased، increased، diff) واستخدمها لتحديد ما إذا كان يجب تشغيل رسم متحرك للتأثير. إن هيكلة شيفرتك بهذه الطريقة، بدلًا من وضع كل شيء مباشرة داخل حلقة التحديث، تمكّننا من بناء تكاملات قابلة للتوسع.
مثال من الواقع
Section titled “مثال من الواقع”الآن بعد أن فهمت الفكرة العامة، سأستعرض سريعًا مثالًا لحلقة من الواقع.
- أنا ألعب لعبة League of Legends، التي تحيط المهارات المتاحة بإبراز أصفر ساطع.
- في كل حلقة، يلتقط عدّاد المهارة المحدد هذا اللون كقيمة “1” لأنه يجتاز نطاق HSL الخاص بالعدّاد بالكامل.
- تُمرَّر هذه القيمة “1” إلى نسخة Meter المرتبطة بعدّاد قراءة الشاشة، وتُدرج في مصفوفة المعلومات الخاصة بذلك Meter.
- إذا كانت كل قيمة في تلك المصفوفة هي “1”، فإنها تُعتبر مستقرة، وستفعّل دالة الاستدعاء الراجع للتأثير المرتبطة بها. وستُفعَّل دالة الاستدعاء الراجع هذه أيضًا إذا كانت كل قيمة “0”، أو “.1” مثلًا؛ فكل ما يهم Meter هو الاستقرار. ومن الملاحظات المهمة هنا أن دالة الاستدعاء الراجع لن تُفعَّل باستمرار إذا كان Meter مستقرًا دائمًا عند القيمة نفسها – فالاستقرار عند قيمة جديدة فقط هو ما يفعّل الاستدعاء الراجع.
- بمجرد تنفيذ دالة الاستدعاء الراجع، نصل إلى بعض الفحوصات الشرطية – وفي هذه الحالة، كل ما علينا فعله هو التحقق مما إذا كانت Meter.value تساوي “0”، مما يشير إلى أن مهارة قد استُخدمت.
- بما أن قيمة Meter هي “1”، فإننا نفشل في هذا الفحص ولن نشغّل تأثير المهارة.
- بعد عدة ثوانٍ، أفعّل المهارة فيختفي الإبراز الأصفر حول الزر.
- قيمة العدّاد الجديدة هي 0، وتُمرَّر إلى صنف Meter الخاص به.
- بمجرد الوصول إلى الاستقرار، يُفعَّل الاستدعاء الراجع ويُجتاز الشرط، فيُشغَّل تأثير المهارة. ويعتمد زمن التأخير كليًا على طول مصفوفة Meter، الذي تحدده عند تعريفه. فالطول الأكبر يعني تأخيرًا أكبر وتشغيلًا خاطئًا أقل، لذا احرص على الاختبار حتى تجد توازنًا جيدًا.
اصطلاحات التسمية
Section titled “اصطلاحات التسمية”يجب أن تكون لـ عدّادات قراءة الشاشة أسماء بسيطة وواضحة ووصفية، تبدأ دائمًا بحرف صغير. فتسمية عدّاد شريط الصحة “healthBar” أمر ممتاز. كما أن تسمية عدّادين “healthBarRed” و**“healthBarGreen”** عندما يتتبعان ألوانًا مختلفة في المنطقة نفسها أمر رائع أيضًا. لكن تسمية عدّاد صغير لا يظهر إلا أثناء تأثير القدرة النهائية لبطل واحد باسم مثل “hrO21_yes” لن تجلب سوى الألم والمعاناة لأي شخص آخر يحاول إصلاح شيفرتك. فمعرفة ما يتتبعه عدّاد صغير سيئ التسمية قد تستغرق حرفيًا ساعة من التحديق في بكسلات فردية إذا لم يحالفك الحظ، لذا لا تفعل ذلك.
يجب أن تبدأ أسماء نسخ صنف Meter بحرف كبير وأن تنتهي بكلمة Meter. فأمثلة مثل “Q_Meter” و**“TookDamageMeter”** و**“TowerDestroyedMeter”** كلها مقبولة تمامًا. ويجب أن تكون هذه الأسماء قابلة للتمييز بوضوح عن العدّادات المُعرَّفة في قسم <head>.
يجب أيضًا تسمية دوال التأثيرات بأبسط طريقة وأكثرها وصفًا ممكن. فبعض الألعاب تحتوي على مئات من هذه الدوال؛ بينما قد يحتوي بعضها الآخر على أقل من عشر. إذا كان لدى عدة أبطال مهارات فريدة، فضمّن اسم البطل كبادئة، مثل “SonaQ” أو “ChamberE” أو “AshUlt”. ففي League of Legends، على سبيل المثال، هناك دوال مثل “DragonEffect” و**“TowerEffect”** و**“Q_Effects”**، والتي تحتوي على شروط متعددة وتستخدمها عدة عدّادات. لذا فإن هذا النوع من التسمية يساعد أيضًا في التحسين من أجل التوسع.
لا تخطئ في كتابة الكلمات. وإذا لم تكن متأكدًا من كيفية كتابة شيء ما، فابحث عنه. يجب أن تكون الأسماء واضحة ومقروءة، بغض النظر عمن يعمل على الشيفرة أو مقدار الوقت الذي مضى. ويساعد تنظيم الأسماء أبجديًا في البحث السريع، خاصةً إذا كنت ستعدّل ذلك القسم كثيرًا. وعلى الرغم من أن هذا المستوى من التنظيم ليس مطلوبًا لتشغيل الشيفرة، فإنه يُحدث فرقًا كبيرًا لمطوري الصيانة لدينا.