Snippets
Esta seção inclui três snippets de código úteis para seus LightScripts: medidores, manipuladores de estado e manipuladores de efeitos.
O Meter
Seção intitulada “O Meter”Como continuação da seção anterior, a classe Meter foi projetada para ajudar a rastrear mudanças significativas em dados de medição instáveis. Pense nela como um pedal de freio para o seu código — fornecendo estabilidade mesmo em zonas complexas. Cada medidor mantém um array personalizável de valores coletados durante cada execução da sua função update. Quando todos os valores nesse array são iguais (ou seja, os dados estão “estáveis”), o medidor atualiza seu valor e aciona uma função de callback vinculada para ativar um efeito.
| Método | Descrição |
|---|---|
| Meter(size, callback) | O construtor aceita tanto um size quanto um callback.\n\n\n\nsize - o número de vezes que um valor idêntico deve estar presente para que o valor do medidor seja considerado “estável” o suficiente para ser processado. Valores maiores resultam em mais precisão; valores menores resultam em menos latência.\n\n\ncallback - uma função a ser chamada quando o valor do medidor for estável e tiver mudado. |
| Meter.setValue(value) | Você deve chamar setValue(value) a cada frame, ou sempre que novos dados brutos para este medidor estiverem disponíveis. |
O processo de coleta de dados da tela geralmente deve seguir esta estrutura:
- O valor engine.vision.meter é atualizado com base em novos dados da tela.
- Dentro da função update, Meter.setValue(engine.vision.meter) é chamado para registrar o novo valor.
- O Meter verifica seu array interno para ver se todos os valores são idênticos. Se forem, atualiza seu próprio estado e executa a função de callback atribuída.
- A função de callback então avalia condições específicas usando as variáveis do Meter e executa seu código se essas condições forem atendidas.
NOTA IMPORTANTE:
Não pule o uso de callbacks. Como a função update é executada continuamente, ela deve permanecer o mais eficiente possível. Seu papel principal deve ser atualizar os valores do Meter. Evite encadear condicionais dentro do update para verificar medidores e acionar efeitos, pois isso leva a verificações desnecessárias a cada ciclo. Em vez disso, defina seus efeitos em funções separadas e passe-as para o seu Meter como callbacks.
Variáveis do Meter
Seção intitulada “Variáveis do Meter”Quando estável, o Meter fornecerá alguns valores à sua função de callback:
| Variáveis | Descrição |
|---|---|
| Meter.value | O valor atual do medidor. |
| Meter.increased | Um booleano que indica se o valor aumentou ou não nesta atualização |
| Meter.decreased | Um booleano que indica se o valor diminuiu ou não nesta atualização |
| Meter.diff | O valor absoluto da mudança que o medidor experimentou nesta atualização. |
Exemplo do Meter
Seção intitulada “Exemplo do Meter”Aqui está uma configuração básica de medidor único, incluindo o código da classe 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(); } }; }O Manipulador de Estado
Seção intitulada “O Manipulador de Estado”O manipulador de estado é uma pilha de efeitos que lida especificamente com efeitos que têm prioridade sobre todos os outros. Se você quiser que uma grande animação dominante seja executada até o fim sem interrupção, insira-a no manipulador de estado.
| Método | Descrição |
|---|---|
| StateHandler() | O construtor não requer argumentos. |
| StateHandler.push(new State()) | Você pode empurrar um novo estado para a pilha usando push, e o processamento começará imediatamente. |
| StateHandler.pop() | Remove o estado atual da pilha e começa a processar o estado anterior. |
Qualquer objeto inserido no manipulador de estado deve implementar Process(). A função Process determina o tempo de vida de um efeito no manipulador.
Exemplo do Manipulador de Estado
Seção intitulada “Exemplo do Manipulador de Estado”O seguinte mostra um manipulador de estado básico, além da função Process que deve ser executada dentro das suas funções de efeito:
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();};O Manipulador de Efeitos
Seção intitulada “O Manipulador de Efeitos”Os manipuladores de efeitos são excelentes para armazenar e renderizar efeitos menores e mais leves todos juntos. Cada efeito no manipulador será avaliado a cada chamada de update e é removido quando atinge o fim do seu tempo de vida.
O manipulador de efeitos é apenas um array para armazenar efeitos. Só isso.
// Declare effects arraylet effects = [];
// (Not shown) Evaluate Meter, callback function pushes effect into effects arrayeffects.push(new SpecialEffect());
// Iterate through the array, animating a frame for each effectfor (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); }}AVISO: EFEITO VS. ESTADO
Seção intitulada “AVISO: EFEITO VS. ESTADO”O manipulador de estado é especificamente para efeitos prioritários, o que significa que precisamos dar a ele prioridade durante a execução. Na sua função update, processe o manipulador de efeitos PRIMEIRO e depois o manipulador de estado. Isso desenhará o efeito de estado sobre os itens do manipulador de efeitos.
Assim:
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();}Guia de Captura de Dados USB
Seção intitulada “Guia de Captura de Dados USB”Salvar dados USB é um processo direto, mas os drivers usados por esses programas são conhecidos por conflitar com certos sistemas, às vezes desabilitando portas USB até que o software seja removido. A correção comum é desativar o ‘Secure Boot’ nas configurações do BIOS/UEFI. Antes de prosseguir, é altamente recomendável ter uma restauração do sistema disponível em um pendrive ou uma forma de acessar remotamente seu computador que não dependa de entrada do usuário no boot. Isso é importante caso desativar o Secure Boot não resolva o problema e você não consiga acessar o sistema para desinstalar o programa. Nesses casos, uma atualização do Windows pode ser necessária para remover todos os programas instalados enquanto mantém seus arquivos pessoais. Você está fazendo isso por sua conta e risco. Se não se sentir confortável tentando, solicite seu dispositivo aqui. Não use um notebook para este processo.
Uma vez instalado, o processo é simples e capturará todos os dados passando pelos seus dispositivos USB. Não digite nenhuma informação sensível durante a captura se planeja compartilhar os dados, pois as teclas pressionadas estão incluídas na gravação. Dois programas de terceiros que podem ser usados são Usblyzer (avaliação gratuita) e Wireshark (gratuito). Ambos funcionam, mas se você escolher o Wireshark, certifique-se de que USBPcap esteja selecionado.
Confira nossa próxima página, Callbacks, para mais detalhes sobre como construir callbacks de medidores e funções de efeito.