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

Author Topic: Sprite being drawn as a white square even though sprite points to texture  (Read 1081 times)

0 Members and 1 Guest are viewing this topic.

aSpookyMan

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
I have this struct containing a sprite and a texture:
struct Layer
{
        Layer(const char* _path, sf::View& view) : deviation{ 0.0f }, mod{ 1 } {
                txtr.loadFromFile(_path);
                spr.setTexture(txtr);
                txtr.setRepeated(true);

                scale = { view.getSize().y / txtr.getSize().y ,
                                  view.getSize().y / txtr.getSize().y };

                sf::Vector2f pos(view.getCenter().x - view.getSize().x, view.getCenter().y + view.getSize().y / 2);
                sf::Vector2f sprdim(txtr.getSize().x* scale.x, txtr.getSize().y* scale.y);

                spr.setOrigin({0.0f, sprdim.y});
                spr.setPosition(pos);
                spr.setTextureRect({ 0, 0, static_cast<int>(txtr.getSize().x),
                                                               static_cast<int>(txtr.getSize().y) });
                spr.setScale(scale);
        }

        sf::Vector2f scale;

        sf::Sprite spr;
        sf::Texture txtr;

        float deviation;

        unsigned mod;
};
 
Then I made a vector of 'Layer' in the following class:
class Parallax {
public:

        std::vector<Layer> layers;

        sf::Sprite sprite;//test
        sf::Texture t;
       
        Player player;

        float deviation = 0.0f;
        float speed = 0.5f;
        unsigned mod = 1;

        bool canMove;

        void Init(Player& player, sf::View& view);
        void Update(const float& dt, sf::View& view);
        void Draw(sf::RenderTarget& target);
};
 
And lastly, the definition:
#include "Parallax.h"

void Parallax::Init(Player& player, sf::View& view) {
       
        this->player = player;

        //Further-most layers added first
        layers.push_back(Layer("Res/Textures/Parallax/glacial_mountains.png", view));

}
void Parallax::Update(const float& dt, sf::View& view) {
        for (size_t i = 0; i < layers.size(); i++) {
                if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) && player.canMoveLeft) {
                        layers.at(i).deviation += this->speed * i * dt;
                        this->canMove = true;
                }
                else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) && player.canMoveRight) {
                        layers.at(i).deviation -= this->speed * i * dt;
                        this->canMove = true;
                }
                else this->canMove = false;

                if (canMove) layers.at(i).spr.move(deviation * dt, 0.0f);
               
                sf::Vector2f sprpos(layers.at(i).spr.getPosition());
                sf::Vector2f sprdim(layers.at(i).txtr.getSize().x * layers.at(i).spr.getScale().x,
                        layers.at(i).txtr.getSize().y * layers.at(i).spr.getScale().y);

                if (sprpos.x + sprdim.x < view.getCenter().x + view.getSize().x / 2) {
                        layers.at(i).mod++;
                        layers.at(i).spr.setTextureRect({ 0, 0, static_cast<int>(layers.at(i).txtr.getSize().x * layers.at(i).mod),
                                                                                                        static_cast<int>(layers.at(i).txtr.getSize().y) });
                }
        }
}
void Parallax::Draw(sf::RenderTarget& target) {
        for (auto& i : this->layers) target.draw(i.spr);
}
 
I don't understand how that could possibly lose the pointer to its texture, since the texture itself is not a temporary variable. Maybe it's some dumb mistake that I'm making, but I can't really see it.
I tried pinting
std::cout << sprite.getTexture() << "\n";
and the texture's memory address was outputted just fine. Any ideas to what might be causing this?

« Last Edit: July 27, 2020, 02:07:25 am by aSpookyMan »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
It's because std::vector<Layer> will move it's elements when it needs more contiguous space in memory. You should handle copy or move construction for your Layer class, or better, store textures outside them (especially if they share the same ones).

The address returned by Sprite::getTexture() never magically goes back to null of course, the problem is that there's no more valid texture at that address, because it moved somewhere else. Your sprite thinks it points to a valid texture, but it's just garbage, and therefore it needs to be updated (which never happens in your code).
Laurent Gomila - SFML developer

aSpookyMan

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Yeah that makes sense, thank you!