跳转到内容

代码片段

本节包含三个用于 LightScripts 的有用代码片段:计量器状态处理程序效果处理程序

作为上一节的延续,Meter 类旨在帮助跟踪不稳定计量数据中有意义的变化。可以将其视为代码的刹车踏板——即使在复杂区域也能提供稳定性。每个计量器保存一个可自定义的值数组,在更新函数的每次运行期间收集。当该数组中的所有值都相同(即数据”稳定”)时,计量器更新其值并触发链接的回调函数以激活效果。

方法描述
Meter(size, callback)构造函数接受 sizecallback。\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 值。避免在 update 中链接条件来检查计量器和触发效果,因为这会导致每个周期进行不必要的检查。相反,在单独的函数中定义您的效果并将它们作为回调传入您的 Meter

稳定后,Meter 将为其回调函数提供一些值:

变量描述
Meter.value计量器的当前值。
Meter.increased一个布尔值,指示本次更新中值是否增加
Meter.decreased一个布尔值,指示本次更新中值是否减少
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>
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();
};

效果处理程序非常适合一起存储和渲染更小、更轻的效果。处理程序中的每个效果将在每次更新调用时被评估,当它们到达生命周期末尾时被删除。

效果处理程序只是一个用于存储效果的数组。就这样。

// 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);
}
}

状态管理器专门用于优先效果,这意味着我们必须在执行期间给予它优先权。在您的更新函数中,处理效果处理程序,然后处理状态处理程序。这将在效果处理程序的项目之上绘制状态效果。

像这样:

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 端口。常见的解决方法是在 BIOS/UEFI 设置中禁用**“安全启动”**。在继续之前,强烈建议在闪存驱动器上准备系统还原,或者有一种不依赖于启动时用户输入的方式远程访问您的计算机。这在禁用安全启动不能解决问题且您无法访问系统卸载程序的情况下很重要。在这种情况下,可能需要 Windows 刷新以在保留您的个人文件的同时删除所有已安装的程序。您需自行承担风险。如果您不愿意尝试,请在此处请求您的设备。请勿在笔记本电脑系统上使用此过程。

安装后,该过程很简单,将捕获通过 USB 设备传递的所有数据。如果您计划共享数据,请在捕获时不要键入任何敏感信息,因为录制中包含键击。可以使用的两个第三方程序是 Usblyzer(免费试用)和 Wireshark(免费)。两者都有效,但如果您选择 Wireshark,请确保选择了 USBPcap

查看我们的下一页回调,了解有关构建计量器回调和效果函数的更多详细信息。