Bonjouur,
Je tombe présentement sur un nouveau problème dans mon projet : j'ai deux sf::CircleShape dans ma fenêtre, chacune représentant des stations de trains. Je voudrais détecter que je clique gauche sur une des stationis.
Mon problème est le suivant : j'instancie ma station qui est un sf::Drawable et sf::Transformable, je lui donne une position aléatoire dans ma fenêtre. Jusque là tout va bien, mais quand je récupère le getGlobalBounds, les coordonnées left & top sont le coin supérieur-gauche de la fenêtre.
Après plusieurs tests, je me suis aperçus que si je retire la ligne :
states.transform *= getTransform();
de ma méthode draw, mon setPosition ne fonctionne plus puisque la transformation n'est plus appliquée, ce qui m'obligerai à créer la méthode setPosition et l'appliquer à mon sf::CircleShape (ce que je n'ai pas fait.
Bref, donc mon setPosition n'est pas appliqué et ma statioon se retrouve donc... dans le coin supérieur-gauche de l'écran.
Ce qui veut dire que getGlobalBounds me renvoi non pas les coordonnées après transformation (ici un setPosition), mais avant. Pourtant la documentation SFML 2.6 dit que c'est lel getLocalBounds qui ignore les transformations.
Je précise : je n'ai paas testé d'appeler le getLocalBounds pour voir si j'avais une inversion des deux, mais j'ai en tout cas un comportement avec le getGloballBounds, différent de ce que m'indique la documentation.
Je vous laisse le code de mes deux classes.
Station.cpp :
#include "Station.h"
Station::Station()
{
m_station.setFillColor(convertHexaToColor("fae20a"));
m_station.setOutlineColor(convertHexaToColor("c5c5c5"));
m_station.setRadius(10);
m_station.setOutlineThickness(3);
m_station.setOrigin(m_station.getRadius(), m_station.getRadius());
}
Station::~Station()
{
//dtor
}
sf::FloatRect Station::getGlobalBounds() const
{
return m_station.getGlobalBounds();
}
void Station::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
target.draw(m_station, states);
}
Et Game.cpp qui est la classe qui gère le jeu :
#include <iostream>
#include "Game.h"
Game::Game(Window *window)
{
sf::Vector2u windowSize = window->getWindow()->getSize();
m_stations.push_back(Station());
m_stations.push_back(Station());
m_ground.setFillColor(sf::Color(255, 255, 255));
m_ground.setSize(sf::Vector2f(windowSize.x, windowSize.y));
m_ground.setPosition(0, 0);
m_stations[0].setPosition(rngInt(20, windowSize.x-20), rngInt(20, windowSize.y-20));
m_stations[1].setPosition(rngInt(20, windowSize.x-20), rngInt(20, windowSize.y-20));
window->loop([this](RenderWindow& win) { this->loop(win); });
}
Game::~Game()
{
//dtor
}
void Game::loop(RenderWindow& window)
{
sf::Event event;
window.setRunningLoop(true);
while (window.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
window.close();
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2f mousePos = window.mapPixelToCoords(sf::Mouse::getPosition(window));
std::cout << "Station bounds: Left=" << m_stations[0].getGlobalBounds().left << ", Top=" << m_stations[0].getGlobalBounds().top << ", Width=" << m_stations[0].getGlobalBounds().width << ", Height=" << m_stations[0].getGlobalBounds().height << std::endl << std::endl;
std::cout << "Station 0 position, x=" << m_stations[0].getPosition().x << ", y=" << m_stations[0].getPosition().y << std::endl;
std::cout << "Mouse position, x=" << mousePos.x << ", y=" << mousePos.y << std::endl;
std::cout << m_stations[0].getGlobalBounds().contains(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y) << std::endl << std::endl;
if (m_stations[0].getGlobalBounds().contains(mousePos))
{
std::cout << "Cliked station 0";
}
/*for (int i=0; m_stations.size(); i++)
{
if (m_stations[i].getGlobalBounds().contains(window.mapPixelToCoords(sf::Mouse::getPosition(window))))
{
std::cout << "Station " << i << " left cliked" << std::endl;
break;
}
}*/
}
}
window.clear();
window.draw(m_ground);
window.draw(m_stations[0]);
window.draw(m_stations[1]);
window.display();
}
Je précise que les coordonnées de la station obtenus avec getPosition sont bons, mais la méthode contains est utilisable sur un sf::FloatRect, donc getGlobalBounds ou getLocalBounds, du coup il ne détecte jamais mon clique SAUF dans le coin supérieur-gauche de l'écran, soit donc la position originelle avant mon setPosition de mon constructeur.
J'ai essayé de voir si ChatGPT pouvait m'aider, mais non, tout ce qu'il me dit ne fonctionne pas. D'après lui, c'est parce que je fais ma vérification avant l'application de la transformation, ce qui est logique vu qu'on gère les événements avant de réappliquer l'affichage. Mais d'un autre côté avant de pouvoir faiire mon clic, il a déjà affiché, donc déjà appliqué le setPosition du constructeur.
Et oui je sais ce que certains vont me dire : "T'embête pas, gère ta position aléatoire directement dans le constructeur de ton Station", oui j'y ai pensé, mais on doit pouvoir aussi changer la position à d'autres moments au besoin ; pas forcément ici pour les stations, mais d'autres éléments pourraient avoir ce besoin, donc j'aimerais comprendre pourquoi ces coordonnées totalement loufoque plutôt que les véritables coordonnées.
Merci d'avance à ceux qui pourront m'aider.