IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SDL Discussion :

[SDL] Créer une boucle de jeu correcte


Sujet :

SDL

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2010
    Messages : 21
    Points : 35
    Points
    35
    Par défaut [SDL] Créer une boucle de jeu correcte
    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 :

    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
    }
    => on affiche autant qu'on peut, et le CPU tourne un max
    => 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 :

    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
    }
    => on épargne le CPU (et le framerate est limité, de par le fait)



    Solution 3 :

    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
        }
    }
    => on affiche avec le framerate désiré
    => 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 :

    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
        }
    }
    => 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
    => 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 :

    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());
        }
    }
    => on ne fait rien tant que ce n'est pas le moment du rendu
    => 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 :

    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
    }
    => a priori pire que la solution 5, puisque là en plus on aura un retard avec les entrées utilisateur



    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 !

  2. #2
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    ok , bah c'est bien que tu as réfléchi au problème , mais bon dommage que t'as pas réfléchi au problème le plus simple pour résoudre un FPS correct =P


    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 ?
    Voila ma méthode ,FPS constant,pas de 100% CPU ,aucun souci avec les évènements:

    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
    16
    17
    18
    19
     
    while (run)
    {
        // Gestion des évènements
        // Gestion de la logique du jeu
        // Rendu
     
        beginrender = SDL_GetTicks();
     
        time = beginrender - lastrender;
     
        if(time < 0) time = 0;
     
        if(time < 1000 / FPS)
        SDL_Delay( (1000 / FPS) - time);
     
        lastrender = SDL_GetTicks();
     
    }
    On y reflechisant un peu en peut en faire une fonction fps

  3. #3
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Solution 1 : l'utilisateur va faire chauffer le CPU pour rien (surtout un jeu 2D, moi, je ne m'attend pas à ce qu'il crame mon CPU )
    Solution 2 : si l'update / render prends environ 12 ms (60 FPS -> 16,6ms par tour de boucle), vous allez tomber en dessous des 60 FPS, mais que sur certaine machine. La vitesse dépendra du CPU, ce qui n'est pas bon.
    Solution 4 : même problème

    Pour moi, les meilleurs solutions sont :

    - Séparation de la boucle rendu / update. En effet, je ne veux pas nécessairement de 60 updates par seconde (surtout si je fais de l'IA ) ;
    - Calcul du delta (le nombre de millisecondes entre deux tours de boucles) afin de calculer le déplacement, relatif donc au temps réel écoulé ;
    - le sleep pour alléger le CPU. Il doit être du temps restant lorsque l'on ne dessine pas (1000/60 - temps_draw) ;
    - ne pas oublier de regarder le taux de rafraichissement de la fenêtre (en effet, j'ai un écran à 120 Hertz et jusque là, vous n'avez pensé qu'au 60 FPS ).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2010
    Messages : 21
    Points : 35
    Points
    35
    Par défaut
    @Kannagi

    Ah, je me doutais que tu répondrais, j'avais lu plusieurs de tes interventions ^^

    En fait, en simplifiant avec time et en enlevant le cas où time < 0, on obtient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    while (run)
    {
        // Gestion des évènements
        // Gestion de la logique du jeu
        // Rendu
     
        if (SDL_GetTicks() < (lastrender + 1000 / FPS))
            SDL_Delay((lastrender + 1000 / FPS) - SDL_GetTicks());
     
        lastrender = SDL_GetTicks();
    }
    Tu mets SDL_GetTicks() dans beginrender, j'imagine que c'est pour éviter que juste après la comparaison du if, le temps courant dépasse le moment du rendu et donc envoie une valeur négative à SDL_Delay().
    Sinon en fait c'est plutôt analogue à la solution 5, mais en mieux ; par contre du coup, lastrender ne représente plus le rendu en lui-même (comme dans mes solutions), mais un tour de boucle, un "cycle" de rafraichissement en quelque sorte. Et forcément il est affecté à SDL_GetTicks() à la fin de la boucle et non plus avant le rendu. C'est clairement plus propre effectivement.
    Mais on ne peut vraiment rien faire pour le fait d'attendre passivement que ce soit le moment du prochain cycle ? Ce temps pourrait être utilisé à s'avancer dans les calculs pour le prochain rendu non ?
    Ahem quoique attend non, je crois que je viens de comprendre, s'il fallait de manière générale plus de temps au truc pour faire les calculs, donc si le temps entre 2 cycles ne suffisait pas, on ne pourrait pas tenir les FPS, donc peu importe si on fait une attente passive ou pas, au final.
    Mais c'est quand même rageant de voir que si une scène demande très ponctuellement plus de temps de calcul pour le rendu, alors qu'on peut avoir du temps de disponible à la fin du précédent rendu, ben on ne l'utilise pas et on fait un SDL_Delay()... j'imagine qu'il n'y a pas de solution, à part faire du 100% CPU ?

    En tout cas merci d'avoir montré ta manière de faire, ça m'aide bien !

    @LittleWhite

    Merci pour ton avis sur ces solutions.
    Effectivement la vitesse dépendra du CPU pour la solution 2, mais c'est seulement si on suppose que chaque tour de boucle fait bouger les objets d'un nombre de pixels fixe par exemple. Si on leur associe une vitesse/vélocité (en pixels/s), en ayant enregistré la date du dernier moment où on les a déplacé, on peut savoir combien de temps s'est écoulé et donc de combien de pixels ils doivent être déplacés. Je ne l'ai pas mis dans mes exemples car pour moi, "Gestion de la logique du jeu" englobait un peu tous les traitements possibles. J'aurais du être plus clair, désolé ^^

    - Séparation de la boucle rendu / update. En effet, je ne veux pas nécessairement de 60 updates par seconde (surtout si je fais de l'IA )
    Séparer la boucle rendu / update ? Je ne comprends pas. Tu veux dire séparer la gestion du nombre de frames par seconde et le nombre d'updates par seconde des objets mobiles et/ou animations environnants ?

    - Calcul du delta (le nombre de millisecondes entre deux tours de boucles) afin de calculer le déplacement, relatif donc au temps réel écoulé
    Ah oui, c'est la solution au problème que tu évoques pour l'exemple 2.

    - le sleep pour alléger le CPU. Il doit être du temps restant lorsque l'on ne dessine pas (1000/60 - temps_draw)
    Décidément, je n'arrive pas à m'y faire, je trouve vraiment que ça fait du temps perdu pour rien... mais tout le monde fait ça, j'imagine que c'est comme ça qu'il faut faire ^^

    - ne pas oublier de regarder le taux de rafraichissement de la fenêtre (en effet, j'ai un écran à 120 Hertz et jusque là, vous n'avez pensé qu'au 60 FPS ).
    C'est la classe, tu peux jouer en 3D du coup ^^
    Mais par contre, peu importe le nombre de frames par seconde qu'on utilise tant qu'on est au-dessus de ce que l'oeil humain considère comme fluide (même si c'est mieux de pouvoir maintenir quand même du 60 FPS, ne serait-ce que pour la réactivité du jeu) ; le 120 Hz se rafraichira plusieurs fois de suite avec la même image, mais c'est pas dramatique. Et encore, s'il permet du 120 Hz interpolé il y a pas besoin de s'en préoccuper. Si le matériel derrière permet de soutenir une cadence supérieure à 60 Hz c'est cool, j'imagine qu'il faudrait faire un outil de test pour vérifier combien le jeu peut sortir de FPS, et permettre un réglage dans les options indiquant la fréquence de rafraichissement de l'écran, si c'est ce dont tu veux parler. Comme ça le jeu peut choisir par rapport à ce que le matériel peut faire et ce que l'écran peut accepter. Mais de toute façon, surtout si on utilise des SDL_SWSURFACE, on n'est pas limité à avoir soit 60 FPS, soit 120 FPS ; si le matériel le permet, on peut parfaitement être en 90 FPS par exemple (après l'écran sera bien en 120 Hz mais 1 fois sur 4 l'image sera la même).

    Merci pour tes remarques, n'hésite pas à me corriger si je dis des bêtises

  5. #5
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Séparer la boucle rendu / update ? Je ne comprends pas. Tu veux dire séparer la gestion du nombre de frames par seconde et le nombre d'updates par seconde des objets mobiles et/ou animations environnants ?
    Oui, deux boucles séparés (dans deux threads, même).

    C'est la classe, tu peux jouer en 3D du coup ^^
    Ouep, mais faut avoir les yeux pour

    Pour le 120Hz, je ne sais pas comment cela est géré. Je pense que si le programme est calé sur 60Hz, il scintillera avec la technologie de 3D, ou alors, il affiche deux fois la même image. L'histoire que cela dépend beaucoup de la SDL et de comment elle a créer sa surface.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  6. #6
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Ah, je me doutais que tu répondrais, j'avais lu plusieurs de tes interventions ^^
    Sur la section SDL ,y'a de forte chance que j'y réponde effectivement ^^

    Sinon oui tu as bien compris mon code

    Mais c'est quand même rageant de voir que si une scène demande très ponctuellement plus de temps de calcul pour le rendu, alors qu'on peut avoir du temps de disponible à la fin du précédent rendu, ben on ne l'utilise pas et on fait un SDL_Delay()... j'imagine qu'il n'y a pas de solution, à part faire du 100% CPU ?
    Bah pour faire plus simple en général tu fais tout tes calcul , quand tu les a tous fait ben tu fais un Delay , inutile de prendre 100% de CPU,mais je comprend que tu veux prévoir au cas ou ça demande plus de calcul.
    Franchement tu devrais pas t’inquiéter pour ces temps 'perdu' , même sur un jeu 3D , je fais animation squeletal/collision en 3D cote CPU et j'arrive a environ plus ou moins a 10% de CPU.
    Pour les jeux 2D pareil si t'arrive pas avoir un fps correct c'est que y a un souci sur ton code , inutile de demander plus de CPU , y a toujours moyen optimiser , on arrivais bien a faire un steet fighter sur une snes a 1,79 mhz , c'est pas avec un ordi de plus 1 Ghz que tu vas avoir un souci en 2D sauf si le code est mal foutu.
    Sur la SDL ce qui prend le plus de CPU c'est le rendu.
    Je trouve ça inutile d'utiliser deux thread , sauf si calcul important en demande , mais je me demande réellement quel type de jeux en demande vraiment...

    Sinon pour les fps , 60 fps en SDL c'est faisable plus sur une basse résolution , en fait a part les jeux 2D qui possède de nombreuse animation par frame 60 fps c'est trop tu passera ton temps a afficher la même image.
    Après si ça peut te rassurer ,ma méthode je utilise sur tous mes jeux (2D ou 3D).

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2010
    Messages
    21
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2010
    Messages : 21
    Points : 35
    Points
    35
    Par défaut
    Pour le coup des threads, je m'y hasarderais pas trop avec la SDL, il me semble avoir lu qu'on ne peut effectuer de rendu que depuis le thread ayant initialisé la bibliothèque.

    Sinon oui tu as bien compris mon code
    Yeah, je vais pouvoir tranquillement poursuivre mon apprentissage de la SDL du coup ^^

    on arrivais bien a faire un steet fighter sur une snes a 1,79 mhz , c'est pas avec un ordi de plus 1 Ghz que tu vas avoir un souci en 2D sauf si le code est mal foutu
    J'avais déjà l'intention d'utiliser la manière de faire que tu m'as montré, mais c'est à peu prêt à ce moment que tu m'as complètement convaincu, c'est tout simplement l'argument du siècle

    En tout cas, merci beaucoup à vous 2, tout est bien plus clair ! Je mets le sujet en résolu dès que j'aurais trouvé comment faire...

  8. #8
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Pour l'histoire des threads, je l'ai fait avec la SDL et effectivement c'est la boucle d'update que je passe au thread (donc cela reste possible).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  9. #9
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    Citation Envoyé par Elindur Voir le message
    Yeah, je vais pouvoir tranquillement poursuivre mon apprentissage de la SDL du coup ^^
    N’hésite pas alors a poser des question si tu es bloqué
    Niveau SDL a part les FPS et les évènements a bien contrôlé (parce que c'est assez primordiale) , le reste doit pas poser de souci , (charger/afficher/fenêtre , doit pas causer trop de souci a mon avis).
    Après ce sont des codes plus généralistes (qui est donc pas attaché a la SDL) , comme animation ,collision ect.
    Surtout que quand c'est fait on y retouche plus, le code de fps que je t'ai montré doit avoir facile 3 ans.

    J'avais déjà l'intention d'utiliser la manière de faire que tu m'as montré, mais c'est à peu prêt à ce moment que tu m'as complètement convaincu, c'est tout simplement l'argument du siècle
    he he ^^
    Ben faut dire que je m’intéresse pas mal au technique de époque,tant optimisation mémoire que CPU.
    Par exemple pour la SFML ,elle est vraiment utile que pour les jeux 2D en haute résolution(et donc avoir des tileset en haute résolution) et que les tileset sont pas du pixel art (de toute façon du pixel art HD c'est super rare).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment faire pour créer une boucle ?
    Par Arko76 dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 02/04/2007, 17h14
  2. [XSLT] Comment créer une boucle
    Par Kefass dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 28/02/2007, 21h57
  3. [PHP-JS] Comment créer une boucle avec des headers
    Par djinnwatcher dans le forum Langage
    Réponses: 10
    Dernier message: 17/07/2006, 15h48
  4. Comment créer une boucle ?
    Par kikica dans le forum Langage
    Réponses: 5
    Dernier message: 15/03/2006, 21h02
  5. [XSLT]créer une boucle
    Par fraoustin dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 11/01/2005, 14h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo