Bonjour,
J'ai un petit problème concernant les priorité d'affichage de sprites, dans un environnement 2D. Je commence par vous montrer une petite image, histoire qu'on parle tous de la même chose :
https://www.dropbox.com/s/5i1fkmj2wt...2015.37.36.png
Il y a les petits losanges, qui sont des éléments mobiles. Mon programme gère les évènements et je peux faire bouger ces losanges si je le désire.
Il y a aussi ce mur : c'est un élément qui ne peut pas bouger. Les losanges, s'ils sont derrière ce mur, doivent être affichés derrière le mur, c'est à dire que dans la boucle du programme, on affichera d'abord les losanges qui sont derrière le mur, et ensuite, on affiche le mur par dessus.
Voilà en gros le cadre.
S'il n'y avait pas ce mur, la gestion de la profondeur des losanges est très simple : je fais une std::list de pointeur sur sf::Sprite et à chaque boucle du programme, je trie cette liste avec une fonction de comparaison qui compare la position du point le plus bas de chaque losange. Un bout de code sera peut être un peu plus clair (en C++) :
Code c++ : 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 bool compare (sf::Sprite* & i, sf::Sprite* & j) { // on a préalablement mis l'origine des sprites sur le point le plus bas du losange, de sorte que // getPosition() retourne les coordonnées de ce point return i->getPosition().y < j->getPosition().y; } int main() { std::list<sf::Sprite*> liste; // une liste de pointeur sur sprites // on crée un vector de sf::Sprite et on fait pointer les éléments de liste sur les éléments // de ce vector // boucle du jeu // patati patata, on bouge les losanges liste.sort(compare); }
Voilà. Avec ça, les losanges sont affichés par ordre de position dans la fenetre.
Les problèmes arrivent quand j'ajoute le mur : sa base n'est pas horizontale, je définis donc un segment qui correspond à sa base (en diagonale donc). Ce segment est représenté par une paire de points. Puis je procède de la manière suivante : si le losange est au dessus de ce segment, on affiche d'abord le losange, et ensuite, le mur. Si le losange est en dessous, on affiche d'abord le mur, et ensuite le losange. Le principe est en gros le même que pour les losanges entre eux.
Mais la fonction de tri nécessite donc un traitement différent selon qu'elle compare deux losanges, ou un losange et un mur.
Je remanie donc ma liste : std::list<std::pair<sf::Sprite*,std::pair<sf::Vector2i,sf::Vector2i>*>> liste;
Pour les losanges, je n'ai pas besoin de définir un segment, leur position suffit au tri, je laisse donc le pointeur de la paire de points (std::pair<sf::Vector2i,sf::Vector2i>*) à NULL, c'est à dire qu'il ne pointe sur rien du tout. Pour le mur en revanche, ce pointeur pointera sur une paire de points et dans ma fonction de tri, je peux vérifier si la paire pointe sur quelque chose, ou non, autrement dit : si l'objet est statique ou dynamique.
Et la fonction de tri devient (en C++, encore) :
Code c++ : 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
20
21
22 bool compare (std::pair<sf::Sprite*,std::pair<sf::Vector2i,sf::Vector2i>*> & i, std::pair<sf::Sprite*,std::pair<sf::Vector2i,sf::Vector2i>*> & j) { // cette fonction renvoie vrai si i doit être derrière j, false sinon // si i statique et j dynamique if (i.second != NULL) return clockWise(i.second->first + sf::Vector2i(i.first->getPosition()), i.second->second + sf::Vector2i(i.first->getPosition()), sf::Vector2i(j.first->getPosition())); // si j statique et i dynamique if (j.second != NULL) return !clockWise(sf::Vector2i(j.first->getPosition()) + j.second->first, sf::Vector2i(j.first->getPosition()) + j.second->second, sf::Vector2i(i.first->getPosition())); // si i et j dynamiques else return i.first->getPosition().y < j.first->getPosition().y; }
Voilà où j'en suis. Ce code marche lorsqu'il n'y a dans la fenetre que un objet statique (le mur) et 1 ou 2 objets dynamiques (les losanges). Lorsque je mets plusieurs losanges, la profondeur entre eux est bien gérée, en revanche elle ne l'est pas avec le mur (le screenshot que j'ai mis en lien est juste un cas où ça marche, exceptionnellement).Et je n'arrive toujours pas à trouver mon erreur..
Je n'ai peut être pas été très clair dans mon explication, je peux bien sûr revenir sur certains points si cela est nécessaire.
À bientôt, merci par avance
Partager