Je suis actuellement en train de coder un jeu assez connu sous le nom de "fish" en C avec la SDL, où il faut manger des poissons plus petits que nous pour grossir (comme agar.io au final mais sans les cercles ). J'ai décidé d'animer les poissons en utilisant des sprites sur un site qui en vend (j'ai pris les gratuits). En gros, le jeu commence avec notre poisson qui apparait au milieu de l'écran, et plusieurs poissons apparaissent au fil du temps, de taille variable et proportionnelle à celle de notre poisson (qui peuvent être jusqu'à 1.5 fois plus gros).
(un petit apperçu du jeu )
J'ai donc réfléchi longuement à un problème ; comment faire grossir le poisson que j'ai (et donc faire grossir ses animations) pendant le jeu ?
J'ai pensé à SDL_gfx, puisque l'on peut zoomer avec.
Mais j'ai rencontré un problème qui m'a amené à poster ce sujet : lorsque les poissons sur la map sont plus gros, les animations se font moins rapidement ... pourquoi ? est-ce dû au fait que blitter des images plus grosses est plus long ou est-ce mon code ?
Voilà le bout de code qui traite l'évolution et l'animation (l'animation n'est pas encore dans une fonction pour que vous puissiez voir comment j'ai fait)
//INITIALISATION
SDL_Event event;
while (continuer == 1)
{
SDL_PollEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = -1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
continuer = -1;
break;
//...déplacement
}
break;
case SDL_KEYUP:
switch (event.key.keysym.sym)
{
//...déplacement
}
break;
}
//avant que l'on rentre dans le code problématique, quelques infos :
//la structure "monAnim" et "adversaires" comportent tout ce qui est sprites, tailles, positions, ... des poissons (du notre pour monAnim et des adversaires pour l'autre)
//tempsMaintenant et tempsPrecedent sont juste des int pour pouvoir calculer les fps (pareil pour lastTime et newTime, je sais pas trop pourquoi j'ai fait 2 variables mais c'est pas le problème xD)
//ecran et fond sont des SDL_Surface *
//et après je crois que c'est plutôt clair ; si y'a un truc que vous comprenez pas, demandez moi
tempsMaintenant = SDL_GetTicks();
if(tempsMaintenant - tempsPrecedent > 1000/FPS && continuer==1) //réglage des FPS
{
update(&monAnim); //là je mets à jour les poissons ( pour les déplacements)
for(i=0;i<NB_ADVERSAIRES_MAX;i++)//pour chaque poisson qui existe
if(adversaires[i].vivant==1)//et qui soit vivant
updateAdv(&adversaires[i]);//j'update differement, je les fais se déplacer aléatoirement
clipper.x = monAnim.oldPos.x; //là j'utilise la technique du clipper pour optimiser mes animations _ ici c'est celui du poisson du joueur
clipper.y = monAnim.oldPos.y;
clipper.h = monAnim.animsEntite[monAnim.etat].taille_Y;
clipper.w = monAnim.animsEntite[monAnim.etat].taille_X;
SDL_SetClipRect(ecran,&clipper);
positionFond.x = 0;
positionFond.y = 0;
SDL_BlitSurface(fond, NULL, ecran, &positionFond);
SDL_SetClipRect(ecran,NULL);
monAnim.oldPos.x = monAnim.position.x;
monAnim.oldPos.y = monAnim.position.y;
//...j'affiche aussi le score avec un autre clipper
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
{
if(adversaires[i].vivant==1) //je fais le clipper pour tous les autres poissons ennemis sur la map
{
clipper.x = adversaires[i].oldPos.x;
clipper.y = adversaires[i].oldPos.y;
clipper.h = adversaires[i].animsEntite[adversaires[i].etat].taille_Y;//ça faut pas en avoir peur, c'est juste la taille en pixel du poisson en question (parce que j'ai plusieurs sortes de poissons)
clipper.w = adversaires[i].animsEntite[adversaires[i].etat].taille_X;
SDL_SetClipRect(ecran,&clipper);
positionFond.x = 0;
positionFond.y = 0;
SDL_BlitSurface(fond, NULL, ecran, &positionFond);
SDL_SetClipRect(ecran,NULL);
adversaires[i].oldPos.x=adversaires[i].position.x;
adversaires[i].oldPos.y=adversaires[i].position.y;
}
}
//(les clippers servent à "effacer" les poissons de l'écran et éviter d'effacer tout l'écran et réafficher un a un les poissons (+le fond + les scores ... bref ))
SDL_BlitSurface(monAnim.animsEntite[monAnim.etat].anim[monAnim.animActuelle],NULL,ecran,&monAnim.position); //je blitte notre poisson
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
if(adversaires[i].vivant==1)
SDL_BlitSurface(adversaires[i].animsEntite[adversaires[i].etat].anim[adversaires[i].animActuelle],NULL,ecran,&adversaires[i].position);//et là les autres
SDL_BlitSurface(texte, NULL, ecran, 0); //là c'est juste le score
SDL_Flip(ecran);
//là ça serait la fin de la fonction affichage
monAnim.tempsActuel = SDL_GetTicks();
if(monAnim.tempsActuel - monAnim.tempsPasse > monAnim.temps) //changement d'anim pour notre poisson
{
if(monAnim.animActuelle+1<monAnim.animsEntite[monAnim.etat].anims_totales)
{monAnim.animActuelle++;}
else
{monAnim.animActuelle=0;}
monAnim.tempsPasse = monAnim.tempsActuel;
}
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
{
if(adversaires[i].vivant==1)
{
adversaires[i].tempsActuel = SDL_GetTicks();
if(adversaires[i].tempsActuel - adversaires[i].tempsPasse > adversaires[i].temps) //changement d'anim pour tous les autres
{
if(adversaires[i].animActuelle+1<adversaires[i].animsEntite[adversaires[i].etat].anims_totales)
{adversaires[i].animActuelle++;}
else
{adversaires[i].animActuelle=0;}
adversaires[i].tempsPasse = adversaires[i].tempsActuel;
}
}
}
continuer = verification(&monAnim,adversaires,ecran);//je vérifie ce qui se passe. le "continuer =" c'est parce que cette fonction renvoit 1 pour "il ne s'est rien passé" et des valeurs différentes sinon. Et ce continuer est
tempsPrecedent = tempsMaintenant;
}
else if (continuer==1)
{
SDL_Delay((1000/FPS)-(tempsMaintenant-tempsPrecedent)); //FPS
}
}
//FIN DU JEU
Je suis désolé de mettre 150 lignes :/
J'ai fait de mon mieux pour commenter et pour résumer, mais si vous ne comprenez pas quelque chose demandez moi.
Au final, dès que les poissons sont un peu plus gros que la base, le jeu commence à ralentir et j'ai aussi remarqué qu'il prenait de plus en plus de CPU à chaque fois que tout le monde grossissait ......
Bref, j'espère que quelqu'un pourra m'aider !
Cordialement,
Un petit geek
EDIT : en fait, ça ne bug pas, c'est seulement que les animations sont moins fluides .... je suis désolé d'avoir posté ce sujet inutile xD est-ce que en attendant quelqu'un d'expérimenté pourrait me dire s'il y a des choses incohérentes dans mon code ? et après je mettrai en résolu ;)
Tu devrais passer à la SDL 2.0 , le 'blittage' y est beaucoup plus rapide, et la gestion des touches du clavier est plus en adéquation avec ce qui existe (disons plus universelle). Voici un tutoriel sur la SDL 2.x : https://zestedesavoir.com/tutoriels/1014/utiliser-la-sdl-en-langage-c/
Il faut tester le retour de SDL_PollEvent() (avec un while pour dépiler tout) une bonne structure est ainsi :
Init(); // Chargement des surfaces
while (continuer)
{
while (SDL_PollEvent(&event))
{
switch(event.type) // Traitement des évènements
{
// ..
}
}
Actualisation(); // Mise à jour des positions en fonction du traitement des évènements
Affichage(); // Blit puis Flip
GesFrame(); // Gestion du nombre d'affichages / seconde
}
Fin(); // Free, Quit ...
Je vais mettre la SDL2 est-ce que cela change beaucoup de chose à la 1 ? je veux dire est-ce que je vais devoir reprendre tout mon code ?
[...]
Avec la SDL 2.0 le plus courant est d'utiliser le type 'SDL_Renderer' sous forme de pointeur pour y coller des SDL_Texture (elles aussi sous forme de pointeurs). Les SDL_Surface* sont utilisés comme intermédiaire entre les textures sous forme de fichiers sur un support de stockage (fichiers png ou bmp, etc..) et les SDL_Texture* qui sont stockés la plupart du temps dans la mémoire de la carte graphique.
Tu verra tout ça si tu suis le tuto que j'ai mis en lien. Utiliser la SDL2 n'est pas plus compliqué que la SDL1.2 , il y a toujours des bonnes pratiques comme vérifier que la SDL a bien été initialisée, les textures ont été correctement chargées, etc...
[...]Les SDL_Surface* sont utilisés comme intermédiaire entre les textures sous forme de fichiers sur un support de stockage (fichiers png ou bmp, etc..) [...]
Plutôt inexact. En fait les SDL_Surface sont en RAM et ne sont tout simplement plus utiles en SDL 2 à une ou deux exceptions près. Pour l'instant la seule raison (presque) valable d'utiliser une SDL_Surface (que j'aie pu trouver) est qu'il est dangereux de créer une texture dans un thread, donc j'en sort une surface à convertir en texture dans le programme principal... Et encore, le thread pourrait sortir un RWops (virtualisation de fichier) et ensuite en extraire directement une texture. Oui, SDL_img() charge des surfaces et passe par la conversion surface -> texture, mais ce n'est pas notre problème.
Ceci dit, SDL_Gfx() est très clairement très lent et peut vite plomber le fps d'un jeu.
Passer de la SDL1 à la 2 peut prendre un peu de temps surtout si tu codes tout dans ton main. Bien lire la doc, il y a quelques changements au-delà des surfaces/textures. Notamment les entrés qui passent de keysym à scancode, vu ce que tu veux en faire... Au moins, il sera possible d'abandonner SDL_Gfx() et d'avoir des transformations "natives" d'une rapidité fulgurante.
[...]Les SDL_Surface* sont utilisés comme intermédiaire entre les textures sous forme de fichiers sur un support de stockage (fichiers png ou bmp, etc..) [...]
Plutôt inexact. En fait les SDL_Surface sont en RAM et ne sont tout simplement plus utiles en SDL 2 à une ou deux exceptions près. Pour l'instant la seule raison (presque) valable d'utiliser une SDL_Surface (que j'aie pu trouver) est qu'il est dangereux de créer une texture dans un thread, donc j'en sort une surface à convertir en texture dans le programme principal... Et encore, le thread pourrait sortir un RWops (virtualisation de fichier) et ensuite en extraire directement une texture. Oui, SDL_img() charge des surfaces et passe par la conversion surface -> texture, mais ce n'est pas notre problème.
Ceci dit, SDL_Gfx() est très clairement très lent et peut vite plomber le fps d'un jeu.
Passer de la SDL1 à la 2 peut prendre un peu de temps surtout si tu codes tout dans ton main. Bien lire la doc, il y a quelques changements au-delà des surfaces/textures. Notamment les entrés qui passent de keysym à scancode, vu ce que tu veux en faire... Au moins, il sera possible d'abandonner SDL_Gfx() et d'avoir des transformations "natives" d'une rapidité fulgurante.
Bonne continuation.
Bonjour à toi,
Merci beaucoup pour ces précisions !
J'ai seulement une question ; comment abandonner SDL_gfx ? quelle est la solution "fulgurante" dont tu me parles ?
j'ai également une autre question (eh oui, je code même à cette heure là xD) concernant quelque chose qu'on appelle d'après ce que j'ai compris la collision ; quand deux poissons se touchent, alors y'en a un des deux qui mange l'autre. Donc pour voir s'ils se touchent, je compare les positions relatives des poissons. Cependant, je compare ainsi des "rectangles" sauf qu'en réalité, les poissons à l'intérieur de ces rectangles ne se touchent pas...
Cet exemple devrait être plus parlant
Ici, j'ai mon poisson qui meurt parce que son "rectagle" a touché celui du bleu. Ma question est la suivante : Est-il possible de ne prendre en compte non pas les rectangles mais les figures à l'intérieur avec la SDL 1 ou 2 ?
[...]Les SDL_Surface* sont utilisés comme intermédiaire entre les textures sous forme de fichiers sur un support de stockage (fichiers png ou bmp, etc..) [...]
Plutôt inexact. En fait les SDL_Surface sont en RAM et ne sont tout simplement plus utiles en SDL 2 à une ou deux exceptions près. Pour l'instant la seule raison (presque) valable d'utiliser une SDL_Surface (que j'aie pu trouver) est qu'il est dangereux de créer une texture dans un thread, donc j'en sort une surface à convertir en texture dans le programme principal... Et encore, le thread pourrait sortir un RWops (virtualisation de fichier) et ensuite en extraire directement une texture. Oui, SDL_img() charge des surfaces et passe par la conversion surface -> texture, mais ce n'est pas notre problème.
Ceci dit, SDL_Gfx() est très clairement très lent et peut vite plomber le fps d'un jeu.
Passer de la SDL1 à la 2 peut prendre un peu de temps surtout si tu codes tout dans ton main. Bien lire la doc, il y a quelques changements au-delà des surfaces/textures. Notamment les entrés qui passent de keysym à scancode, vu ce que tu veux en faire... Au moins, il sera possible d'abandonner SDL_Gfx() et d'avoir des transformations "natives" d'une rapidité fulgurante.
Bonne continuation.
En fait , je voulais dire que Les SDL_Surfaces sont intermédiaires entre les SDL_Textures qui sont souvent en VRAM "et" Les fichiers de textures (png, bmp, etc..) je savais que les SDL_Surfaces résidaient en RAM. Je me suis mal exprimé et je m'en excuse.
Tu devrais passer à la SDL 2.0 , le 'blittage' y est beaucoup plus rapide, et la gestion des touches du clavier est plus en adéquation avec ce qui existe (disons plus universelle). Voici un tutoriel sur la SDL 2.x : https://zestedesavoir.com/tutoriels/1014/utiliser-la-sdl-en-langage-c/
- Edité par Warren79 25 février 2018 à 9:59:17
Je viens de me rendre compte à la suite de plusieurs tests que c'est bien le blittage qui est vraiment pas le fort de la SDL (ou de mon code ...) puisque sans les animations, dès que je mets en plein écran et dès qu'il y a des figures "grandes" à afficher, ça commence à ne plus être fluide ...
Par contre, lorsque je ne suis pas en plein écran et que je réduis la taille de la fenêtre de moitié, là c'est très fluide ...
Donc je ne comprends pas tout, alors si quelqu'un a une explication je suis preneur
Ok, si on dit que la SDL est "lente", ce n'est qu'un relent du siècle dernier. En effet, aux début de la SDL (fin 90/ début 2K) les PC présentaient des performances, disons un peu moindre à ceux d'aujourd'hui. Aujourd'hui même un pc bon marché absorbe sans souci le boulot d'un pc de l'époque. Un I7 actuel, c'est au bas mot 300% d'un pentium II de l'époque.
Donc, la SDL a été lente, ce n'est plus vraiment significatif aujourd'hui tant qu'on ne fait pas n'importe quoi, surtout avec le rotozoom qui, lui, est vraiment significativement lent, même de nos jours. J'imagine que tu l'utilises pour agrandir tes poissons... Dans ce cas, tu as tout intérêt à ne pas faire tes zooms à la volée. Idéalement, tu devrais préparer tes surface avant de lancer le jeu. Par exemple, pour chaque poisson, tu te fais une table de SDL_Surface* dans laquelle tu auras passé ton poisson au rotozoom avec un rapport allant crescendo. Comme ça, tes différentes tailles de poissons sont prêtes et tu t'épargnes le rotozoom pendant l'exécution du jeu.
La différence entre un affichage en fenêtre et le full screen n'entre pas en ligne de compte et c'est la carte graphique qui s'en charge. Donc à moins d'avoir une Rage ou une GeForce 2 auquel cas, tu ne pourrais probablement même pas afficher le bureau de ton OS, il n'y a pas de souci. En plus, rien n'est plus "grand", c'est pareil, juste étiré.
Si tu vas voir dans ma signature, il y a une version SDL1 de mon jeu revolver, c'est du 1280*720 avec par moment beaucoup de sprites, 2 plans et même du rotozoom, et j'ai quand-même du le limiter sans quoi je suis entre 250 et 300 de fps. Sachant qu'en moyenne, le fps utile est de 60 (inutile d'avoir plus d'images que ne peut en afficher le moniteur généralement en 60Hz, parfois en 100Hz), ça laisse de la marge.
Ok, ça a presque doublé en passant sur la SDL2.
Après, ce n'est pas forcément moins fluide, il est possible qu'on perçoive mieux les petits défauts quand l'image est plus grande. Par exemple imagine que ton sprite se déplace de 10 en 10 pixels. En fenêtre, tu as un rapport de 1, donc ton sprite se déplace effectivement de 10 pixels/image et ça semble fluide. Si tu as un gros rapport en fullscreen, disons de 3, ton déplacement va passer à 30 pixels/image, ce qui peut donner une impression de "saut". Et ça va aller en s’aggravant quand le rapport va augmenter et le "saut" va carrément se transformer en téléportation.
Il est également possible qu'il y ait une mauvaise gestion dans ton code... Mais sans le code, impossible à dire.
Plus que les Blit, c'est le Flip qui prend du temps; mais même en plein écran SDL 1.2 est largement suffisante pour du 50 à 100 FPS et donc pas de problème de fluidité.
Peut-être que ta gestion de FPS n'est pas bonne, fais voir ton code ...
Je veux bien mettre mon code, mais il fait 1 000 lignes en tout le code concerné est plus au dessus, mais je vous le remet (j'ai modifié quelques trucs).
while (continuer == 1)
{
tempsDepart = SDL_GetTicks();
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
continuer = -1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
//La je regarde les touches ...
break;
case SDL_KEYUP:
//La je regarde encore les touches etc ...
break;
}
}
/***ANIM***/
newtime[0] = SDL_GetTicks();
if(newtime[0] - lasttime[0] > 200) //changement de direction probable => je lance un dé pour chacun des poissons pour les faire changer de direction aléatoirement ou pas toutes les 200 ms
{
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
if(adversaires[i].vivant==1)
changeDirection(&adversaires[i]);
lasttime[0] = newtime[0];
}
newtime[1] = SDL_GetTicks();
if(newtime[1] - lasttime[1] > 500) //spawn probable => je lance encore un dé qui détermine si un poisson spawn toutes les 500 ms
{
nouveau(&ajoutAdversaire);
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
if(adversaires[i].vivant==0)
if(ajoutAdversaire==1)
{
adversaires[i].vivant=1;
spawn(&adversaires[i],ecran,0,monAnim.poids);
ajoutAdversaire = 0;
break;
}
lasttime[1] = newtime[1];
}
newtime[2] = SDL_GetTicks();
if(newtime[2] - lasttime[2] > 10) //mouvement => j'update les positions des poissons toutes les 10 ms et du "poisson du joueur"
{
update(&monAnim);
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
if(adversaires[i].vivant==1)
updateAdv(&adversaires[i]);
lasttime[2] = newtime[2];
}
if(continuer==1)
continuer = verification(&monAnim,adversaires,ecran,*sons); //je vérifie si il y a collision
//ici je fais varier les anims
monAnim.tempsActuel = SDL_GetTicks();
if(monAnim.tempsActuel - monAnim.tempsPasse > monAnim.temps) //changement d'anim
{
if(monAnim.animActuelle+1<monAnim.animsEntite[monAnim.etat].anims_totales)
{monAnim.animActuelle++;}
else
{monAnim.animActuelle=0;}
monAnim.tempsPasse = monAnim.tempsActuel;
}
//ici je fais varier les anims des bots
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
{
if(adversaires[i].vivant==1)
{
adversaires[i].tempsActuel = SDL_GetTicks();
if(adversaires[i].tempsActuel - adversaires[i].tempsPasse > adversaires[i].temps) //changement d'anim
{
if(adversaires[i].animActuelle+1<adversaires[i].animsEntite[adversaires[i].etat].anims_totales)
{adversaires[i].animActuelle++;}
else
{adversaires[i].animActuelle=0;}
adversaires[i].tempsPasse = adversaires[i].tempsActuel;
}
}
}
clipper.x = monAnim.oldPos.x;
clipper.y = monAnim.oldPos.y;
clipper.h = monAnim.animsEntite[monAnim.etat].taille_Y;
clipper.w = monAnim.animsEntite[monAnim.etat].taille_X;
SDL_SetClipRect(ecran,&clipper);
positionFond.x = 0;
positionFond.y = 0;
SDL_BlitSurface(fond, NULL, ecran, &positionFond);
SDL_SetClipRect(ecran,NULL);
monAnim.oldPos.x = monAnim.position.x;
monAnim.oldPos.y = monAnim.position.y;
clipper.h = texte->h;
clipper.w = texte->w;
sprintf(score, "Fattitude : %d / %d",monAnim.poids,POIDS_GAIN);
texte = TTF_RenderText_Blended(police, score, couleur);
clipper.x = 0;
clipper.y = 0;
SDL_SetClipRect(ecran,&clipper);
positionFond.x = 0;
positionFond.y = 0;
SDL_BlitSurface(fond, NULL, ecran, &positionFond);
SDL_SetClipRect(ecran,NULL);
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
{
if(adversaires[i].vivant==1||adversaires[i].vivantAvant==1)
{
if(adversaires[i].vivantAvant==1)
adversaires[i].vivantAvant=0;
clipper.x = adversaires[i].oldPos.x;
clipper.y = adversaires[i].oldPos.y;
clipper.h = adversaires[i].animsEntite[adversaires[i].etat].taille_Y;
clipper.w = adversaires[i].animsEntite[adversaires[i].etat].taille_X;
SDL_SetClipRect(ecran,&clipper);
positionFond.x = 0;
positionFond.y = 0;
SDL_BlitSurface(fond, NULL, ecran, &positionFond);
SDL_SetClipRect(ecran,NULL);
adversaires[i].oldPos.x=adversaires[i].position.x;
adversaires[i].oldPos.y=adversaires[i].position.y;
}
}
//Au dessus, on clippe tous les poissons à l'écran et on met à jour les scores
SDL_BlitSurface(monAnim.animsEntite[monAnim.etat].anim[monAnim.animActuelle],NULL,ecran,&monAnim.position);
for(i=0;i<NB_ADVERSAIRES_MAX;i++)
if(adversaires[i].vivant==1)
SDL_BlitSurface(adversaires[i].animsEntite[adversaires[i].etat].anim[adversaires[i].animActuelle],NULL,ecran,&adversaires[i].position);
//ici, on affiche les poissons à l'écran
SDL_BlitSurface(texte, NULL, ecran, 0);
SDL_Flip(ecran);
//gestion des FPS ( d'après ce que j'ai compris, c'est ce qu'il faut. j'ai réglé la variable FPS à 60)
if(1000/FPS>SDL_GetTicks()-tempsDepart)
SDL_Delay((1000/FPS)-(SDL_GetTicks()-tempsDepart));
}
Je pense que le problème c'est que je bouge mon poisson à 10 px oui et donc c'est fluide en petit mais pas en grand ; voici le bout code qui correspond à la gestion de la distance (c'est dans update() et updateAdv() ):
La fonction updtate pour les adversaires ; elle est différente puisqu'ils rebondissent sur les bords ( j'ai voulu démarrer avec des trucs simples xD) :
Voilà en espérant que cela peut vous aider à m'aider
Si vous avez besoin d'autre chose comme code, demandez moi.
Bonne soirée !
PS : pour les vitesses je les ai initialisées comme ça :
monAnim->vitesse=6;
//ça c'est pour mon poisson
monAnim->vitesse=(rand() % (VITESSE_MAX - 3 + 1)) + 3;
//ça c'est une vitesse comprise entre 3 et 4 pour l'instant pour les poissons ennemis
Mais du coup j'ai 36 % de CPU utilisé alors que j'ai un bon pc ... :o
Et maintenant que tu me le dis, c'est ce que ça me faisait : le jeu commençait tranquille, et au bout d'un moment le CPU utilisé augmentait jusque n'en plus pouvoir et ça buggait x)
tu as d'autres idées ? Peut être que c'est seulement à cause de gfx, mais j'ai testé sans jouer, c'est à dire juste faire apparaitre 6 poissons gros sur l'écran et les animer et ça bugge de ouf ...
Merci pour ta réponse rapide !
edit : ce que je remarque par contre c'est que plus la taille des poissons à l'écran augmente, plus ça bug ... et le CPU reste le même depuis que j'ai bien réglé les FPS donc c'est pas ça non plus ... :/
et la mémoire ? Le CPU c'est une chose, mais la mémoire ? Elle augmente ?
Ou charges tu tes ressources ? Comment les charges tu ? Surtout ton image de fond, est elle en VRAM avec le même display format que la surface screen ?
Que fait ta fonction spawn ?
Voici un exemple ou je déplace 2000 balles en même temps de façon fluide avec SDL 1.2
D'après ce que tu montres la boucle principale devrait tourner avec une période de 16ms. Pour le vérifier tu peux enrichir le code ainsi :
if(1000/FPS>SDL_GetTicks()-tempsDepart)
SDL_Delay((1000/FPS)-(SDL_GetTicks()-tempsDepart));
else
printf("Surcharge CPU au temps = %i \n",SDL_GetTicks());
Il est assez difficile de s'y repérer dans toutes les conditions et je vois que tu rajoutes une condition liée au temps (ligne 58) pour les fonctions update().
Je te conseillerais de faire une mise à jour des positions une seule fois dans la boucle et sans condition de la forme : position = position + vitesse et avec les conditions tu travailles uniquement sur la valeur de "vitesse".
Autre chose pour ne pas avoir de saccades, cette équation doit être faite avec des float ou des doubles ( caster en int à la fin juste pour le blit).
@Léovendeville : n'hésite pas à découper ton code en fonctions plus petites (la taille idéale , c'est pas plus de 20 lignes par fonctions si tu le peux). Et ça rend le debuggage du programme plus facile.
Fvirtman, je te joins ci dessous quelques extraits de mon code qui correspond à ce que tu me demandes avec des commentaires (clairs j'espère ). La mémoire est fixe (par contre, vu que j'ai vérifié, j'ai vu qu'elle augmentait dans mon menu : même problème, j'avais pas libéré la surface "texte" avant de la re-remplir xD) et le CPU aussi ... Après tu verras, je charge tout avec des IMG_Load () parce que j'avais jamais appris les SDL_DisplayFormat ^^ et que veux tu dire par "Surtout ton image de fond, est elle en VRAM avec le même display format que la surface screen ?" ? Ma fonction spawn associe au nouveau poisson qui spawn une taille, une vitesse, une position, un état (bouge ou fixe) et un tableau de sprites pour l'animation, correspondant à la taille (voir en dessous).
Picosoft, merci pour tes conseils, je vais faire ça. Je comprends que ça ne soit pas trop clair mon code je sais pas trop comment faire pour que ça soit bien présenté et facile à comprendre ^^. Mais pourquoi il faudrait calculer avec des floats (ou double) pour les positions pour ensuite les caster ? ... ça ne revient pas au même ? quel est le but ?
Warren79, merci pour ton conseil ! j'avoue que j'aurais dû faire plusieurs fonctions pour ce qui est de l'affichage mais je voulais tester pour voir si cela fonctionne et après tout réorganiser en fonctions, mais je me doute que ce n'est pas la manière la plus logique de faire
temp = IMG_Load("Images/fond.jpg");
fond = SDL_DisplayFormat(temp);
fond = zoomSurface(fond,ZOOM_X,ZOOM_Y,0);
//ça c'est pour le fond, il est mis à l'échelle avec un zoom
//il est chargé dans la fonction principale "jeu"
//FONCTION INIT
for(j=0;j<2;j++)
{
for(i=0;i<monAnim->animsEntite[j].anims_totales;i++)
{
if(j==BOUGEPAS)
sprintf(nomImg, "Images/Poisson_%d/Poissons_bougePas/Poissons_bougePas_%d.png",sortePoisson,i);
else
sprintf(nomImg, "Images/Poisson_%d/Poissons_bouge/Poissons_bouge_%d.png",sortePoisson,i);
printf("%s\n",nomImg); //là je marque juste on s'en fout
monAnim->animsEntite[j].animBase[i] = IMG_Load(nomImg); //on ouvre l'image avec le nom
//Ce que je fais, c'est que je load tout en taille normale dans "anim.base" et après je la traite en dessous par exemple pour le spawn des bots
monAnim->animsEntite[j].animBase[i] = zoomSurface(monAnim->animsEntite[j].animBase[i],ZOOM_X,ZOOM_Y,0); //on met a l'echelle
if(monAnim->animsEntite[j].animBase[i] == NULL)
printf("fail");
}
}
Fvirtman, je viens de trouver la solution sur ton site avec tes cours sur la SDL, et c'est ce que tu m'avais dit plus haut sur SDL_DisplayFormat qui m'a mis la puce à l'oreille ; je me permets de citer, comme ça ça pourra aider d'autres (si cela ne te dérange pas bien sûr !) :
"Ce qui est intéressant est le SDL_DisplayFormat, ou je recrée une deuxième surface à partir de la première, qui aura comme particularité d'avoirCe qui est intéressant est le SDL_DisplayFormat, ou je recrée une deuxième surface à partir de la première, qui aura comme particularité d'avoir les mêmes propriétés que le "vidéo buffer", c'est à dire votre "screen". Si vous ne le faites pas, et que les surfaces n'ont pas le même format, elles sont converties à chaque blit : c'est long et lourd. Si vous le faites, vous gagnez énormément en vitesse."
J'ai donc simplement rajouté à chacun de mes load un displayformat et c'est nickel, je peux animer 40 poissons et le CPU reste en dessous de 10% :)
Soyons clair : Il n'y a rien en VRAM avec la SDL1.x. Pas sous Windows en tout cas et de mémoire, sous linux non-plus.
Très simple à démontrer :
if (SDL_Init(SDL_INIT_VIDEO)<0)
{/*initialisation de la SDL*/
fprintf(stderr, "Err initialisation SDL impossible : %s\n",SDL_GetError());
goto exit_err;
}
else
{
SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
printf("possible to create hardware surfaces=%s\n",(videoInfo->hw_available)? "yes" : "no");
printf("window manager available=%s\n",(videoInfo->wm_available)? "yes" : "no");
printf("hardware to hardware blits accelerated=%s\n",(videoInfo->blit_hw)? "yes" : "no");
printf("hardware to hardware colorkey blits accelerated=%s\n",(videoInfo->blit_hw_CC)? "yes" : "no");
printf("hardware to hardware alpha blits accelerated=%s\n",(videoInfo->blit_hw_A)? "yes" : "no");
printf("software to hardware blits accelerated=%s\n",(videoInfo->blit_sw)? "yes" : "no");
printf("software to hardware colorkey blits accelerated=%s\n",(videoInfo->blit_sw_CC)? "yes" : "no");
printf("software to hardware alpha blits accelerated=%s\n",(videoInfo->blit_sw_A)? "yes" : "no");
printf("color fills accelerated=%s\n",(videoInfo->blit_fill)? "yes" : "no");
}
La réponse à toutes les solutions hardware est non...
Les formats d'images les mieux adaptés sont les jpg (ou jpeg) pour tout ce qui est fond et png avec transparence pour les sprites.
Convertir les sprites avec SDL_DisplayFormatAlpha(). Avec des couleurs 32 bits bien entendu.
Reclipper des bouts du fond pour effacer tes sprites avant de les afficher de nouveau n'est pas nécessaire, reblit le tout. Quelle est ta définition de base ? Avec 2 plans de 1280*720 plus les sprites, j'avais encore plus de 200 affichages par seconde...
Bonne continuation.
Edit : Nouvelle mesure, j'ai changé de PC depuis :
Ben écoute je suis en 1920/1080 du coup, comme ça c'est grand et joli pour mon pc ; cependant, j'ai fait en sorte que ça s'adapte aux résolutions du joueur
J'ai fait en reblittant tout, et je crois que ça altère pas la qualité
Pour avoir le nb de fps max je vais essayer de coder ça avant d'aller me coucher et je te mets ça en édit
EDIT :
Voilà donc ça c'est en plein écran donc ça va beaucoup mieux grâce à displayformat par contre quand je le mets en 1920/2;1080/2 y'a 750 FPS xD
EDIT 2: wow en effet la différence est vraiment notable entre SDL et SDL2 Merci beaucoup drx !
En effet, DisplayFormat évite les conversions à chaque blit. (+ de 1 million de pixels à chaque fois !)
Tu ne m'as pas dit, quand tu charges ton image de fond (et tes poissons) c'est bien avant ta boucle, et une fois pour toutes ? (je pense que oui, sinon ton ordi serait bien à la ramasse)
Pour la différence entre SDL1 et SDL2, SDL1 utilise les technologies de blitting obsolètes des cartes graphiques. Elle permet de mettre les images en VRAM malgré tout : on peut faire l'essai en créant des surfaces avec SW_SURFACE ou HW_SURFACE.
Mais à l'heure actuelle, les cartes graphiques sont faites pour la 3D et uniquement la 3D.
Donc il est beaucoup plus rapide, même pour faire de la 2D, de créer un polygone sur le plan Z = 0 (la 2D n'est qu'un cas particulier de la 3D) et de le texturer ! C'est ce que fait SDL 2 .
Re, désolé d'insister, mais le HW_SURFACE ne sert à rien, il ne passe jamais :
SDL_Init(SDL_INIT_VIDEO);
/*contrôle tati tata*/
ecran = SDL_SetVideoMode(1280, 800, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
/*contrôle etc*/
if (ecran->flags & SDL_HWSURFACE)
fprintf(stdout, "utilise le HW\n");
else
fprintf(stdout, "Perdu...\n");
if (ecran->flags & SDL_DOUBLEBUF)
fprintf(stdout, "utilise le double buffering\n");
else
fprintf(stdout, "Ha ? Bin non plus...\n");
Le code du post plus haut démontrait déjà clairement que la SDL 1.x n'a accès à aucune solution matérielle. Je n'ai pas testé les autres plateformes (megadrive, psp etc) mais sous Win et Linux, il est sûr et certain que ça n'arrive pas.
En effet, DisplayFormat évite les conversions à chaque blit. (+ de 1 million de pixels à chaque fois !)
Tu ne m'as pas dit, quand tu charges ton image de fond (et tes poissons) c'est bien avant ta boucle, et une fois pour toutes ? (je pense que oui, sinon ton ordi serait bien à la ramasse)
Pour la différence entre SDL1 et SDL2, SDL1 utilise les technologies de blitting obsolètes des cartes graphiques. Elle permet de mettre les images en VRAM malgré tout : on peut faire l'essai en créant des surfaces avec SW_SURFACE ou HW_SURFACE.
Mais à l'heure actuelle, les cartes graphiques sont faites pour la 3D et uniquement la 3D.
Donc il est beaucoup plus rapide, même pour faire de la 2D, de créer un polygone sur le plan Z = 0 (la 2D n'est qu'un cas particulier de la 3D) et de le texturer ! C'est ce que fait SDL 2 .
Du coup bien sûr, je la charge qu'une fois, je connais ça t'inquiète Je ne savais pas la différence et maintenant je comprends merci je vais passer à la SDL_2 très bientot alors !
drx a écrit:
Re, désolé d'insister, mais le HW_SURFACE ne sert à rien, il ne passe jamais :
SDL_Init(SDL_INIT_VIDEO);
/*contrôle tati tata*/
ecran = SDL_SetVideoMode(1280, 800, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
/*contrôle etc*/
if (ecran->flags & SDL_HWSURFACE)
fprintf(stdout, "utilise le HW\n");
else
fprintf(stdout, "Perdu...\n");
if (ecran->flags & SDL_DOUBLEBUF)
fprintf(stdout, "utilise le double buffering\n");
else
fprintf(stdout, "Ha ? Bin non plus...\n");
Le code du post plus haut démontrait déjà clairement que la SDL 1.x n'a accès à aucune solution matérielle. Je n'ai pas testé les autres plateformes (megadrive, psp etc) mais sous Win et Linux, il est sûr et certain que ça n'arrive pas.
Bonne continuation.
D'accord merci donc au final la SDL_1 c'est la base, mais y'a complètement mieux, c'est ça ?
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr
Bonhomme !! | Jeu de plateforme : Prototype.
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr
Bonhomme !! | Jeu de plateforme : Prototype.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Mon site web de jeux SDL2 entre autres : https://www.ant01.fr
Bonhomme !! | Jeu de plateforme : Prototype.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Bonhomme !! | Jeu de plateforme : Prototype.