L'effetto fade-in nei nostri giochi

Di recente ho cercato di realizzare un effetto Fade-in in uno dei miei giochi, ovvero quel nero che avvolge tutto lo schermo diventando sempre più fitto durante il passaggio da un livello ad un altro.

Ho trovato dozzine di tutorial in giro per la rete, anche esempi al quanto bizzarri e assurdi sul come ottenere questo effetto, e tutti con un punto in comune, l'uso di un'immagine completamente nera da rendere trasparente in un primo tempo e man mano eliminarne la trasparenza gradualmente.
Quello che però nessuno ha proposto, e addirittura in molti hanno reputato "impossibile", è quello di usare una semplice superficie di disegno completamente nera al posto di caricare un'immagine.


Partendo dal presupposto che caricare un'immagine in SDL (ed anche in altre librerie grafiche) vuol dire semplicemente realizzare una superficie di disegno in memoria e riempirla con i dati dell'immagine, perché non evitare il caricamento dell'immagine e l'uso di risorse extra per tale task e creare direttamente la superficie di disegno in memoria?

L'esempio che ho realizzato parte proprio da questo presupposto, avere una superficie di tipo SDL_Surface (che può essere una ALLEGRO_BITMAP o quant'altro la vostra libreria grafica proponga) completamente nera, da mostrare completamente trasparente ad inizio effetto, e gradualmente eliminarne la trasparenza.


void fadein()
{
 if(fade == NULL)
 {
  fade= SDL_CreateRGBSurface(SDL_HWSURFACE,screen->w,screen->h,32,0,0,0,0);
 }
 
 static int alpha=0;
 
 if(alpha<255)
 {
  alpha+=10;
 }
 
 SDL_SetAlpha( fade, SDL_SRCALPHA, alpha );
 SDL_BlitSurface(fade,NULL,screen,NULL);

 if(alpha>=250)
 {
  alpha=0;
      end=1; //Flag fine effetto
}

Partendo dal presupposto che il puntatore fade, sia dichiarato da qualche parte nel vostro codice, da prima ne controlliamo la validità, creando all'occorrenza la superficie necessaria, successivamente teniamo conto dello stato della trasparenza con la variabile alpha.

Se il valore della trasparenza è minore di 255 (valore massimo), lo incrementiamo di 10, successivamente applichiamo la trasparenza alla superficie fade con il valore attuale di alpha e copiamo l'intera superficie su quella dello schermo.

Quando il valore di alpha sarà maggiore di 250, e quindi la superficie fade sarà praticamente nera e priva di trasparenza, resettiamo la variabile statica alpha per futuri utilizzi della funzione e impostiamo un flag generico a 1.

Se ve lo stesse chiedendo, la risposta è si, avremmo potuto usare un ciclo for/while, ma ciò avrebbe monopolizzato l'intero programma per la durata dell'effetto, ed avremmo avuto bisogno di chiamare ad ogni giro la funzione SDL_Flip() ed SDL_Delay(), introducendo così nell'applicazione un'alterazione degli FPS ed una velocità probabilmente non costante su tutti i sistemi.

Nel mio caso la chiamata alla funzione è regolata tramite un semplice timer esterno gestito incrementando una variabile int, e richiamando la funzione ogni qualvolta il valore della variabile sia divisibile per 5.


void doTransition()
{
 static int delay = 0;
 delay++;
 
 if(delay % 5 == 0)
 {
  fadein();
  delay=0;
 }
}

Il timer unito ad un gestore di FPS, mi darà una velocità pressoché costante all'interno del gioco, su svariati tipi di macchine, in ogni caso potete adottare la soluzione che più vi aggrada per regolare l'effetto fade.

In ogni caso qui sotto trovate anche un esempio alternativo con l'uso di un ciclo for:


 int i;
 for(i=0; i<255; i+=5)
 {
  SDL_SetAlpha( fade, SDL_SRCALPHA, i );
  SDL_BlitSurface(fade,NULL,screen,NULL);
  SDL_Flip(screen);
  SDL_Delay(10);
 }

Personalmente per questione di portabilità, performance e integrazione indolore nei vostri progetti, consiglio l'uso della prima versione, e magari all'occorrenza adattarla al vostro codice. Per un esempio funzionante del tutto, potete dare un occhio alla demo RPG, del progetto RetroGear in cui ho implementato con successo il tutto.

Nessun commento :

Posta un commento

Related Posts Plugin for WordPress, Blogger...