Snippets
Esta secção inclui três snippets de código úteis para os seus LightScripts: medidores, manipuladores de estado e manipuladores de efeitos.
O Meter
Seção intitulada “O Meter”Como continuação da secção anterior, a classe Meter foi concebida para ajudar a rastrear mudanças significativas em dados de medição instáveis. Pense nela como um pedal de travão para o seu código — fornecendo estabilidade mesmo em zonas complexas. Cada medidor mantém um array personalizável de valores recolhidos 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 o seu valor e aciona uma função de callback associada para ativar um efeito.
| Método | Descrição |
|---|---|
| Meter(size, callback) | O construtor aceita tanto um size como 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) | Deve chamar setValue(value) a cada frame, ou sempre que novos dados brutos para este medidor estiverem disponíveis. |
O processo de recolha de dados do ecrã geralmente deve seguir esta estrutura:
- O valor engine.vision.meter é atualizado com base em novos dados do ecrã.
- Dentro da função update, Meter.setValue(engine.vision.meter) é chamado para registar o novo valor.
- O Meter verifica o seu array interno para ver se todos os valores são idênticos. Se forem, atualiza o 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 o seu código se essas condições forem satisfeitas.
NOTA IMPORTANTE:
Não ignore o uso de callbacks. Como a função update é executada continuamente, deve permanecer o mais eficiente possível. O 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 os 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>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 trata especificamente de efeitos que têm prioridade sobre todos os outros. Se quiser que uma grande animação dominante seja executada até ao 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()) | 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 de lhe dar prioridade durante a execução. Na sua função update, processe o manipulador de efeitos PRIMEIRO e depois o manipulador de estado. Isto 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”Guardar dados USB é um processo direto, mas os drivers usados por esses programas são conhecidos por conflituar com certos sistemas, às vezes desativando portas USB até que o software seja removido. A correção comum é desativar o ‘Secure Boot’ nas definições do BIOS/UEFI. Antes de prosseguir, é altamente recomendável ter uma restauração do sistema disponível numa pen USB ou uma forma de aceder remotamente ao seu computador que não dependa de entrada do utilizador no arranque. Isto é importante caso desativar o Secure Boot não resolva o problema e não consiga aceder ao 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 os seus ficheiros pessoais. Está a fazer isto por sua conta e risco. Se não se sentir confortável a tentar, solicite o seu dispositivo aqui. Não use um portátil para este processo.
Uma vez instalado, o processo é simples e capturará todos os dados a passar pelos seus dispositivos USB. Não escreva nenhuma informação sensível durante a captura se planeia partilhar os dados, pois as teclas premidas 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 escolher o Wireshark, certifique-se de que USBPcap está selecionado.
Consulte a nossa próxima página, Callbacks, para mais detalhes sobre como construir callbacks de medidores e funções de efeito.