Bonjour,
Je suis en train de me mettre à la SDL et plus particulièrement la création de jeux, mais j'ai quelques problèmes avec la bonne façon de gérer le temps et créer une bonne boucle de jeu.
J'ai lu plusieurs tutoriels, mais je trouve qu'en général ils n'expliquent pas suffisamment les avantages/inconvénients de leur solution ; du coup j'ai cherché s'il existait des "comparatifs" des styles de boucles de jeu possibles, mais je n'en ai pas trouvé...
En plus de ça, j'ai quelques questions sur ces différentes solutions (en ne considérant que les SDL_SWSURFACE) ; voici ce que j'ai pu trouver :
Solution 1 :
=> on affiche autant qu'on peut, et le CPU tourne un max
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 while (run) { // Gestion des évènements // Gestion de la logique du jeu // Rendu }
=> Questions : Est-ce que c'est un comportement désiré/désirable en général ? Si la gestion des évènements prend en compte le fait que la fenêtre n'a plus le focus, ou qu'on sort la souris de l'écran (le jeu se met en pause par exemple), est-ce toujours un problème de faire tourner le CPU à fond quand on est en jeu ?
Solution 2 :
=> on épargne le CPU (et le framerate est limité, de par le fait)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 while (run) { // Gestion des évènements // Gestion de la logique du jeu // Rendu SDL_Delay(5); // pour ne pas utiliser 100% du CPU }
Solution 3 :
=> on affiche avec le framerate désiré
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 while (run) { // Gestion des évènements // Gestion de la logique du jeu currenttime = SDL_GetTicks(); if (currenttime > (lastrender + 1000 / FPS)) { lastrender = currenttime; // Rendu } }
=> le CPU tourne quand même à fond
=> nécessiterait une gestion du retard (par exemple si on dépasse de 30-40 ms le moment où on doit faire le rendu), et donc de "passer" certaines frames
=> Questions : idem que la solution 1
Solution 4 :
=> par rapport à la solution 3, on épargne le CPU, mais on perd encore en précision ; si par exemple on est juste 1 ms avant la date de rendu, on va quand meme devoir attendre 5 ms en plus de reboucler
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 while (run) { // Gestion des évènements // Gestion de la logique du jeu currenttime = SDL_GetTicks(); if (currenttime > (lastrender + 1000 / FPS)) { lastrender = currenttime; // Rendu } else { SDL_Delay(5); // pour ne pas utiliser 100% du CPU } }
=> Questions : Ne peut-on rien faire contre ça ? Même en prenant un intervalle proche de la date de rendu dans lequel on fait le rendu même si ce n'est pas encore le moment, si on est à 1 ms de cet intervalle.... on attendra et on re-bouclera... c'est un problème sans fin !
Solution 5 :
=> on ne fait rien tant que ce n'est pas le moment du rendu
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 while (run) { // Gestion des évènements // Gestion de la logique du jeu lastrender = SDL_GetTicks(); // Rendu if (SDL_GetTicks() < (lastrender + 1000 / FPS)) { SDL_Delay((lastrender + 1000 / FPS) - SDL_GetTicks()); } }
=> Questions : N'est-il pas risqué de faire les choses de cette manière ? Si on remet le traitement de toutes les entrées utilisateurs et de la logique du jeu (rien que la détection de collision, ça peut être lourd, alors avec le reste...) au moment du rendu, les calculs risquent de prendre des plombes et le rendu ne sera pas fait à temps, non ? Pour un tuto j'imagine que c'est bon, mais pour un truc un peu plus sérieux/lourd ...
Solution 6 :
=> a priori pire que la solution 5, puisque là en plus on aura un retard avec les entrées utilisateur
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 while (run) { // Gestion des évènements // Gestion de la logique du jeu if (SDL_GetTicks() < (lastrender + 1000 / FPS)) { SDL_Delay((lastrender + 1000 / FPS) - SDL_GetTicks()); } lastrender = SDL_GetTicks(); // Rendu }
De mon point de vue, les solutions 3 et 4 me semblent être les meilleures ; cependant la solution 3 fait tout le temps tourner le CPU, et la solution 4 aggrave le problème de la précision dans le déclenchement du rendu, problème qu'on a en fait dans plus ou moins toutes les solutions. De manière générale le fait de faire du framerate fixe me semble plus propre, ce qui est amusant vu que la solution 3 fait bien du framerate fixe mais avec quand même un CPU qui tourne à fond.
Peut-être que je n'ai pas assez lu de tutos, mais n'existe-t'il pas une manière plus générique / professionnelle de faire une bonne boucle de jeu pour la gestion du temps ?
Merci à ceux qui me liront et plus encore à ceux qui pourront me corriger !
Partager