Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [SOLVED] Sprite is drawn in incorrect position after RenderWindow is resized  (Read 1836 times)

0 Members and 1 Guest are viewing this topic.

CardsChris

  • Newbie
  • *
  • Posts: 2
    • View Profile
I've noticed a majorly strange issue in my project. Here is some very simplified code that still shows the issue:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
using namespace std;
int main()
{
    //path = current directory
    std::string path = "";
    const float defaultx = 1024;
    bool resized = false;
    const float defaulty = 768;
    sf::RenderWindow window(sf::VideoMode(defaultx, defaulty), "SFML works!");
    sf::Sprite s;
    sf::Sprite l;
    sf::Texture t;
    if (!t.loadFromFile(path + "Textures/playbutton.jpg")) {
        cout << "something went wrong" << endl;
    } else {
        s.setTexture(t);
        s.setOrigin(s.getTextureRect().getSize().x/2, s.getTextureRect().getSize().y/2);
        s.setPosition(sf::Vector2f(window.getSize().x/2, window.getSize().y/2));
    }
    while (window.isOpen())
    {
        window.clear();
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
            if (event.type == sf::Event::Resized) {
                resized = true;
                l.setTexture(t);
                l.setOrigin(l.getTextureRect().getSize().x/2, l.getTextureRect().getSize().y/2);
                l.setScale(sf::Vector2f(defaultx*0.5/window.getSize().x, defaulty*0.5/window.getSize().y));
                l.setPosition(sf::Vector2f(window.getSize().x/2, window.getSize().y/2));
                s.setScale(sf::Vector2f(defaultx/window.getSize().x, defaulty/window.getSize().y));
//                s.setPosition(sf::Vector2f(window.getSize().x/2, window.getSize().y/2));
            }
        }
        window.draw(s);
        if(resized) window.draw(l);
        window.display();
    }
    return 0;
}
A quick rundown of what the code is doing, to my understanding:
- application starts, displays sprite 's' as intended: centered in the screen perfectly.
- on window resize, the sprite 'l' is assigned the same texture as sprite 's', with half the scale.
- l's position *should* be set to the same as s's: centered on the screen perfectly.
What is actually happening:
- everything goes as planned until the application is resized. When resized, l's position is offset by some value (I'm not entirely sure what this value is, but it is directly correlated to the amount of resizing done to the window)
- if window has been downsized diagonally, l seems to be positioned too far to the left and too high. if window has been upsized diagonally, l seems to be positioned too far to the right and low. (pattern seems to follow as horizontal expansion/contraction -> l moves right/left respectively. vertical expansion/contraction -> l moves down/up respectively)

I've also included s being drawn to the screen after this occurs to show that s is unaffected by this resizing, which is strange. To be completely honest, I'm at a loss. I've been fiddling with this for a few hours now and I can't quite determine why this is happening. I tried looking on the forums to see if anyone else had this issue, but not much came up. I assume my code may be faulty somehow if nobody else is having this issue, or it could be my sfml version. I'm using SFML version 2.6.1, on MacOS, with a 2020 MacBook Air that has an M1 chip.

If it's an issue with my code, I am more than happy to take criticism. This has been bugging me for hours

« Last Edit: May 22, 2024, 11:00:19 pm by CardsChris »

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
The view controls how the scene is mapped onto the window. But when a window resizes, the view isn't modified. So you'll need to generate a new view. For example:
                                if (event.type == sf::Event::Resized)
                                {
                                        sf::Vector2u size = g_window.getSize();
                                        g_window.setView(sf::View(sf::Vector2f(size.x / 2.0f, size.y / 2.0f), sf::Vector2f(size.x, size.y)));
                                }
 

CardsChris

  • Newbie
  • *
  • Posts: 2
    • View Profile
After a bit of experimenting, that solution partially worked. I figured it out so I'm going to mark the thread as solved, but for anyone who runs into this issue:

Resetting the window view is NOT enough to solve this on its own. The flow of code should be something like this:
if (event.type == sf::Event::Resized) {
        window.setView(sf::View(sf::Vector2f(window.getSize().x/2.f,window.getSize().y/2.f), sf::Vector2f(window.getSize().x, window.getSize().y)));
        for (auto& i : sprites) {
            i.setPosition(/*new position */);
        }
       
    }
You must adjust every drawn object/sprite's position after you change the sf::View, otherwise each drawn object is stuck with an arbitrary sf::View based on the time it was drawn before/after the resizing of the window.