Pular para o conteúdo

Snippets

Esta secção inclui três snippets de código úteis para os seus LightScripts: medidores, manipuladores de estado e manipuladores de efeitos.

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étodoDescriçã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:

  1. O valor engine.vision.meter é atualizado com base em novos dados do ecrã.
  2. Dentro da função update, Meter.setValue(engine.vision.meter) é chamado para registar o novo valor.
  3. 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.
  4. 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.

Quando estável, o Meter fornecerá alguns valores à sua função de callback:

VariáveisDescrição
Meter.valueO valor atual do medidor.
Meter.increasedUm booleano que indica se o valor aumentou ou não nesta atualização
Meter.decreasedUm booleano que indica se o valor diminuiu ou não nesta atualização
Meter.diffO valor absoluto da mudança que o medidor experimentou nesta atualização.

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 é 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étodoDescriçã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.

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

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

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

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.