تخطَّ إلى المحتوى

مقتطفات برمجية

يتضمن هذا القسم ثلاثة مقتطفات برمجية مفيدة لملفات LightScripts الخاصة بك: المقاييس، ومعالجات الحالة، ومعالجات التأثيرات.

استكمالًا للقسم السابق، صُممت الفئة Meter لمساعدتك على تتبّع التغيرات المهمة في بيانات المقاييس غير المستقرة. يمكنك اعتبارها بمثابة دواسة فرامل لشيفرتك، إذ توفر الاستقرار حتى في المناطق المعقدة. يحتفظ كل مقياس بمصفوفة قابلة للتخصيص من القيم التي تُجمع في كل مرة تُنفَّذ فيها دالة التحديث. وعندما تتطابق جميع القيم في تلك المصفوفة (أي عندما تكون البيانات “مستقرة”)، يحدّث المقياس قيمته ويستدعي دالة رد النداء (callback) المرتبطة به لتفعيل تأثير ما.

الدالةالوصف
Meter(size, callback)يقبل المُنشئ كلًّا من size وcallback.\n\n\n\nsize - عدد المرات التي يجب أن تتكرر فيها قيمة متطابقة حتى تُعتبر قيمة المقياس ‘مستقرة’ بما يكفي لمعالجتها. القيم الأعلى تمنح دقة أكبر، والقيم الأقل تقلل زمن الاستجابة.\n\n\ncallback - دالة تُستدعى عندما تكون قيمة المقياس مستقرة وقد تغيّرت.
Meter.setValue(value)يجب عليك استدعاء setValue(value) في كل إطار، أو في أي وقت تتوفر فيه بيانات خام جديدة لهذا المقياس.

يجب أن تتبع عملية جمع بيانات الشاشة عمومًا البنية التالية:

  1. تتحدّث قيمة engine.vision.meter بناءً على بيانات جديدة من الشاشة.
  2. داخل دالة التحديث، تُستدعى Meter.setValue(engine.vision.meter) لتسجيل القيمة الجديدة.
  3. يتحقق Meter من مصفوفته الداخلية لمعرفة ما إذا كانت جميع القيم متطابقة. فإذا كانت كذلك، يحدّث حالته الخاصة ويشغّل دالة رد النداء المخصصة له.
  4. تقيّم دالة رد النداء بعد ذلك شروطًا محددة باستخدام متغيرات Meter، وتنفّذ شيفرتها إذا تحققت تلك الشروط.

ملاحظة مهمة:

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

عندما يستقر المقياس، يوفّر بعض القيم لدالة رد النداء الخاصة به:

المتغيراتالوصف
Meter.valueالقيمة الحالية للمقياس.
Meter.increasedقيمة منطقية (boolean) تشير إلى ما إذا كانت القيمة قد ازدادت في هذا التحديث أم لا
Meter.decreasedقيمة منطقية (boolean) تشير إلى ما إذا كانت القيمة قد انخفضت في هذا التحديث أم لا
Meter.diffالقيمة المطلقة للتغيّر الذي طرأ على المقياس في هذا التحديث.

إليك إعدادًا أساسيًا لمقياس واحد، بما في ذلك شيفرة الفئة Meter:

<head>
<title>Meter Example</title>
<meta description="Step-by-step metering" />
<meta meter="health" tags="vlc,fortnite" x= ".05" y=".9" width=".189" h="70-140" s="40-100" l="40-100" type="linear" />
</head>
<body style="margin: 0; padding: 0; background: #000;">
<canvas id="exCanvas" width="320" height="200"></canvas>
</body>
<script>
var c = document.getElementById("exCanvas");
var ctx = c.getContext("2d");
// Initialize meter
var healthMeter = new Meter(5, healthEffect);
function update(){
// Update Meter values
healthMeter.setValue(engine.vision.health);
window.requestAnimationFrame(update);
}
function healthEffect(){
if(healthMeter.increased){
// Trigger effect
} else if (healthMeter.value == 0){
// Trigger effect
} else if (healthMeter.diff > .3){
// Trigger effect
}
}
function Meter(size, callback) {
this.size = size;
this.value = 0;
this.diff = 0;
this.increased = false;
this.decreased = false;
var values = [];
this.setValue = function (updatedValue) {
// Add and shift.
values.push(updatedValue);
if (values.length > this.size) {
values.shift();
}
// Exit early if we don't have a long-term match.
for (var i = 0; i < values.length - 1; i++) {
if (values[i] !== values[i + 1]) return;
}
// We got here, so we've got a matching value collection. Set variables and execute callback.
if (this.value !== values[0]) {
this.diff = Math.abs(this.value - values[0]);
this.increased = this.value < values[0];
this.decreased = this.value > values[0];
this.value = values[0];
callback();
}
};
}
window.requestAnimationFrame(update);
</script>
<head>
<title>Meter Example</title>
<meta description="Step-by-step metering" />
<meta meter="health" tags="vlc,fortnite" x= ".05" y=".9" width=".189" h="70-140" s="40-100" l="40-100" type="linear" />
</head>
<body style="margin: 0; padding: 0; background: #000;">
<canvas id="exCanvas" width="320" height="200"></canvas>
</body>
<script>
var c = document.getElementById("exCanvas");
var ctx = c.getContext("2d");
// Initialize meter
var healthMeter = new Meter(5, healthEffect);
function update(){
// Update Meter values
healthMeter.setValue(engine.vision.health);
window.requestAnimationFrame(update);
}
function healthEffect(){
if(healthMeter.increased){
// Trigger effect
} else if (healthMeter.value == 0){
// Trigger effect
} else if (healthMeter.diff > .3){
// Trigger effect
}
}
function Meter(size, callback) {
this.size = size;
this.value = 0;
this.diff = 0;
this.increased = false;
this.decreased = false;
var values = [];
this.setValue = function (updatedValue) {
// Add and shift.
values.push(updatedValue);
if (values.length > this.size) {
values.shift();
}
// Exit early if we don't have a long-term match.
for (var i = 0; i < values.length - 1; i++) {
if (values[i] !== values[i + 1]) return;
}
// We got here, so we've got a matching value collection. Set variables and execute callback.
if (this.value !== values[0]) {
this.diff = Math.abs(this.value - values[0]);
this.increased = this.value < values[0];
this.decreased = this.value > values[0];
this.value = values[0];
callback();
}
};
}
window.requestAnimationFrame(update);
</script>
function Meter(size, callback) {
this.size = size;
this.value = 0;
this.diff = 0;
this.increased = false;
this.decreased = false;
var values = [];
this.setValue = function (updatedValue) {
// Add and shift.
values.push(updatedValue);
if (values.length > this.size) {
values.shift();
}
// Exit early if we don't have a long-term match.
for (var i = 0; i < values.length - 1; i++) {
if (values[i] !== values[i + 1]) return;
}
// We got here, so we've got a matching value collection. Set variables and execute callback.
if (this.value !== values[0]) {
this.diff = Math.abs(this.value - values[0]);
this.increased = this.value < values[0];
this.decreased = this.value > values[0];
this.value = values[0];
callback();
}
};
}

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

الدالةالوصف
StateHandler()لا يتطلب المُنشئ أي وسائط.
StateHandler.push(new State())يمكنك إضافة حالة جديدة إلى مكدّس الحالات باستخدام push، وستبدأ المعالجة فورًا.
StateHandler.pop()يزيل الحالة الحالية من مكدّس الحالات، ويبدأ معالجة الحالة السابقة في المكدّس.

أي كائن يُضاف إلى معالج الحالة يجب أن يطبّق الدالة Process(). تحدد الدالة Process عمر التأثير داخل المعالج.

يوضح ما يلي معالج حالة أساسيًا، بالإضافة إلى الدالة Process التي يجب أن تعمل داخل دوال التأثيرات الخاصة بك:

var stateHdlr = new StateHandler();
function StateHandler() {
var stack = [];
var state = null;
// Set current state to the top item in the stack
var updateState = function () {
if (stack.length > 0) {
state = stack[stack.length - 1];
} else {
state = null;
}
};
// Allows dev to add effect to state handler
this.Push = function (newState) {
stack.push(newState);
updateState();
};
// Allows dev to remove effect from handler
this.Pop = function () {
stack.pop();
updateState();
};
// Call the Process function of the current state (effect)
this.Process = function () {
if (state != null) {
state.Process();
}
};
}
function update(){
stateHdlr.Process();
}
this.start = new Date.now()
this.elapsed = 0;
this.duration = 1000;
this.Process = function () {
// Evaluate time since effect start
this.elapsed = new Date.now() - this.start;
// If the effect has reached its lifespan, remove it from the state handler
if (this.elapsed > this.duration) {
stateMgr.Pop();
}
// If the effect is still running, call the effect draw function
this.Draw();
};

معالج التأثيرات (Effect Handler)

Section titled “معالج التأثيرات (Effect Handler)”

تُعد معالجات التأثيرات ممتازة لتخزين التأثيرات الأصغر والأخف وعرضها معًا. يُقيَّم كل تأثير في المعالج عند كل استدعاء للتحديث، ويُزال عندما يصل إلى نهاية عمره.

معالج التأثيرات مجرد مصفوفة لتخزين التأثيرات. هذا كل ما في الأمر.

// Declare effects array
let effects = [];
// (Not shown) Evaluate Meter, callback function pushes effect into effects array
effects.push(new SpecialEffect());
// Iterate through the array, animating a frame for each effect
for (let i = 0; i < effects.length; i++) {
effects[i].draw();
// Remove effect if the lifetime has ended
if (effects[i].lifetime <= 0) {
effects.splice(i, 1);
}
}

تحذير: التأثير مقابل الحالة

Section titled “تحذير: التأثير مقابل الحالة”

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

على النحو التالي:

function update(){
// Evaluate effects handler
for (let i = 0; i < effects.length; i++) {
effects[i].draw();
if (effects[i].lifetime <= 0) {
effects.splice(i, 1);
}
}
// THEN evaluate state handler
stateMgr.Process();
}

حفظ بيانات USB عملية بسيطة، لكن من المعروف أن برامج التشغيل التي تستخدمها هذه البرامج تتعارض مع بعض الأنظمة، وقد تعطّل أحيانًا منافذ USB إلى أن يُزال البرنامج. الحل الشائع هو تعطيل ‘Secure Boot’ (التمهيد الآمن) في إعدادات BIOS/UEFI. قبل المتابعة، يُنصح بشدة بأن تجهّز نسخة لاستعادة النظام على محرك أقراص محمول، أو طريقة للوصول إلى حاسوبك عن بُعد لا تعتمد على إدخال المستخدم أثناء الإقلاع. هذا مهم في حال لم يؤدِّ تعطيل التمهيد الآمن إلى حل المشكلة ولم تتمكن من الوصول إلى النظام لإلغاء تثبيت البرنامج. في مثل هذه الحالات، قد تحتاج إلى تحديث Windows لإزالة جميع البرامج المثبتة مع الاحتفاظ بملفاتك الشخصية. أنت تقوم بذلك على مسؤوليتك الخاصة. إذا لم تكن مرتاحًا لتجربة ذلك، فاطلب دعم جهازك من هنا. لا تستخدم حاسوبًا محمولًا لهذه العملية.

بعد التثبيت، تصبح العملية بسيطة وتلتقط جميع البيانات التي تمر عبر أجهزة USB لديك. لا تكتب أي معلومات حساسة أثناء الالتقاط إذا كنت تخطط لمشاركة البيانات، لأن ضغطات المفاتيح تُضمَّن في التسجيل. من البرامج الخارجية التي يمكن استخدامها برنامجا Usblyzer (نسخة تجريبية مجانية) وWireshark (مجاني). كلاهما يعمل، لكن إذا اخترت Wireshark، فتأكد من تحديد USBPcap.

اطّلع على صفحتنا التالية، دوال رد النداء، لمزيد من التفاصيل حول إنشاء دوال رد النداء للمقاييس ودوال التأثيرات.