-
Bonjour,
Tout d'abord j'espère exposer mon problème dans la bonne catégorie.
Voilà, j'aimerais pouvoir gérer toutes les résolutions possibles dans mon jeu, et selon ces critères :
- la proportion doit toujours être la même (ici 16:9)
- cela inclut donc de dessiner des bandes noires en haut et en bas de l'image si l'écran du PC n'est pas 16:9
- quelle que soit la résolution, l'image finale devra être toujours strictement la même et donc redimensionnée
J'ai pensé au système suivant mais il me semble quand même lourd.
Mes sprites sont destinés à des écrans 1920/1080
Si la résolution courante en est une autre, tous mes sprites seront redimensionnés et positionnés selon un ratio calculé à partir de la "différence" entre ma résolution 1920/1080 et la résolution courante.
De plus, si le format de l'écran n'est pas 16:9 il faut que je décale tous mes sprites vers le bas...
C'est quand même un sacré bordel tout ça :S
Ma question est donc la suivante : Avant de me lancer dans cette usine à gaz, existe-t'il un moyen plus simple de procéder ?
Merci à vous
Bonne soirée.
EDIT : J'espère avoir été clair, n'hésitez pas à me poser des questions si vous n'avez pas tout saisi.
-
Salut, je te conseillerais d'aller jeter un oeil sur les sf::View, ce qui éviterait de tout recalculer à la main.
-
Bonjour,
J'ai essayé d'utiliser sf::view pour résoudre ce problème mais je ne dois pas les utiliser comme il faut.
Voilà mon code qui doit permettre de répondre aux problématiques que j'ai exposé plus haut :
// Récupération de la résolution de l'écran du client et on crée la fenêtre en conséquence
sf::VideoMode clientVideoMode = sf::VideoMode::getDesktopMode();
// si le format d'écran n'est pas 16:9 on doit rajouter les bandes noires
if(clientVideoMode.width / clientVideoMode.height != 16/9)
{
// calcul de la taille de la bande noire du dessus
float decalY = (clientVideoMode.height - (clientVideoMode.width * 9 / 16)) / 2;
this->mainView = sf::View(sf::FloatRect(0, 0, 1920, 1080));
// On décale la vue vers le bas
this->mainView.move(sf::Vector2f(0, decalY));
}
else
{
this->mainView = sf::View(sf::FloatRect(0, 0, 1920, 1080));
}
// Pour finir on crée la fenêtre et on set la vue.
globals.window.create(clientVideoMode, "Abysses v0.1", sf::Style::Fullscreen);
globals.window.setView(this->mainView);
Voilà le code, le problème est que ça ne fonctionne pas du tout...
Quand l'écran est en 16:9 pas de soucis, mais si on tape dans le 16:10 ou le 4:3, pas de bandes noir, l'image prend tout l'écran quand même.
-
Par défaut une vue prend toute la fenêtre. Définis un viewport pour ta sf::View.
-
hmmm et quand je fais sf::View(sf::FloatRect(0, 0, 1920, 1080));
ça ne définie pas de ViewPort ?
-
Ben non, comme le dit la doc (http://www.sfml-dev.org/documentation/2.0/classsf_1_1View.php#a1d63bc49e041b3b1ff992bb6430e1326) ce rectangle définit la zone à afficher.
Le viewport (http://www.sfml-dev.org/documentation/2.0/classsf_1_1View.php#a8eaec46b7d332fe834f016d0187d4b4a) définit l'endroit de ta fenêtre où tu vas afficher le contenu de ta vue.
Tu peux aussi jeter un oeil à ce tutorial sur les vues (https://github.com/SFML/SFML/wiki/Tutorial:-Using-View) qui aborde rapidement les viewports pour faire un écran splitté ou une minimap.
Je pense que tu devrais trouver comment arriver à ce que tu veux une fois que t'auras joué un peu avec le viewport en en définissant un différent de 0, 0, 1, 1
-
Attention à ce test:
// si le format d'écran n'est pas 16:9 on doit rajouter les bandes noires
if(clientVideoMode.width / clientVideoMode.height != 16/9)
Tu fais des opérations sur des entiers.
Ainsi, avec un VideoMode en 16/9, en 10/9 ou 4/3, ça correspond à ceci:
if(1 != 1)
ce qui sera toujours évalué comme étant false.
Tu peux résoudre le problème en remplaçant les quotients par des produits comme ceci:
if(9 * clientVideoMode.width != 16 * clientVideoMode.height)
Pour ce qui est de créer la vue, voilà comment je ferais avec un viewport:
// Récupération de la résolution de l'écran du client et on crée la fenêtre en conséquence
sf::VideoMode clientVideoMode = sf::VideoMode::getDesktopMode();
// ceci est à faire de toute façon, donc je le mets hors du if
this->mainView = sf::View(sf::FloatRect(0, 0, 1920, 1080));
// si le format d'écran n'est pas 16:9 on doit rajouter les bandes noires
if(9 * clientVideoMode.width != 16 * clientVideoMode.height)
{
// calcul de la taille de la bande noire du dessus
float decalY = (clientVideoMode.height - (clientVideoMode.width * 9 / 16)) / 2;
// on l'exprime par rapport à la hauteur totale
float rapport = decalY / clientVideoMode.height;
// On applique le viewport
this->mainView.setViewport(sf::FloatRect(0.f, rapport, 1.f, 1.f-rapport*2));
}
// Pour finir on crée la fenêtre et on set la vue.
globals.window.create(clientVideoMode, "Abysses v0.1", sf::Style::Fullscreen);
globals.window.setView(this->mainView);
-
Holàlà oui effectivement...
Le test foirait à chaque fois, je pouvais attendre longtemps pour que ça marche...
Merci à vous deux en tout cas :)
-
Plutôt que de faire un test d'égalité avec 16/9, fais plutôt une comparaison : la fenêtre pourrait être encore plus longue que 16/9 ; du coup, il ne faut pas des barres noires en haut et en bas mais à droite et à gauche.
Ça peut arriver si l'utilisateur rétrécit verticalement la fenêtre (ou simplement si la barre de titre prend plus d'espace vertical que les bordures latérales), ou s'il utilise un des (encore rares) écrans super-larges, comme le toshiba U845W.
-
Ha oui exact. Merci, je n'avais pas pensé à ces cas là ^^
-
bonjour, je me suis inspiré de cette discussion pour faire ma propre gestion, seulement ça n'as pas l'air de marcher :-\.
Cela viens peut-être de ma compréhension douteuse de sf::View ou alors d'une faute banale que je ne décèle pas.
#include<SFML/Graphics.hpp>
int main()
{
sf::VideoMode videoMode = sf::VideoMode(500,500);//sf::VideoMode::getDesktopMode();
float ratio = 16/10;
sf::View view(sf::FloatRect(0, 0, 1600, 1000));
if( float(videoMode.width/videoMode.height) > ratio )
{
// marges verticales
float padX( ( videoMode.width - (videoMode.height*ratio) )/2 );
float relative( padX/videoMode.width );
view.setViewport(sf::FloatRect(relative, 0.f, 1.f-relative*2, 1.f));
}
else if( float(videoMode.width/videoMode.height) < ratio )
{
// marges horizontales
float padY( ( videoMode.height - (videoMode.width/ratio) )/2 );
float relative( padY/videoMode.height );
view.setViewport(sf::FloatRect(0.f, relative, 1.f, 1.f-relative*2));
}
sf::RenderWindow win(videoMode, "SANDBOX", sf::Style::Titlebar);
win.setView(view);
while(win.isOpen())
{
sf::Event event;
while(win.pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
win.close();
break;
default:
break;
}
}
sf::RectangleShape rectangle(sf::Vector2f(500,500));
rectangle.setFillColor(sf::Color::Green);
rectangle.setPosition(100, 50);
win.clear(sf::Color::White);
win.draw(rectangle);
win.display();
}
}
Je suis censé voir un carré et je vois un rectangle.
-
float(videoMode.width/videoMode.height)
Ca te donnera toujours un entier. Fais plutôt ça
float(videoMode.width) / videoMode.height
-
pareil pour le 16/10 au début ;)
Fais plutôt :
16/10.0f
-
Ah les floats je tombe toujours dans le piège :o
PS : ça marche à merveille, <3 sf::View.