Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: [Résolu] getGlobalBounds : coin supérieur gauche ?  (Lu 655 fois)

0 Membres et 2 Invités sur ce sujet

christophedlr

  • Full Member
  • ***
  • Messages: 156
    • Voir le profil
    • E-mail
[Résolu] getGlobalBounds : coin supérieur gauche ?
« le: Décembre 14, 2024, 12:12:05 pm »
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.
« Modifié: Décembre 21, 2024, 09:33:42 am par christophedlr »

G.

  • Hero Member
  • *****
  • Messages: 1595
    • Voir le profil
Re: getGlobalBounds : coin supérieur gauche ?
« Réponse #1 le: Décembre 15, 2024, 01:17:00 am »
T'as 2 transformable, ta Station (puisqu'elle hérite de Transformable) et ta donnée membre m_station (qui est un CircleShape qui hérite aussi de Transformable).
Quand tu fais tes m_stations[0].setPosition(...) ils s'appliquent à ton transformable Station, mais pas à sa donnée membre m_station qui reste à sa position d'origine 0, 0. Ton m_station s'affiche correctement au bon endroit car tu récupères la transformation de Station avec ton getTransform() dans ta fonction draw.

Pour que ton Station::getGlobalBounds() renvoie ce que tu veux il faut donc aussi appliquer la transformation de Station à ton m_station avant de renvoyer ce rectangle, et si je me souviens bien ça donnerait :
getTransform().transformRect(m_station.getGlobalBounds());

Ensuite ça reste une détection de clic dans un rectangle/carré donc pas forcément idéal pour un Cercle mais ça c'est à toi de voir :p (les calculs pour voir si un point est dans un cercle sont très facile)
« Modifié: Décembre 15, 2024, 01:18:38 am par G. »

christophedlr

  • Full Member
  • ***
  • Messages: 156
    • Voir le profil
    • E-mail
Re: getGlobalBounds : coin supérieur gauche ?
« Réponse #2 le: Décembre 16, 2024, 08:33:18 pm »
Merci pour ta réponse, je teste ça samedi quand je vais me remettre dessus (j'ai un boulot toute la semaine, je bosse le jeu que le samedi du coup ^^), et je te dis ce qu'il en est ensuite.

christophedlr

  • Full Member
  • ***
  • Messages: 156
    • Voir le profil
    • E-mail
Re: getGlobalBounds : coin supérieur gauche ?
« Réponse #3 le: Décembre 21, 2024, 09:33:13 am »
Ca fonctionne merci beaucoup à toi. Juste le std::cout qui  se fait en retard (quand je ferme la fenêtre), mais on s'en fiche j'ai testé de mettre un window.close à la place et c'est bon, donc c'est nickel.

Merci beaucoup, je finissais par devenir dingue ;)

G.

  • Hero Member
  • *****
  • Messages: 1595
    • Voir le profil
Re: [Résolu] getGlobalBounds : coin supérieur gauche ?
« Réponse #4 le: Aujourd'hui à 12:30:50 am »
T'envoies ton texte dans le flux de cout mais pour qu'il l'affiche il faut que tu le std::flush ou std::endl (qui contient flush), sinon il flush pas, ou alors tout seul quand il veut (?) genre quand tu termines le programme.