Visualizzazione post con etichetta howto. Mostra tutti i post
Visualizzazione post con etichetta howto. Mostra tutti i post

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.

Game Design, questo sconosciuto

Questo mese invece del classico articolo sul game programming, affrontiamo un tema leggermente piu' soft e alla portata di tutti, il Game Design.
Un argomento molto vasto e complesso, ma che cerchero' di spiegare al meglio e nei punti essenziali.

Prima di tutto diciamo che il Game Design e' una parte fondamentale della produzione di un videogioco, in cui vengono gettate le basi ideologiche di esso, come ad esempio la grafica e la storia di gioco per dirne alcune.

Mappe da file

Fino ad ora abbiamo visto come realizzare semplici livelli di gioco basati sui tiles e con una grafica molto semplice.

Riprendendo l'argomento del tile mapping di cui si e' gia' parlato, implementeremo in questo articolo un pratico sistema di gestione delle suddette mappe da file.

Un semplice gioco di Snake

Lo abbiamo visto ovunque, sui cellulari, in regalo con i detersivi, persino nei decoder per digitale terrestre!

Snake e' un giochino tanto scemo quanto elegante allo stesso tempo, realizzarlo non richiede nemmeno troppo lavoro.
Per chi non lo conoscesse (ne dubito fortemente), si tratta di un semplice giochino in cui un serpente muovendosi a intervalli regolari per lo schermo, deve cercare di crescere raggiungendo delle mele piazzate casualmente nel campo di gioco, senza toccare i bordi dello schermo ne se stesso.
Al giocatore viene semplicemente chiesto di dare la direzione di movimento al serpente, cercando di entrare in sincronia con il suo movimento perpetuo, niente di particolare.

Lo scrolling nei nostri giochi

Una caratteristica fondamentale di un buon gioco, e' quella di presentare livelli esplorabili in lungo e in largo, senza costringere il giocatore ad una schermata fissa.

Questa caratteristica e' detta Scroller, per l'appunto scorrimento, si tratta della possibilita' di avere livelli che scorrano orizzontalmente e verticalmente a seconda del movimento del personaggio, permettendo cosi' di avere livelli di gioco non limitati alla dimensione della finestra di gioco.

Facciamo quattro salti

Nei precedenti articoli, abbiamo avuto modo di affrontare diverse tematiche, tra cui quelle relative a giochi basati sui tiles.

In questo articolo riprenderemo il discorso dei tiles, gia' affrontato con un semplice gioco di labirinto, implementando la possibilita' di avere un giocatore che si muova liberamente in un livello molto poco simmetrico e restrittivo, saltando a piacimento.

Animiamo i nostri giochi

Abbiamo imparato come caricare e mostrare porzioni di un immagine su schermo, per i nostri giochi, grazie all'articolo precedente sui font bmp.

Ora parliamo anche di come possiamo animare la grafica dei nostri giochi, dando maggior vita alle nostre creazioni.

Gestire le immagini nei nostri giochi

Fino ad ora, abbiamo utilizzato e imparato a disegnare semplici forme geometriche.
Purtroppo disegnare da codice non e' cosi' comodo come magari puo' esserlo disegnare in appositi programmi come Paint e affini, decisamente meglio preparare la propria immagine e utilizzarla nel programma come parte secondaria.

In questo articolo, voglio introdurre un semplice metodo per gestire le immagini, piu' specificamente dei font disegnati.
Dalla stessa base si potrebbe anche ricavare un comodo metodo per disegnare mappe e quant'altro, il tutto partendo da una semplice immagine BMP popolata di elementi di egual misura.
Piccoli passi per arrivare pian piano a cose sempre piu' complesse, come animazioni e tanto altro.

Crea il tuo Tetris in 30 minuti

Lo scorso mese ho introdotto l'utilizzo delle matrici in un semplice gioco di campo minato, in questo articolo estenderemo quel concetto realizzando un completo clone del tetris.

Realizzare un clone del tetris non e' poi cosi' difficile, una volta capito il concetto lo si realizza molto in fretta, bastano solo 30 minuti per realizzarne un clone completamente funzionante!

Come resuscitare un Nintendo DS

In un precedente articolo, ho parlato di quanto fosse scadente il DS Lite in termini di materiali di fabbricazione, ora invece voglio parlavi di come con una spesa di circa 20 euro, sono riuscito ad aggiustare la console.

Come funziona Campo Minato

Campo minato e' uno dei piu' semplici ed interessanti che ci sia a mio parere.
Ci vogliono circa 10 minuti per realizzarne un clone da console, si puo' imparare molto da un gioco cosi' banale.

Fino ad ora abbiamo visto solo esempi grafici e interattivi che sfruttavano le librerie SDL per l'input e la grafica, ora facciamo un passo indietro.

Linux Game Master 2

Ho gia' avuto modo di parlare di questo fantastico gingillo e di come farlo funzionare su un sistema Linux molto grossolanamente, ironia della sorte vuole che abbia dovuto fare pulizia sul computer e di conseguenza rimboccarmi le maniche.

Dopo un aggiornamento generico del sistema e del kernel ad una versione piu' recente, ho notato con grande stupore dopo qualche tempo che il pad non funzionava come mi aspettassi.

Non sono sceso troppo nei meandri della questione, ma giusto per evitare che anche a voi succeda la stessa cosa, vi do qualche dritta sul come cercare di risolvere eventuali problemi di configurazione di joystick e gampad sul vostro amato sistema Linux.

Ovviamente questa guida non copre ogni singolo modello presente sul mercato e non, ma di certo potra' indirizzarvi nella giusta via per rendere operativo l'apparecchio.

Breakout, come estendere il Pong

In un precedente articolo, abbiamo realizzato un semplice clone del Pong, sfruttando le tecniche apprese.
Da questa base possiamo espandere il gameplay del nostro gioco e realizzare un clone del mitico Breakout, il tutto con pochissime modifiche al codice.
Se non conoscete Breakout, e ne dubito fortemente, e' un gioco sviluppato originariamente da Atari in cui il giocatore muovendo una racchetta sullo schermo doveva far rimbalzare una pallina contro dei mattoni posti nella parte alta di esso per eliminarli tutti.
In questa versione, mi sono ispirato molto all'edizione per atari2600, qualcuno notera' una leggera somiglianza con il classico :]

Il mio primo gioco, il Pong

Retropong, un semplice remake realizzato da Pix3l.Nel precedente articolo, abbiamo trattato l'argomento collisioni semplici ed implementato una sorta di mini gioco che le sfruttasse.

Partendo da quella stessa base, possiamo dare vita ad uno dei piu' classici dei giochi, il Pong!
Per chi non lo conoscesse (mi metto le mani nei capelli!), il Pong e' un semplice simulatore del gioco del Ping Pong.
In questo gioco, due giocatori con relative racchette rappresentate da due semplici rettangoli, devono cercare di mandare una pallina oltre la racchetta dell'avversario per effettuare un punto. Semplice!

Giocare con le collisioni

Molti videogiochi, spesso e volentieri presentano un gameplay basato sul contatto dei vari oggetti di gioco, tipo il contatto tra il giocatore e un muro che ne impedisca l'avanzare.
Per questa ed altre situazioni esistono svariati metodi, ognuno specifico per uno o piu' tipi di situazioni o comunque molto piu' indicati da utilizzare per semplicita' in casi specifici.

Il metodo piu' semplice da utilizzare per gestire delle collisioni e' sicuramente il Rectangular Collision (Collisione rettangolare), conosciuto anche come Box Collision. Il presupposto e' che un qualunque oggetto sullo schermo occupa un'area quadrata o rettangolare nel campo di gioco, a discapito dello sprite (l'immagine dell'oggetto).

Si tiene conto delle coordinate di tre angoli di quest'area, segnati in verde nell'immagine.
Tenendo conto delle loro rispettive posizioni sul piano, si puo' fare un confronto fra le loro coordinate, larghezze e altezze.

Ad esempio, nel primo caso vogliamo controllare un'eventuale collisione nel lato basso del nostro giocatore, questo lato e' definito con la coordinata h1 data dalla somma del valore di Y + H dell'oggetto.
Per prima cosa controlliamo se h1 e' maggiore di y2, se si ha questa condizione successivamente si controlla che la coordinata w1 (data da X + W) sia maggiore di x2 (coordinata dell'altro oggetto).
Avendo entrambe le condizioni soddisfatte come si puo' vedere nell'immagine a destra, si ha una collisione! Se anche una sola delle due condizioni non viene soddisfatta, non si puo' parlare di collisione, questo ragionamento puo' essere applicato con facilita' a tutti e 4 i lati del rettangolo.

A wild Mew appeared

Molti credono sia una leggenda metropolitana, altri ne sono dannatamente convinti ed infine ci sono quelli che dicono di averlo trovato, come il sottoscritto.

Qualche anno fa, parlando con un compagno di scuola e' venuta fuori la storia che sapeva come catturare questo fantomatico pokemon, Gameboy alla mano mi diede una dimostrazione pratica. Pare che il tutto sia frutto di un bug del gioco, e pare che sia possibile sfruttare questo bug con una qualsiasi delle prime tre versioni uscite, io ho testato la cosa sulla versione Yellow.

Il tutto parte da Cerulean City, la citta' con la palestra di Misty per intenderci, nei paraggi della citta' vi e' un giovane allenatore con uno slowpoke. Per la buona riuscita del trucco bisogna evitare la sfida con questo allenatore fino al momento opportuno, inolte bisogna assicurarsi di avere un pokemon con attacco volo e possibilmente una master ball per il finale.

Imparare a disegnare da codice

Molto spesso la grafica dei giochi puo' essere composta da forme geometriche molto semplici, si pensi al Pong, il Breakout e il Tetris. Sono tutti giochi in cui gli elementi grafici sono semplici forme geometriche quali cerchi, rettangoli e quadrati.

Questi elementi grafici sono realizzati dal programma per mezzo di funzioni specifiche, che molto spesso sono la semplice conversione in linguaggio informatico di quelle formulette di geometria analitica che ci insegnavano a scuola.

Come nella realta', per disegnare dobbiamo disporre di una qualche superficie idonea.
Nel precedente tutorial "Datti una mossa" ho introdotto molto velocemente un tipo di superficie idoneo e adatto alla nostra causa, la SDL_Surface. Nello specifico, una superficie all'interno del programma di un videogame e' un'area di memoria (ram o video) grande quanto serve, atta a contenere le informazioni che si visualizzeranno sullo schermo quali pixel, grandezza e altezza.

Un pixel e' un quadratino sullo schermo composto dai tre colori primari, Rosso, Blue e Verde (RGB), che insieme ad altri compone le immagini sullo schermo.
Piu' nello specifico e' una struttura dati, contenente i valori cromatici di base del colore che vogliamo utilizzare nelle gradazioni volute. Si possono avere pixel da 8 a 32 bit, nell'ultimo caso sono divisi in 8 bit per colore primario. I primi 8 sono riservati alla trasparenza dell'immagine, spesso questi bit vengono ignorati.

La superficie e' un buffer (array monodimensionale) contenente svariate informazioni come gia' detto, le piu' importanti oltre i pixel sono la grandezza, l'altezza e il pitch.


La zona azzurra e' la nostra finestra di gioco, la zona arancione e' l'area rimanente dello schermo.
Il driver video in uso sul sistema crea un buffer che usa per la gestione della grafica sullo schermo, grande quanto la larghezza di risoluzione scelta sul sistema, questo buffer e' detto Pitch (in italiano Campo).
Se la risoluzione di sistema e' 800x600 mentre quella della finestra di gioco e' 320x200, la nostra superficie sara' un buffer di ampiezza [320*200] (Larghezza per altezza) ed avra' una sua posizione nel pitch che sara' grande [800*600].

Questi due buffer pur essendo di base array monodimensionali possono essere intesi come tabelle formate da righe e colonne.
Se per esempio volessimo disegnare un pixel alle coordinate (10,20), ci arriveremo sapendo la lunghezza dello schermo in primis. Moltiplicando la lunghezza dello schermo per il numero di colonne, sapremo in che punto nel pitch inizia la riga che vogliamo (scorriamo l'asse Y con 320*20), ora che siamo alla riga voluta ci basta sommare il valore della coordinata X per il numero di bit per pixel (Bpp, scorriamo l'asse X di un numero di byte corretto) per muoverci alla colonna desiderata (320*20+10).

Si puo' riassumere il lavoro teorico in una pratica funzione:

void drawPixel(int x, int y, int color)
{
Uint32 bpp, ofs;

bpp = screen->format->BytesPerPixel;
ofs = screen->pitch*y + x*bpp;

SDL_LockSurface(screen);
memcpy(screen->pixels + ofs, &color, bpp);
SDL_UnlockSurface(screen);
}

Datti una mossa

Nell'ultimo articolo (Tempo di giocare) ho introdotto il concetto di timing nei giochi, in questo articolo voglio introdurre i concetti base del disegno e del movimento di oggetti sullo schermo utilizzando le librerie SDL.

Iniziamo definendo alcune costanti, la larghezza e l'altezza di un nostro ipotetico personaggio sullo schermo:


#define PLAYER_W 10 //Larghezza
#define PLAYER_H 10 //Altezza


In questo caso il nostro personaggio avra' una forma prettamente quadrata, possiamo passare ora alla definizione di una struttura atta a contenere altre informazioni utili.
Creiamo il tipo di dato "Player" ad esempio, nel modo che segue:

struct _Player
{
int x, y; //Coordinate del giocatore
} Player;

Due semplici variabili di tipo integer per gestire separatamente le coordinate del nostro giocatore nella finestra di gioco, queste coordinate saranno incrementate e decrementate dalla pressione dei tasti sulla tastiera.

Sulle coordinate del nostro personaggio verra' disegnata la sua immagine, io per comodita' ho racchiuso il tutto in una funzione:

void DrawRect(int x, int y, int width, int height, int color)
{
rect.x = x;
rect.y = y;
rect.w = width;
rect.h = height;
SDL_FillRect(screen, &rect, color);
}

Questa funzione sfrutta delle strutture gia' dichiarate all'interno delle libreria SDL, tra cui SDL_Surface ed SDL_Rect.
Possiamo dichiarare come globali delle variabili di questo tipo in cima al nostro sorgente:


SDL_Surface *screen; //L'intera area di gioco
SDL_Rect rect; //Un area per il disegno

All'interno della superfice "screen" verranno piazzate come in un collage le varie immagini rappresentate da "rect", il tutto viene effettuato dalla funzione "SDL_FillRect()".
Ora ci bastera' richiamare la funzione DrawRect in modo analogo per disegnare il nostro personaggio sullo schermo:

DrawRect(Player.x, Player.y, PLAYER_W, PLAYER_H, 0xffffff);

L'argomento color e' un semplice valore esadecimale come quelli che si usano nelle pagine html proprio per i colori, in questo caso il nostro personaggio sara' bianco.
Questa funzione verra' richiamata nel main game loop ad ogni ciclo disegnando un rettangolo colorato delle dimensioni specificate alle coordinate "attuali" del giocatore.

Per incrementare e decrementare le coordinate del nostor giocatore scriviamo quindi passo passo la nostra funzione getInput()" che verra' anch'essa usata successivamente nel main game loop:


int getInput()
{
while(SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT ||
(event.type == SDL_KEYDOWN &&
event.key.keysym.sym == SDLK_ESCAPE)) quit = 1; /* Window closed */
}

Questo ciclo esegue un "polling" su una struttura contenente una lista di eventi, ovvero controlla la presenza di un qualunque evento in questa lista, lo esegue e lo toglie dalla coda.
In questo caso controlla se vi e' la volonta' di uscire dal programma controllando l'eventuale pressione del tasto ESC, in caso di positivita' assegna ad una variabile quit il valore di 1, ritroveremo questa variabile piu' avanti nel corso del sorgente.

// Controlla lo stato della tastiera
keystate = SDL_GetKeyState( NULL );
/* Gestisce la pressione dei tasti */
if (keystate[SDLK_LEFT])
Player.x = -1;

if (keystate[SDLK_RIGHT])
Player.x = 1;

if (keystate[SDLK_UP])
Player.y = -1;

if (keystate[SDLK_DOWN])
Player.y = 1;
}

Qui troviamo la variabile "keystate" associata alla funzione SDL_GetKeyState(), questa funzione ci ritorna lo stato di un dato tasto passatogli come argomento.
I valori "SDLK_" sono delle costanti numeriche definite all'interno della libreria SDL riferiti ai valori ASCII dei tasti.
In questo caso viene controllato se un determinato tasto e' premuto, in caso positivo viene incrementata una coordinata del giocatore.
Se gli input qui elencati fossero gestiti nel ciclo di polling come per il tasto ESC, si dovrebbe continuamente ripremere il tasto per incrementare o decrementare le coordinate del giocatore.
Questo metodo di gestire gli input ci permette di avere un controllo "continuo" sulla pressione di un eventuale tasto ad ogni ciclo.

Si noti bene che le variabili keystate, quit ed event non sono definite nella funzione, andranno definita in maniera globale nel modo seguente:

SDL_Event event; // Struttura per eventi
Uint8 *keystate; // Stato della tastiera
int quit=0, repeat;

Ora che abbiamo sia la funzione di disegno che quella per la gestione dei movimenti del nostro giocatore, possiamo assemblare il tutto, inseriamo la nostra funzione di gestione del timing come nel precedente articolo:

int fps_sync ()
{
t = SDL_GetTicks ();
if (t - tl >= frequency)
{
temp = (t - tl) / frequency;
tl += temp * frequency;
return temp;
}
else
{
SDL_Delay (frequency - (t - tl));
tl += frequency;
return 1;
}
}

Ora implementiamo il nostro main game loop in una funzione apposita, successivamente lo richiameremo all'interno di un ciclo.

int mainLoop()
{
//main game loop
while(!quit)
{
repeat = fps_sync ();
for (i = 0; i < repeat ; i++){
getInput();
}

Come gia' visto nell'articolo "Tempo di giocare", limitiamo il numero di azioni di gioco eseguite al secondo. Si nota anche la presenza di un !quit come argomento nel while, finche' quit sara' uguale a 0 il ciclo continuera'.

// Cancella tutto lo schermo di gioco
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
// Disegna il personaggio
DrawRect(Player.x, Player.y, PLAYER_W, PLAYER_H, 0xffffff);
// Aggiorna lo schermo di gioco
SDL_Flip(screen);
}
}

Qui ho usato la funzione SDL_FillRect() per riempire lo schermo di nero, se non si facesse cio' si continuerebbero a vedere i disegni del giocatore nelle varie posizioni passate. Diamo come un colpo di gomma e ridisegniamo successivamente con la funzione DrawRect() il nostro personaggio.
Con SDL_Flip() aggiorniamo interamente lo schermo e lo rendiamo pronto per la visualizzazione, su superfici software in alternativa viene richiamato SDL_UpdateRect().

Ora non ci rimane che popolare la nostra funzione principale e testare il nostro prodotto.

int main()
{
// Inizializziamo la libreria SDL
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
if(screen == NULL)
{
fprintf(stderr, "Can't initialize SDL: %s\n", SDL_GetError());
exit(-1);
}

SDL_WM_SetCaption("Esempio", "Esempio");

// Posizione di partenza del nostro giocatore
Player.x = 64;
Player.y = 64;

//main game loop
mainLoop();
SDL_Quit(); // Terminiamo l'utilizzo della libreria in modo corretto
return 0;
}

Il nostro gioco di base e' pronto, al momento non fa molto a parte muovere un quadrato bianco sullo schermo ma come base per capire i concetti di un videogame va piu' che bene.
Salvate il tutto come game.c e compilate il vostro gioco con gcc -o game game.c -lSDL, oppure impostate il vostro IDE preferito e divertitevi!

Corso di diploma in game programming con XNA

Se abitate nella provincia di Torino, piu' precisamente a Grugliasco, potreste frequentare un fantastico corso di game programming presso l'istituto "Majorana".
Il corso nominato Interactive Graphics & Gaming e' un percorso di studi di scuola superiore con possibilita' di conseguimento di diploma Statale valido a tutti gli effetti.
Il corso presenta nel suo percorso tematiche relative all'utilizzo di Blender, Flash e programmazione di un gioco 2D con XNA per xbox 360.
Il tutto e' disponibile per il download e la consultazione presso la pagina del corso.

Un percorso di studi veramente interessante, mi pare gia' che dalle parti di Roma ci fosse stato qualcosa del genere ma a livello di master universitario. Speriamo che anche in Italia si comincia a dare la giusta importanza a certe cose e non a continuare a vedere l'informatica sempre e solo come un gioco.

Tempo di giocare

Ricordo tempo fa di giochi che se eseguiti su sistemi piu' recenti rispetto al loro anno di nascita' schizzavano a velocita' pazzesche fino ad essere ingiocabili. Il problema risiedeva in una dimenticanza o non curanza dei programmatori di un aspetto molto importante.
Il "timing", in italiano si potrebbe tradurre letteralmente in temporizzazione.

Un qualsiasi programma per quanto semplice sia, verra' eseguito alla velocita' massima consentita dalla macchina e dal sistema ospitante, cio' vuol dire che piu' il nostro pc sara' veloce piu' veloce sara' la nostra applicazione nell'elaborazione dei dati e del suo lavoro.
I giochi essendo di base "applicazioni" come un qualsiasi altro programma, possono essere composti da cicli tipo for o while che verranno eseguiti alla massima velocita' fornita dal processore.

Un gioco tipo ha uno schema di base simile al seguente:

int main()
{
//main game loop
while()
{
//meccanismi di gioco
muoviGiocatore();
aggiornaPunteggio();
Disegna();
}
return 0;
}

Una funzione da cui parte tutto e un ciclo principale detto "main game loop", entro cui il gioco vive.
In questo ciclo vengono ripetute sistematicamente tutte le funzioni relative ai vari aspetti del gioco, tipo il movimento dei personaggi e assegnazione punteggi o il semplice disegno sullo schermo delle immagini.
Nell'entrare nella funzione di "muoviGiocatore()" si effettua un controllo sulla tastiera per controllare se un dato tasto e premuto, nel caso lo sia si muove il nostro personaggio di 1 pixel nella direzione voluta, in caso contrario si continua il ciclo.
Tenendo conto che il ciclo verra' eseguito N volte in base alla velocita' del processore, la pressione del tasto nell'arco di un appena un secondo verra' letta piu' di quanto ci si aspetti. Si vedrebbe il nostro personaggio schizzare letteralmente fuori dal campo di gioco ad una velocita' pari quasi a quella del processore. Impossibile seguire l'azione ad occhio nudo.

Per ovviare a questo semplice problema, si dovrebbe campionare "1 secondo" reale nel programma ed eseguire le azioni una volta per ogni secondo "reale".
I computer gia' a livello di hardware sono dotati di sistemi per il conteggio del tempo, in elettronica tutto cio' e' detto "cloacking" e molti linguaggi di programmazione mettono a disposizione strumenti per campionare il clocking e gestire il tempo.

Esistono funzioni nei linguaggi di programmazione che ci permettono di sapere quanti millisecondi sono passati dall'avio del programma, e' il caso della funzione clock_gettime() presente nella glibc ed utilizzato anche nella libreria SDL per fornire supporto nella gestione del tempo nei nostri giochi. L'esempio qui di seguito utilizza la funzione SDL_GetTicks(), questa funzione ci restituisce il numero di millisecondi passati fin da quanto la libreria e' stata inizializzata. In altre parole ci restituisce il tempo passato in millisecondi dalla partenza del programma

int fps_sync (void)
{
static int t, tl = 0, frequency = 1000 / 100, temp;

t = SDL_GetTicks (); //Tempo trascorso dall'inizio del programma

if (t - tl >= frequency)
{
temp = (t - tl) / frequency;
tl += temp * frequency;
return temp;
}
else
{
sleep (frequency - (t - tl));
tl += frequency;
return 1;
}
}

La funzione qui sopra aggiorna la variabile T (Tempo atutale) con il numero di millisecondi restituiti da SDL_GetTicks() e controlla che tra T e TL (Tick last) vi sia una differenza di almeno 10 millisecondi, rappresentati dalla frequenza e viene restituita una variabile che successivamente verra' usata nel main game loop.
Se non vi e' questa differenza tra T e TL, viene messo a dormire il processo sulla macchina per un tempo variabile tra 0 e 10 millisecondi e succesivamente si incrementa TL di 10 millisecondi in modo da recuperare il conteggio perduto nello sleep.

Questa funzione torna utile nel nostro main game loop in quanto ci permettera' di limitare l'uso della cpu in modo dinamico.

while()
{
repeat = fps_sync ();

for (i = 0; i < repeat; i ++)
{
muoviGiocatore();
aggiornaPunteggio();
}
Disegna();
}

In un lasso di tempo (frequenza) verranno eseguite le azioni di gioco all'interno di un ciclo limitato dalla variabile temp rilasciata dalla funzione fps_sync().
Il tutto in modo dinamico, garantendo la stessa velocita' su diversi computer a discapito della velocita' del processore.
Questo modo di gestire gli FPS rispetto a molti altri vanta la possibilita' di poter limitare solo alcune parti del programma garantendo allo stesso tempo la massima velocita' nella resa grafica, a differenza di molti altri metodi usati da molti che mettono a dormire l'intero programma indistintamente.

Questo articolo prende spunto dall'articolo presentato dal sito di Loser Juegos da cui si trova ben poco riguardo i dettagli di funzionamento dell'algoritmo intero, qui ho provato a spiegarlo ed esporlo al meglio.
Se non vi sara' chiaro al primo colpo, non vi scoraggiate, provate a pacioccare un po' con le varie variabili e vedere i vari effetti sul gioco.