SFML community forums

Help => General => Topic started by: congwei on November 25, 2023, 05:59:42 pm

Title: image cannot display
Post by: congwei on November 25, 2023, 05:59:42 pm
I create a sfml project with cmake on windows, but image cannot display

bye the way, I am a beginner of c++ and sfml, so ignore the style of code, I just want it work.

src/main.cpp
#include "game.hpp"
#include <SFML/Graphics.hpp>

int main() {

    Game game;

    sf::Clock clock;
    sf::Time elapsed;

    float frametime = 1.0f / 60.0f;

    while (game.window.isOpen()) {
        sf::Event event;
        while (game.window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                game.window.close();
            }
        }

        // 1. 事件处理
        game.handleInput();

        // 2. 更新物理逻辑
        if (elapsed.asSeconds() >= frametime) {
            elapsed -= sf::seconds(frametime);
            game.update(); // 60次/秒
        }
        elapsed += clock.restart();

        // 3. 渲染
        game.window.clear();
        game.render();
        game.window.display();
    }

    return 0;
}
 

src/game.hpp
class Game {
  public:
    sf::RenderWindow window;

    sf::Sprite s;

    Game() {
        window.create({320, 480}, "hello");

        sf::Texture t;
        t.loadFromFile("images/tiles.png");

        s.setTexture(t);
    }

    void handleInput() {}

    void update() {}

    void render() { window.draw(s); }
};
 

but if I put draw code into main.cpp, it's work, I dont know why. like this:
src/main.cpp
       ...
        // 3. 渲染
        game.window.clear();
        // game.render();
        sf::Texture t;
        t.loadFromFile("images/tiles.png");

        sf::Sprite s(t);
        game.window.draw(s);
        game.window.display();
       ...
 

Title: Re: image cannot display
Post by: congwei on November 25, 2023, 06:42:53 pm
I know the reason, if put sf::Texture t to class member, it work.
Title: Re: image cannot display
Post by: Hapax on November 25, 2023, 06:56:32 pm
Hi, welcome, and glad you got it to work! :)

The reason it works as a member of the class is that it continues to exists (as long as the class instance does).

The other two options you mentioned both create a new texture each time and are destroyed at the end of that scope (the closing brace: } )

The one in the class's constructor is destroyed almost immediately.
The one in the loop is destroyed at the end of the loop.

But, the one in the loop is loading the texture every frame and is best avoided. Resources (especially heavy ones like textures) should be loaded once and changed as little as possible.

So, the best option here is, as you've already found, is put the texture as a class member. You can still load it in the constructor but the member lasts as long as the class instance does.

e.g.
class Game {
public:
    sf::Texture t;
    Game() {
        if (!t.loadFromFile("images/tiles.png")) {
            std::cerr << "Unable to load texture!\n";
        }
    }
}

Remember to test the return value (bool) from loadFromFile (as shown in my example) as it informs you if the texture load was successful.
You could throw an exception, for example, as it's likely you wouldn't want to continue without it.