Dans un premier temps, nous allons apprendre à utiliser 2 fonctions très simples :
- SDL_Delay : permet de mettre en pause le programme un certain nombre de millisecondes.
- SDL_GetTicks : retourne le nombre de millisecondes écoulées depuis le lancement du programme.
Ces 2 fonctions sont peut-être super simples comme nous allons le voir, mais bien savoir les utiliser n'est pas évident... alors ouvrez grand vos
oreilles yeux
SDL_Delay
Comme je l'ai précédemment dit, cette fonction effectue une pause sur le programme durant un certain temps. Pendant que le programme est en pause, on dit qu'il dort ("sleep" en anglais) : il n'utilise pas le processeur.
SDL_Delay peut donc être utile pour réduire l'utilisation du processeur. Notez que j'abrègerai processeur par
CPU désormais, ce qui signifie Central Processing Unit, soit "
Unité centrale de calcul".
Grâce à SDL_Delay, vous pourrez rendre votre programme moins gourmand en ressources processeur. Il fera donc moins "ramer" votre PC si SDL_Delay est utilisée intelligemment.
Bien, revenons à la fonction qui nous intéresse. Son prototype est d'une simplicité affligeante :
Code : C1 | void SDL_Delay(Uint32 ms);
|
En clair, vous envoyez à la fonction le nombre de millisecondes pendant lesquelles votre programme doit "dormir". C'est une simple mise en pause.
Par exemple, si vous voulez que votre programme se mette en pause 1 seconde, vous devrez taper :
Code : C
N'oubliez pas que ce sont des millisecondes :
1000 millisecondes = 1 seconde
500 millisecondes = 1/2 seconde
250 millisecondes = 1/4 seconde
etc etc.
Attention : vous ne pouvez rien faire dans votre programme pendant qu'il est en pause ! Un programme qui "dort" ne peut rien faire puisqu'il n'est pas actif pour l'ordinateur.
Le problème de la granularité du temps
Non rassurez-vous, je ne vais pas vous faire un traité de physique quantique au beau milieu d'un chapitre SDL

Toutefois, il y a quelque chose que j'estime que vous devez savoir : SDL_Delay n'est pas une fonction "parfaite". Et ce n'est pas sa faute, c'est la faute à votre OS (comme Windows).
Qu'est-ce que vient faire l'OS là-dedans ?
Oh mais l'OS a tout à faire là-dedans :
c'est lui qui contrôle les programmes qui tournent !
Votre programme va donc dire à l'OS : "
Je dors, réveille-moi dans 1 seconde". Mais l'OS ne va pas forcément le réveiller au bout d'une seconde exactement.
En effet, il aura peut-être un peu de retard (un retard de 10ms en moyenne environ, ça dépend des PC). Pourquoi ? Parce que votre CPU ne peut travailler que sur un programme à la fois. Le rôle de l'OS est de dire au CPU ce sur quoi il doit travailler : "
Alors, pendant 40ms tu vas travailler sur firefox.exe, puis pendant 110ms tu vas travailler sur explorer.exe, et ensuite pendant 80ms tu vas travailler sur programme_sdl.exe, puis tu vas retravailler sur firefox.exe pendant 65ms" etc etc...
L'OS est le véritable chef d'orchestre de l'ordinateur !
Maintenant, imaginez qu'au bout d'une seconde un autre programme soit encore en train de travailler : il faudra qu'il ait fini de travailler pour que votre programme puisse "reprendre la main" comme on dit, c'est-à-dire être traité à nouveau par le CPU.
Tout ça pour dire quoi ?

Ooops, excusez-moi j'étais en train de dériver

En gros, j'essayais de vous expliquer que votre CPU ne pouvait pas gérer plus d'un programme à la fois. Pour donner l'impression que l'on peut faire tourner plusieurs programmes en même temps sur un ordinateur, l'OS "découpe" le temps et autorise les programmes à travailler au tour par tour.
Or, cette gestion des programmes est très complexe et on ne peut donc pas avoir la garantie que notre programme sera réveillé au bout d'une seconde exactement.
Toutefois, ça dépend des PC comme je vous l'ai dit plus haut. Chez moi, la fonction SDL_Delay est assez précise.
En résumé : SDL_Delay c'est cool, mais ne lui faites pas trop confiance. Elle ne mettra pas en pause votre programme pendant le temps
exact que vous indiquez.
Ce n'est pas parce que la fonction est mal codée, c'est parce que le fonctionnement d'un ordinateur est très complexe et ne permet pas d'être très précis à ce niveau.
SDL_GetTicks
Cette fonction renvoie le nombre de millisecondes écoulées depuis le lancement du programme.
Hein ? Mais on s'en fout de savoir ça

Au contraire, c'est un indicateur de temps indispensable. Cela vous permet de vous
repérer dans le temps, vous allez voir !
Voici le prototype :
Code : C1 | Uint32 SDL_GetTicks(void);
|
La fonction n'attend aucun paramètre, elle renvoie juste le nombre de millisecondes écoulées.
Ce nombre augmente au fur et à mesure du temps, inlassablement. Pour info, la doc de la SDL indique que le nombre atteint son maximum et est réinitialisé au bout de 49 jours ! A priori votre programme SDL devrait tourner moins longtemps que ça, donc pas de souci de ce côté-là
Utiliser SDL_GetTicks pour gérer le temps
Si SDL_Delay est assez facile à comprendre et à utiliser, ce n'est pas le cas de SDL_GetTicks. Il est temps d'apprendre à bien s'en servir...
Voici un exemple ! Nous allons reprendre notre bon vieux programme avec la fenêtre affichant Zozor à l'écran. Souvenez-vous :
Cette fois, au lieu de le diriger au clavier ou à la souris, nous allons faire en sorte qu'il bouge tout seul sur l'écran !
Pour faire simple, on va le faire bouger horizontalement sur la fenêtre.
On reprend pour commencer exactement le même code source que celui qu'on avait utilisé dans le chapitre sur les évènements. Cette fois, j'ai enlevé la partie gérant les évènements au clavier vu qu'on ne va plus bouger Zozor au clavier :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 | int main(int argc, char *argv[])
{
SDL_Surface *ecran = NULL, *zozor = NULL;
SDL_Rect positionZozor;
SDL_Event event;
int continuer = 1;
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("Gestion du temps en SDL", NULL);
zozor = SDL_LoadBMP("zozor.bmp");
SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor->format, 0, 0, 255));
positionZozor.x = ecran->w / 2 - zozor->w / 2;
positionZozor.y = ecran->h / 2 - zozor->h / 2;
SDL_EnableKeyRepeat(10, 10);
while (continuer)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
}
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
SDL_BlitSurface(zozor, NULL, ecran, &positionZozor);
SDL_Flip(ecran);
}
SDL_FreeSurface(zozor);
SDL_Quit();
return EXIT_SUCCESS;
}
|
Bon, si vous testez ce code, vous devriez voir un Zozor au centre de la fenêtre. Rien de bien palpitant encore.
Nous voulons le faire bouger. Pour cela, le mieux est d'utiliser
SDL_GetTicks. On va avoir besoin de 2 variables :
tempsPrecedent et
tempsActuel. Elles vont stocker le temps retourné par
SDL_GetTicks à des moments différents.
Il nous suffira de faire la différence entre
tempsActuel et
tempsPrecedent pour voir le temps qui s'est écoulé. Si le temps écoulé est supérieur à 30ms par exemple, alors on change les coordonnées de Zozor.
Commencez donc par créer ces 2 variables dont on va avoir besoin :
Code : C1 | int tempsPrecedent = 0, tempsActuel = 0;
|
Maintenant, dans notre boucle infinie, nous allons rajouter le code suivant :
Code : C1
2
3
4
5
6 | tempsActuel = SDL_GetTicks();
if (tempsActuel - tempsPrecedent > 30) /* Si 30 ms se sont écoulées */
{
positionZozor.x++; /* On bouge Zozor */
tempsPrecedent = tempsActuel; /* Le temps "actuel" devient le temps "precedent" pour nos futurs calculs */
}
|
Attention, là c'est
super important. C'est là qu'on comprend le truc (ou pas

)
- On prend le temps actuel grâce à SDL_GetTicks
- On compare au temps précedemment enregistré. Si il y a un écart de 30 ms au moins, alors...
- ... alors on bouge Zozor, car on veut qu'il se déplace toutes les 30 ms. Ici, on le décale juste vers la droite toutes les 30 ms.
Il faut vérifier si le temps est
supérieur à 30ms, et non égal à 30ms ! En effet, il faut vérifier si au moins 30ms se sont écoulées. Rien ne vous garantit que l'instruction sera exécutée pile poil toutes les 30ms

- Puis (et c'est vraiment le truc à pas oublier), on place le temps "actuel" dans le temps "précédent". En effet, imaginez au prochain tour de boucle : le temps "actuel" aura changé, et on pourra le comparer au temps précédent. A nouveau, on pourra vérifier si 30 ms se seront écoulées et bouger Zozor
Et que se passe-t-il si la boucle va plus vite que 30 ms ?
Lisez mon code : il ne se passe rien

On ne rentre pas dans le "if", on ne fait donc rien. On attend le prochain tour de boucle où on vérifiera à nouveau si 30 ms se seront écoulées depuis la dernière fois qu'on a fait bouger Zozor.
Ce code est court, mais il faut le comprendre ! Relisez mes explications autant de fois que nécessaire, parce que c'était ça le passage le plus important du chapitre
Un changement dans la gestion des évènements
Notre code est presque bon à un détail près : la fonction
SDL_WaitEvent.
Elle était très pratique jusqu'ici, puisqu'on n'avait pas à gérer le temps. Cette fonction mettait en "pause" le programme (un peu à la manière de
SDL_Delay) tant qu'il n'y avait pas d'évènement.
Or ici, on n'a pas besoin d'attendre un évènement pour faire bouger Zozor !
Il doit bouger tout seul.
Vous n'allez quand même pas bouger la souris juste pour générer des évènements et donc faire sortir le programme de la fonction SDL_WaitEvent
La solution ?
SDL_PollEvent.
Je vous avais déjà présenté cette fonction : contrairement à SDL_WaitEvent, elle renvoie une valeur qu'il y ait eu un évènement ou pas. On dit que la fonction n'est pas "bloquante" : elle ne met pas en pause le programme, la boucle infinie va donc tourner indéfiniment tout le temps.
Code complet
Voici le code final que vous pouvez tester :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 | int main(int argc, char *argv[])
{
SDL_Surface *ecran = NULL, *zozor = NULL;
SDL_Rect positionZozor;
SDL_Event event;
int continuer = 1;
int tempsPrecedent = 0, tempsActuel = 0;
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("Gestion du temps en SDL", NULL);
zozor = SDL_LoadBMP("zozor.bmp");
SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor->format, 0, 0, 255));
positionZozor.x = ecran->w / 2 - zozor->w / 2;
positionZozor.y = ecran->h / 2 - zozor->h / 2;
SDL_EnableKeyRepeat(10, 10);
while (continuer)
{
SDL_PollEvent(&event); /* On utilise PollEvent et non WaitEvent pour ne pas bloquer le programme */
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
}
tempsActuel = SDL_GetTicks();
if (tempsActuel - tempsPrecedent > 30) /* Si 30 ms se sont écoulées depuis le dernier tour de boucle */
{
positionZozor.x++; /* On bouge Zozor */
tempsPrecedent = tempsActuel; /* Le temps "actuel" devient le temps "precedent" pour nos futurs calculs */
}
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
SDL_BlitSurface(zozor, NULL, ecran, &positionZozor);
SDL_Flip(ecran);
}
SDL_FreeSurface(zozor);
SDL_Quit();
return EXIT_SUCCESS;
}
|
Vous devriez voir Zozor bouger tout seul sur l'écran. Il se décale vers la droite

Essayez de changer le temps de 30ms en 15ms par exemple : Zozor devrait se déplacer 2 fois plus vite ! En effet, il se déplacera une fois toutes les 15ms au lieu d'une fois toutes les 30ms auparavant
Consommer moins de CPU
Actuellement, notre programme tourne en boucle indéfiniment à la vitesse de la lumière (enfin presque). Il consomme donc 100% du CPU.
Si vous faites CTRL + ALT + SUPPR (onglet "Processus"), vous verrez ça sous Windows :
Comme vous pouvez le voir, notre CPU est utilisé à 100% par notre programme testsdl.exe.
Je vous l'ai dit plus tôt : si vous codez un jeu (surtout un jeu plein écran), ce n'est pas grave si vous utilisez 100% du CPU. Mais si c'est un jeu dans une fenêtre par exemple, il vaut mieux qu'il utilise le moins de CPU possible pour que l'utilisateur puisse faire autre chose sans que son PC ne "rame".
La solution ? On va reprendre exactement le même code que ci-dessus mais on va lui ajouter en plus un SDL_Delay pour patienter le temps qu'il faut afin que ça fasse 30ms.
On va juste rajouter un SDL_Delay dans un "else" :
Code : C 1
2
3
4
5
6
7
8
9
10 | tempsActuel = SDL_GetTicks();
if (tempsActuel - tempsPrecedent > 30)
{
positionZozor.x++;
tempsPrecedent = tempsActuel;
}
else /* Si ça fait moins de 30ms depuis le dernier tour de boucle, on endort le programme le temps qu'il faut */
{
SDL_Delay(30 - (tempsActuel - tempsPrecedent));
}
|
Comment ça fonctionne cette fois ?
C'est simple, il y a 2 possibilités (d'après le if) :
- Soit ça fait plus de 30ms qu'on n'a pas bougé Zozor, dans ce cas on le bouge.
- Soit ça fait moins de 30 ms, dans ce cas on fait dormir le programme avec SDL_Delay le temps qu'il faut pour que ça fasse 30ms environ.
D'où mon petit calcul 30 - (tempsActuel - tempsPrecedent). Si la différence entre le temps actuel et le temps précédent est de 20ms par exemple, alors on endormira le programme (30 - 20) = 10ms afin que ça fasse environ 30ms 
Rappelez-vous que SDL_Delay mettra peut-être quelques millisecondes de plus que prévu. Chez moi, comme je vous l'ai dit, c'est assez précis.
Du coup, notre programme va "dormir" la plupart du temps et donc consommer très peu de CPU. Regardez !
En moyenne, le programme utilise 0-1% de CPU... Parfois il utilise légèrement plus, mais il retombe rapidement à 0% de CPU.
Contrôler le nombre d'images par seconde
Vous vous demandez certainement comment on peut limiter (fixer) le nombre d'images par seconde (FPS) affichées par l'ordinateur.
Eh bien c'est exactement ce qu'on est en train de faire ! Ici, on affiche une nouvelle image toutes les 30ms en moyenne.
Sachant qu'une seconde vaut 1000ms, pour trouver le nombre de FPS (images par seconde), il suffit de faire une bête division : 1000 / 30 =
33 images par seconde environ.
Pour l'oeil humain, une animation est fluide si elle contient au moins 25 images / seconde. Avec 33 images / seconde, notre animation sera donc tout à fait fluide, elle n'apparaîtra pas "saccadée".
Si vous voulez plus d'images par seconde, il faut réduire la limite de temps entre 2 images. Passez de 30 à 20ms, et ça vous fera du 1000 / 20 = 50 FPS
Exercices
La manipulation du temps n'est pas évidente, il serait bien de vous entraîner un peu, qu'en dites-vous ?
Voici quelques exercices justement :
- Pour le moment, Zozor se décale vers la droite puis disparaît de l'écran. Ce serait mieux s'il repartait dans l'autre sens une fois arrivé tout à droite non ? Ca donnerait l'impression qu'il rebondit

Pour faire ça, je vous conseille de créer un booléen versLaDroite qui vaut vrai si Zozor se déplace vers la droite (et faux s'il va vers la gauche). Si le booléen vaut vrai, vous décalez donc Zozor vers la droite, sinon vous le décalez vers la gauche.
Surtout, n'oubliez pas de changer la valeur du booléen lorsque Zozor atteint le bord droit ou le bord gauche ! Eh oui, il faut qu'il reparte dans l'autre sens 
- Plutôt que de faire rebondir Zozor de droite à gauche, faites le rebondir en diagonale sur l'écran ! Il vous suffira de modifier positionZozor.x et positionZozor.y simultanément. Vous pouvez essayer de voir ce que ça fait si on augmente x et si on diminue y en même temps, ou bien si on augmente les 2 en même temps etc.

- Faites en sorte qu'un appui sur la touche P empêche Zozor de se déplacer, et qu'un rappui à nouveau sur la touche P relance le déplacement de Zozor. C'est un bête booléen à activer / désactiver

Voilà, ce sont quelques petits exos comme ça qui devraient vous occuper quelques minutes et vous permettre ainsi d'améliorer le programme
L'utilisation des Timers est un peu complexe. Elle fait intervenir une notion qu'on n'a pas vue jusqu'ici : les pointeurs de fonctions.
Il n'est pas indispensable d'utiliser les Timers : si vous ne le sentez pas, vous pouvez donc passer votre chemin sans souci

Les Timers sont une autre façon de réaliser ce qu'on vient de faire avec SDL_GetTicks.
C'est une technique un peu particulière. Certains la trouveront pratique, d'autres pas. Ca dépend donc des goûts du programmeur
Qu'est-ce qu'un Timer ?
C'est un système qui permet de demander à la SDL d'
appeler une fonction toutes les X millisecondes. Vous pourriez ainsi créer une fonction
bougerEnnemi() que la SDL appellerait automatiquement toutes les 50ms afin que l'ennemi se déplace à intervalles réguliers.
Comme je viens de vous le dire, cela est aussi faisable avec SDL_GetTicks en utilisant la technique qu'on a vue plus haut.
Quel avantage alors ? Eh bien disons que les Timers nous obligent à mieux structurer notre programme en fonctions.
Initialiser le système de Timers
Pour pouvoir utiliser les Timers, vous devez d'abord initialiser la SDL avec un flag spécial : SDL_INIT_TIMER.
Vous devriez donc avoir une fonction SDL_Init appelée comme ceci :
Code : C1 | SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
Voilà, la SDL est maintenant prête à utiliser les Timers
Ajouter un Timer
Il existe 2 fonctions permettant d'ajouter un Timer en SDL : SDL_AddTimer et SDL_SetTimer.
Quelle est la différence entre les 2 ? En fait,
elles sont quasiment identiques. Cependant, SDL_SetTimer est une fonction "ancienne" qui existe toujours pour des raisons de compatibilité. Aujourd'hui, si on veut bien faire les choses, on nous recommande donc d'utiliser
SDL_AddTimer
Alors attention, c'est là que ça se corse. Voici le prototype de SDL_AddTimer :
Code : C1 | SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param);
|
On envoie 3 paramètres à la fonction :
- L'intervalle de temps (en ms) entre chaque appel de la fonction
- Le nom de la fonction à appeler. On appelle cela un callback : le programme se charge de rappeler cette fonction de callback régulièrement.
- Les paramètres à envoyer à votre fonction de callback.
QUOIII ? Un nom de fonction peut servir de paramètre ? Je croyais qu'on ne pouvait envoyer que des variables !?
En fait, les fonctions sont aussi stockées en mémoire au chargement du programme. Elles ont donc elles aussi une adresse.
Du coup, on peut créer des...
pointeurs de fonctions ! Il suffit d'écrire le nom de la fonction à appeler pour indiquer l'adresse de la fonction. Ainsi, la SDL saura à quelle adresse en mémoire elle doit se rendre pour appeler votre fonction de callback.
SDL_AddTimer renvoie un numéro de Timer (un "ID"). Vous devez stocker ce résultat dans une variable de type
SDL_TimerID. Cela vous permettra par la suite de désactiver le Timer : il vous suffira d'indiquer l'ID du Timer à arrêter.
On va donc créer un ID de Timer :
Code : C1 | SDL_TimerID timer; /* Variable pour stocker le numéro du Timer */
|
... puis on va créer notre Timer :
Code : C1 | timer = SDL_AddTimer(30, bougerZozor, &positionZozor); /* Démarrage du Timer */
|
Ici, je crée un Timer qui a les propriétés suivantes :
- Il sera appelé toutes les 30ms
- Il appellera la fonction de callback bougerZozor
- Il lui enverra comme paramètre un pointeur sur la position de Zozor pour qu'il puisse la modifier.
Vous l'aurez compris : le rôle de la fonction bougerZozor sera de changer la position de Zozor toutes les 30ms
Création de la fonction de callback
Attention là il ne faut pas se planter. Votre fonction de callback doit
obligatoirement avoir le prototype suivant :
Code : C1 | Uint32 nomDeLaFonction(Uint32 intervalle, void *parametre);
|
Pour créer le callback bougerZozor, je devrai donc écrire la fonction comme ceci :
Code : C1 | Uint32 bougerZozor(Uint32 intervalle, void *parametre);
|
Voici maintenant le contenu de ma fonction bougerZozor (ouvrez grand les yeux c'est très intéressant

) :
Code : C1
2
3
4
5
6
7
8 | /* Fonction de callback (sera appelée toutes les 30ms) */
Uint32 bougerZozor(Uint32 intervalle, void *parametre)
{
SDL_Rect* positionZozor = parametre; /* Conversion de void* en SDL_Rect* */
positionZozor->x++;
return intervalle;
}
|
La fonction bougerZozor sera donc automatiquement appelée toutes les 30ms par la SDL.
La SDL lui enverra toujours 2 paramètres (ni plus, ni moins) :
- L'intervalle de temps qui sépare 2 appels de la fonction (ici ça sera 30)
- Le paramètre "personnalisé" que vous avez demandé à envoyer à la fonction. Remarquez, et c'est très important, que ce paramètre est un pointeur sur void. Cela signifie que c'est un pointeur qui peut pointer sur n'importe quoi : un int, une structure personnalisée, ou comme ici un SDL_Rect (positionZozor)
Le problème, c'est que ce paramètre est un pointeur de type "inconnu" (void) pour la fonction. Il va donc falloir dire à l'ordinateur que ce paramètre est un SDL_Rect* (un pointeur sur SDL_Rect).
Pour faire ça, je crée un pointeur sur SDL_Rect dans ma fonction qui prend comme valeur... le pointeur
parametre.
Quel intérêt d'avoir créé un DEUXIEME pointeur qui contient la même adresse ?
L'intérêt, c'est que
positionZozor est de type SDL_Rect* contrairement à
parametre qui était de type void*.
Vous pourrez donc accéder à
positionZozor->x et
positionZozor->y.
Si vous aviez fait
parametre->x ou
parametre->y, le compilateur vous aurait jeté parce que le type void ne contient pas de sous-variable x et y
Après, la ligne suivante est simple : on modifie la valeur de positionZozor->x pour décaler Zozor vers la droite.
Dernière chose, très importante :
vous devez retourner la variable intervalle. Cela indiquera à la SDL qu'on veut continuer à ce que la fonction soit appelée toutes les 30ms.
Si vous voulez changer l'intervalle d'appel, il suffit de renvoyer une autre valeur (mais bien souvent, on ne change pas l'intervalle d'appel

)
Arrêter le Timer
Pour arrêter le Timer, c'est super simple :
Code : C1 | SDL_RemoveTimer(timer); /* Arrêt du Timer */
|
Il suffit d'appeler SDL_RemoveTimer en indiquant l'ID du Timer à arrêter.
Ici, j'arrête le Timer juste après la boucle infinie (au même endroit que les SDL_FreeSurface quoi

).
Code complet d'exemple
Allez, on résume tout ça pour mettre nos idées au clair. Toutes les lignes intéressantes sont commentées :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 | #include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
/* Prototype de la fonction de callback */
Uint32 bougerZozor(Uint32 intervalle, void *parametre);
int main(int argc, char *argv[])
{
SDL_Surface *ecran = NULL, *zozor = NULL;
SDL_Rect positionZozor;
SDL_Event event;
int continuer = 1;
SDL_TimerID timer; /* Variable pour stocker le numéro du Timer */
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("Gestion du temps en SDL", NULL);
zozor = SDL_LoadBMP("zozor.bmp");
SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor->format, 0, 0, 255));
positionZozor.x = ecran->w / 2 - zozor->w / 2;
positionZozor.y = ecran->h / 2 - zozor->h / 2;
SDL_EnableKeyRepeat(10, 10);
timer = SDL_AddTimer(30, bougerZozor, &positionZozor); /* Démarrage du Timer */
while (continuer)
{
SDL_PollEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
}
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
SDL_BlitSurface(zozor, NULL, ecran, &positionZozor);
SDL_Flip(ecran);
}
SDL_RemoveTimer(timer); /* Arrêt du Timer */
SDL_FreeSurface(zozor);
SDL_Quit();
return EXIT_SUCCESS;
}
/* Fonction de callback (sera appelée toutes les 30ms) */
Uint32 bougerZozor(Uint32 intervalle, void *parametre)
{
SDL_Rect* positionZozor = parametre; /* Conversion de void* en SDL_Rect* */
positionZozor->x++;
return intervalle;
}
|
Vous devriez voir Zozor bouger toutes les 30ms. Cette fois, le déplacement est géré par un Timer qui appelle une fonction de callback à intervalle de temps régulier (ouah ça fait pro cette phrase vous trouvez pas

)
Sur un petit exemple comme ça, il peut sembler plus simple d'utiliser SDL_GetTicks. Je suis bien d'accord. Mais sur de gros programmes, vous aurez très probablement des fonctions de callback plus longues et complexes à créer, ce qui rendra l'utilisation de Timers plus intéressante
Au fait... On ne peut envoyer qu'un seul paramètre à la fonction de callback ?
Oui. Comme vous le voyez, le seul paramètre qu'on peut envoyer est :
void *parametre.
Ce void* peut être un pointeur sur int, sur SDL_Rect, sur ce que vous voulez quoi
Si vous voulez envoyer plusieurs variables à la fois, c'est tout à fait possible : créez une structure personnalisée qui contiendra les variables que vous voulez. C'est d'ailleurs ce qu'on fait avec notre positionZozor qui contient les sous-variables x et y !