Search code examples
c++sfmlviewport

How to know a sprite position inside a view, relative to window?


I have this sprite of a car that moves with varied speed.

It is inside a view and the view is moved to the left to keep the car always in the center of the window.

enter image description here

The view accompanies the displacement of the car, ie it is shifted to the left as the car accelerates or brakes. This way the car will always appear in the center.

But if for example it is overtaken by another car, it will be left behind. For it not to disappear from the window, I have to zoom in the view so that all the cars appear.

But for this, I need to know the position of the car in relation to the window (not in relation to the view).

getGlobalBounds().left or getPosition().x show the same value, which is the position relative to the view, not relative to the window, as shown in the image.

How to know a sprite position inside a view, relative to window?


Solution

  • After several hours of research, I finally find the easy way of achieve this. And yes, it was ridiculously easy.

    But first, I would like to clear up some misconceptions.

    getGlobalBounds().left or getPosition().x show the same value, which is the position relative to the view, not relative to the window, as shown in the image.

    In fact, those methods return the position in the world, not in the view nor in the window.

    You can have, for instance, a 500x500 window, with a 400x400 view, in a 10000x10000 world. You can place things in the world, outside of the view or the window. When the world is rendered, then the transformations of the view (translations, rotations, zoom, ...) are applied to the world and things are finally shown in the window.

    To know where a coordinate in the world is represented in the window (or any other RenderTarget) and vice versa, SFML actually have a couple of functions:

    RenderTarget.mapCoordsToPixel(Vector2f point)

    Given a point in the world gives you the corresponding point in the RenderTarget.

    RenderTarget.mapPixelToCoords(Vector2f point)

    Given a point in the RenderTarget gives you the corresponding point in the world. (this is useful to map mouse clicks to corresponding points in your world)

    Result

    enter image description here


    Code

    int main()
    {
        RenderWindow window({ 500, 500 }, "SFML Views", Style::Close);
    
        sf::View camera(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y));
        sf::Vector2f orig(window.getSize().x / 2, window.getSize().y / 2);
        camera.setCenter(orig);
        sf::Font f;
        f.loadFromFile("C:/Windows/Fonts/Arial.ttf");
        sf::Text t;
        t.setFont(f);
        sf::RectangleShape r;
        r.setPosition(10, 10);
        r.setSize(sf::Vector2f(20, 20));
        r.setOutlineColor(sf::Color::Blue);
        r.setFillColor(sf::Color::Blue);
    
        t.setPosition(10, 40);
    
        while (window.isOpen())
        {
            for (Event event; window.pollEvent(event);)
            if (event.type == Event::Closed)
                window.close();
            else if (event.type == Event::KeyPressed){
                camera.move(-3, 0);
                camera.rotate(5.0);
                camera.zoom(1.1);
            }
    
            auto realPos = window.mapCoordsToPixel(r.getPosition());
            std::string str = "Pos: (" + std::to_string(realPos.x) +","+ std::to_string(realPos.y) + ")";
    
            t.setString(str);
            window.clear();
            window.setView(camera);
            window.draw(r);
            window.draw(t);
            window.display();
        }
        return EXIT_SUCCESS;
    }