Apprenez à programmer en C !

Apprenez à programmer en C !

Mis à jour le mardi 29 juillet 2014

Ce chapitre est d'une importance capitale : il va vous apprendre à contrôler le temps en SDL. Il est rare que l'on crée un programme SDL sans faire appel aux fonctions de gestion du temps, bien que le TP Mario Sokoban constitue un contre-exemple. Il n'en reste pas moins que pour la majorité des jeux, la gestion du temps est fondamentale.

Par exemple, comment vous y prendriez-vous pour réaliser un Tetris ou un Snake (jeu du serpent) ? Il faut bien que les blocs bougent toutes les X secondes, ce que vous ne savez pas faire. Du moins, pas avant d'avoir lu ce chapitre. ;-)

Le Delay et les Ticks

Dans un premier temps, nous allons apprendre à utiliser deux 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 deux fonctions sont très simples comme nous allons le voir, mais bien les utiliser n'est pas si évident que ça en a l'air…

SDL_Delay

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 utilisée pour réduire l'utilisation du processeur (notez que j'abrègerai CPU), désormais. C'est une abréviation courante 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.

Revenons à la fonction qui nous intéresse. Son prototype est d'une simplicité désolante :

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 écrire :

SDL_Delay(1000);

N'oubliez pas que ce sont des millisecondes :

  • 1000 millisecondes = 1 seconde ;

  • 500 millisecondes = 1/2 seconde ;

  • 250 millisecondes = 1/4 seconde.

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, j'estime qu'il y a quelque chose que vous devez savoir : SDL_Delay n'est pas une fonction « parfaite ». Et ce n'est pas de sa faute, c'est la faute de votre OS (Windows, Linux, Mac OS X…).

Pourquoi l'OS intervient-il là-dedans ? Tout simplement parce que 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 exactement au bout d'une seconde.

En effet, il aura peut-être un peu de retard (un retard de 10 ms 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 40 ms tu vas travailler sur firefox.exe, puis pendant 110 ms sur explorer.exe ; ensuite, pendant 80 ms tu vas travailler sur programme_sdl.exe, puis retravailler sur firefox.exe pendant 65 ms », 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 pour que votre programme puisse « reprendre la main » comme on dit, c'est-à-dire être traité à nouveau par le CPU.

Qu'est-ce qu'il faut retenir ? Que votre CPU ne peut 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 tour à tour.
C'est toutefois de moins en moins vrai. Les CPU double cœur ont en effet la capacité de travailler sur deux programmes à la fois, maintenant.

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, cela dépend des PC comme je vous l'ai dit plus haut. Chez moi, j'ai pu constater que la fonction SDL_Delay était assez précise.

SDL_Delay est donc bien pratique, 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. C'est un indicateur de temps indispensable. Cela vous permet de vous repérer dans le temps, vous allez voir !

Voici le prototype :

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 que le temps passe, 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 la fonction 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 (fig. suivante).

Zozor au centre de l'écran

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. Vous devriez pouvoir créer un programme aussi simple sans avoir besoin de mon aide, ici. Si néanmoins vous en avez besoin, vous pouvez récupérer le code source de base sur Internet.

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

Intéressons-nous à Zozor. Nous voulons le faire bouger. Pour cela, le mieux est d'utiliser SDL_GetTicks. On va avoir besoin de deux 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 par exemple supérieur à 30 ms, alors on change les coordonnées de Zozor.

Commencez donc par créer ces deux variables dont on va avoir besoin :

int tempsPrecedent = 0, tempsActuel = 0;

Maintenant, dans notre boucle infinie, nous allons ajouter le code suivant :

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 */
}

Comprenez bien ce qui se passe.

  1. On prend le temps actuel grâce à SDL_GetTicks.

  2. On compare au temps précédemment enregistré. S'il y a un écart de 30 ms au moins, alors…

  3. … 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 à 30 ms, et non égal à 30 ms ! En effet, il faut vérifier si au moins 30 ms se sont écoulées. Rien ne vous garantit que l'instruction sera exécutée pile poil toutes les 30 ms.

  4. Puis, et c'est vraiment ce qu'il ne faut pas oublier, on place le temps « actuel » dans le temps « précédent ». En effet, imaginez le prochain tour de boucle : le temps « actuel » aura changé, et on pourra le comparer au temps précédent. À nouveau, on pourra vérifier si 30 ms se seront écoulées et bouger Zozor.

Et que se passe-t-il si la boucle met moins de temps 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 probablement le passage le plus important du chapitre.

Un changement dans la gestion des événements

Notre code est parfait à 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 non. On dit que la fonction n'est pas bloquante : elle ne met pas en pause le programme, la boucle infinie va donc tourner tout le temps.

Code complet

Voici le code final que vous pouvez tester :

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 par exemple de changer le temps de 30 ms en 15 ms : Zozor devrait se déplacer deux fois plus vite ! En effet, il se déplacera une fois toutes les 15 ms au lieu d'une fois toutes les 30 ms 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.
Pour voir cela, il vous suffit par exemple de faire CTRL + ALT + SUPPR (onglet Processus) sous Windows (fig. suivante).

Consommation du CPU par le programme

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 30 ms.

On va juste ajouter un SDL_Delay dans un else :

tempsActuel = SDL_GetTicks();
if (tempsActuel - tempsPrecedent > 30)
{
    positionZozor.x++;
    tempsPrecedent = tempsActuel;
}
else /* Si ça fait moins de 30 ms depuis le dernier tour de boucle, on endort le programme le temps qu'il faut */
{
    SDL_Delay(30 - (tempsActuel - tempsPrecedent));
}

Comment cela fonctionne-t-il, cette fois ? C'est simple, il y a deux possibilités (d'après le if) :

  • soit ça fait plus de 30 ms 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 atteindre les 30 ms environ. D'où mon petit calcul 30 - (tempsActuel - tempsPrecedent). Si la différence entre le temps actuel et le temps précédent est par exemple de 20 ms, alors on endormira le programme (30 - 20) = 10 ms afin d'atteindre les 30 ms.

Avec ce code, notre programme va « dormir » la plupart du temps et donc consommer très peu de CPU (fig. suivante).

Consommation de CPU réduite

En moyenne, le programme utilise maintenant entre 0 et 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 (couramment abrégé FPS pour « Frames per second ») 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 30 ms en moyenne.
Sachant qu'une seconde vaut 1000 ms, pour trouver le nombre de FPS (images par seconde), il suffit de faire une division : 1000 / 30 = 33 images par seconde environ.

Pour l'œil 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 deux images. Passez de 30 à 20 ms, 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.

  • 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 ? Cela donnerait l'impression qu'il rebondit.

  • 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 bien 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 deux 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 nouvel appui sur la touche P relance le déplacement de Zozor. C'est un bête booléen à activer et désactiver.

Les timers

Les timers constituent une autre façon de réaliser ce qu'on vient de faire avec la fonction SDL_GetTicks.
C'est une technique un peu particulière. Certains la trouveront pratique, d'autres non. Cela 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 50 ms afin que l'ennemi se déplace à intervalles réguliers.

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 appeler votre fonction SDL_Init comme ceci :

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);

La SDL est maintenant prête à utiliser les timers !

Ajouter un timer

Pour ajouter un timer, on fait appel à la fonction SDL_AddTimer dont voici le prototype.

SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param);

Il existe en fait deux fonctions permettant d'ajouter un timer en SDL : SDL_AddTimer et SDL_SetTimer.
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.

On envoie trois 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.

Comment ? 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.
Si vous souhaitez en savoir plus sur les pointeurs de fonctions, je vous invite à lire le tutoriel rédigé par mleg qui traite de ce sujet.

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.

La SDL vous permet d'activer plusieurs timers en même temps. Cela explique l'intérêt de stocker un ID de timer pour pouvoir les différencier.

On va donc créer un ID de timer :

SDL_TimerID timer; /* Variable pour stocker le numéro du timer */

… puis on va créer notre timer :

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 30 ms ;

  • 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 30 ms.

Création de la fonction de callback

Attention : il faut être particulièrement vigilant ici. Votre fonction de callback doit obligatoirement avoir le prototype suivant :

Uint32 nomDeLaFonction(Uint32 intervalle, void *parametre);

Pour créer le callback bougerZozor, je devrai donc écrire la fonction comme ceci :

Uint32 bougerZozor(Uint32 intervalle, void *parametre);

Voici maintenant le contenu de ma fonction bougerZozor, qui est plus délicate qu'il n'y paraît :

/* Fonction de callback (sera appelée toutes les 30 ms) */
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 30 ms par la SDL.
La SDL lui enverra toujours deux paramètres (ni plus, ni moins) :

  • l'intervalle de temps qui sépare deux appels de la fonction (ici, ça sera 30 ms) ;

  • 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).
    Notez qu'il n'est pas possible d'envoyer plus d'un paramètre personnalisé à la fonction de callback. Heureusement, vous pouvez toujours créer un type personnalisé (ou un tableau) qui sera un assemblage des variables que vous voulez transmettre.

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 DEUXIÈME pointeur qui contient la même adresse ?

L'intérêt, c'est que positionZozor est de type SDL_Rect* contrairement à la variable 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 aurait tout rejeté en bloc 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 à faire en sorte que la fonction soit appelée toutes les 30 ms.
Si vous voulez changer l'intervalle d'appel, il suffit de renvoyer une autre valeur (mais bien souvent, on ne change pas cet intervalle).

Arrêter le timer

Pour arrêter le timer, c'est très simple :

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.

En résumé

  • La fonction SDL_Delay permet de mettre en pause le programme un certain nombre de millisecondes. Cela permet de réduire l'utilisation du CPU qui n'est alors plus monopolisé par votre programme.

  • On peut connaître le nombre de millisecondes écoulées depuis le lancement du programme avec SDL_GetTicks. Avec quelques petits calculs, on peut s'en servir pour effectuer une gestion des événements non bloquante avec SDL_PollEvent.

  • Les timers constituent un système qui permet de rappeler une de vos fonctions (dite de callback) à intervalles réguliers. Le même résultat peut être obtenu avec SDL_GetTicks mais les timers aident à rendre le programme plus lisible et mieux structuré.

Exemple de certificat de réussite
Exemple de certificat de réussite