Durante lo sviluppo di un gioco, potresti trovare valori troppo rumorosi per le tue esigenze. Il caso comune è l'input dell'utente analogico (mouse, touch o joystick), ma il rumore potrebbe provenire anche dai sistemi di gioco, come la fisica o il comportamento dello sterzo, in cui soluzioni approssimative o cambiamenti non contigui producono rumore. In questo tutorial imparerai un modo semplice per attenuare quei valori rumorosi. Gli esempi di codice sono in C #, ma sono facili da adattare a qualsiasi altra lingua.
Il modo più semplice per attenuare il valore variabile consiste nel prendere un numero di campioni passati e convertirli nella media. Useremo un numero costante di campioni, quindi una matrice di dimensioni fisse è una scelta naturale ed efficiente per la memorizzazione di questi. Quindi, per evitare di spostare quell'array, useremo un trucco: la struttura dei dati del "ring buffer".
Iniziamo definendo i dati da memorizzare nella nostra classe di utilità:
public class SlidingAverage float [] buffer; somma mobile; int lastIndex; public SlidingAverage (int num_samples, float initial_value) buffer = new float [num_samples]; lastIndex = 0; reset (valore_iniziale);
Qui abbiamo il nostro buffer di campioni, la somma dei campioni e l'ultimo indice usato nella matrice. Il costruttore alloca l'array di buffer, set lastIndex
a zero e chiama il reset()
metodo:
public void reset (valore float) sum = value * buffer.Length; per (int i = 0; iQui, riempiamo il buffer con il valore iniziale specificato e impostiamo la somma per abbinarla. Questo metodo può essere utilizzato ogni volta che è necessario riavviare il livellamento per evitare effetti di memoria dei campioni precedenti.
Ora, il metodo principale: spingere un nuovo valore nel nostro buffer circolare:
public void pushValue (float value) sum- = buffer [lastIndex]; // sottrarre il campione più vecchio dalla somma somma + = valore; // aggiungi il nuovo buffer di esempio [lastIndex] = valore; // memorizza il nuovo esempio // fa avanzare l'indice e lo avvolge attorno a lastIndex + = 1; if (lastIndex> = buffer.Length) lastIndex = 0;Qui, sovrascriviamo il campione più vecchio in
lastIndex
con quello nuovo, ma prima aggiustiamo la somma sottraendo il vecchio campione e aggiungendo quello nuovo.Quindi, avanziamo
lastIndex
in modo che punti al campione successivo (che è ora il più vecchio). Ma se solo avanziamolastIndex
esauriremo l'array in pochissimo tempo, quindi quando uscirà dalla matrice, lo avvolgeremo intorno a zero.Ecco perché è a squillare buffer. È essenzialmente lo stesso di spostare l'array e accodare il nuovo campione, ma molto più velocemente poiché invece di copiare i valori in memoria, basta avvolgere l'indice.
Ora, l'unica cosa che manca è ottenere il valore corretto:
public float getSmoothedValue () return sum / buffer.Length;Questo è tutto; dividiamo semplicemente la somma per il numero di campioni per ottenere la media. Se non archiviamo la somma, dovremmo calcolarla qui dai campioni.
risultati
Diamo un'occhiata ai risultati:
La linea nera è il segnale originale (onda sinusoidale con qualche rumore), la linea bianca viene attenuata con due campioni e la linea rossa viene attenuata con quattro campioni.Come vedi, anche alcuni campioni la rendono notevolmente più liscia, ma più campioni utilizziamo, più è in ritardo rispetto al segnale originale. Questo è previsto dal momento che utilizziamo solo esempi precedenti nel caso in tempo reale. Se sei in fase di post-elaborazione, puoi spostare i valori livellati in tempo per evitare il ritardo.
Conclusione
Ora disponi di una semplice classe di utilità che può essere utilizzata per smussare qualsiasi valore di ingresso rumoroso, sia che si tratti di input dell'utente, traccia di un oggetto o indicatore di velocità.
Può essere ulteriormente migliorato aggiungendo pesi campione (abbiamo usato una media semplice con una costante
1 / N
peso), ma questo è un argomento enorme, l'elaborazione del segnale digitale, e meglio lasciarlo a un futuro tutorial!