2
votes

sfml sprite class .setTexure() method doesnt work inside of constructor for iterator, but does work when iterator is already made

We're trying to construct structure for frames that are being drawn onto the window. We're using sfml library, with their sprite and texture classes. In the constructor for the frameData structure we load a texture from file then apply it to the sprite using the .setTexture() method. We either get white block or a program crash depending on the machine when we compile and run our program.

If we create do a pointer reference to texture with .setTexture() outside the constructor for frameData, it works!

All if this is with an iterator structure that iterates through the different frames. Here is the relevant code, First this is in the header for the FrameData struct:

private:
    struct FrameData
    {
        FrameData(const std::string& fileName, int frameDelay);

        sf::Texture texture;
        sf::Sprite sprite;
        unsigned int frameDelay;
    };

Second, here are the actual constructors, not working:

const sf::Sprite& SpriteAnimator::currentFrame() const
{
    return currentFrame_->sprite;
}

SpriteAnimator::FrameData::FrameData(const std::string& fileName, int frameDelay)
: frameDelay(frameDelay)
{
    texture.loadFromFile(fileName);
    sprite.setTexture(texture);
}

And thirdly, here is what does work:

const sf::Sprite& SpriteAnimator::currentFrame() const
{
    currentFrame_->sprite.setTexture(currentFrame_->texture);
    return currentFrame_->sprite;
}

SpriteAnimator::FrameData::FrameData(const std::string& fileName, int frameDelay)
: frameDelay(frameDelay)
{
    texture.loadFromFile(fileName);
    sprite.setTexture(texture);
}

Any ideas about why this happens, are we missing something? We want to have the constructor work properly, the current frame is returned a lot more frequently than the texture changing, so we don't need to update the texture every time the current frame is returned.

Thank you!

2
I had a similar problem with this. My solution was to store all of my textures in a container outside of the class and use a pointer to the texture instead of the texture itself. This kills 2 birds with one stone because you don't have to store more than 1 of the same texture if you are going to create another object from the class. - elimirks
So do you think the problem comes from using the textures themselves rather than pointers? I wonder if that is documented. Thank you! - s3binator
Since you solved your question, can you post the solution as an answer? That way it doesn't look like an open question to all the other SO users. Thanks! - Tim

2 Answers

1
votes

SOLVED! Read last paragraph of the class documentation for sf::sprite:

It is important to note that the sf::Sprite instance doesn't copy the texture that it uses, it only keeps a reference to it. Thus, a sf::Texture must not be destroyed while it is used by a sf::Sprite (i.e. never write a function that uses a local sf::Texture instance for creating a sprite).

So creating a repository for textures outside of the scope of this class, then passing references works, like strongdrink recommended!

1
votes

I had a similar problem with this. My solution was to store all of my textures in a container outside of the class and use a pointer to the texture instead of the texture itself. This kills 2 birds with one stone because you don't have to store more than 1 of the same texture if you are going to create another object from the class.