Skip to main content
added 235 characters in body
Source Link
Vaillancourt
  • 16.4k
  • 17
  • 55
  • 61

This is based on the code you supplied on your other answer. I have uploaded the relevant changes to a github repository.


This is based on the code you supplied on your other answer. I have uploaded the relevant changes to a github repository.

Source Link
Vaillancourt
  • 16.4k
  • 17
  • 55
  • 61

Why is there this issue?

The issue is here:

if (space)
{
  Bullet b1;
  b1.setPos(player.getPosition());
  b.push_back(std::make_unique<Bullet>(b1));
}

Let's look at the Bullet class (the relevant parts):

class Bullet
{
private:
  Texture t;
  Sprite bullet;
  
public:
  Bullet()
  {
    //Setting Texture
    if (!t.loadFromFile("Graphics/bullet2.png"))
    {
      std::cout << "Bullet Texture Failed to Load\n";
    }
    else
    {
      t.loadFromFile("Graphics/bullet2.png");
      bullet.setTexture(t);
    }      
  }
};

and the Sprite class (the relevant parts):

class SFML_GRAPHICS_API Sprite : public Drawable, public Transformable
{
public:
    Sprite() : 
      m_texture (NULL) {}
    void setTexture(const Texture& texture, bool resetRect = false) 
    { 
      m_texture = &texture; 
    }
    const Texture* m_texture;     ///< Texture of the sprite
};

When a Bullet instance is created, the object is created on the stack. The issue comes when you add it to the vector and then get out of the scope. It's most likely moving the objects within to a new location, moving the Sprite and the Texture. But notice that the Sprite has a reference to the texture? This texture will be deleted when we'll come out of the scope of the if (space). Even if we move everything, there is nothing to tell the Sprite that the Texture has moved.

How to solve it?

The trivial solution is to create your Bullet on the heap right away, using std::make_unique:

if (space)
{
  b.push_back(std::make_unique<Bullet>());
  b[b.size()-1]->setPos (player.getPosition());
}

This way, the references will always stay in place in memory and the image will show.

Doing this will "fix" your issue. But the next step is: you'll notice that when you spawn a Bullet, there is some slight lag.

This is most likely due to the lines:

if (!t.loadFromFile("Graphics/bullet2.png"))
{
  std::cout << "Bullet Texture Failed to Load\n";
}
else
{
  t.loadFromFile("Graphics/bullet2.png");
  bullet.setTexture(t);
}

You're reading a file twice. IO operations are the most costly operations on a system. We can fix this by loading all of our textures at startup, and then passing a reference to them to our Bullet instance.

We'll then end up with something like this in your main():

...
//Creating the Vector
std::vector<std::unique_ptr<Bullet>> b;
std::map<std::string, std::unique_ptr<Texture>> textures;

auto load_texture = [&]( std::string texture_path, std::string texture_id ) {
    
  std::unique_ptr<Texture> new_texture = std::make_unique<Texture>();

  if ( new_texture->loadFromFile( texture_path ) )
  {
    textures[texture_id] = std::move( new_texture );
  }
  else
  {
    std::cout << "Failed to load \"" << texture_id << "\" for path \"" << texture_path << "\".\n";
  }
};

load_texture( "Graphics/bullet2.png", "bullet" );

bool space = false;

...

if (space)
{
  auto texture = textures.find( "bullet" );

  b.push_back(std::make_unique<Bullet>(*texture->second));
  b[b.size()-1]->setPos (player.getPosition());
}

...

And a Bullet class like this:

class Bullet
{
private:
  Texture& t;
  Sprite bullet;
  Vector2f pos;
public:
  Bullet(Texture& texture);
  ~Bullet();
  void setPos(Vector2f pos);
  void update();
  Sprite getSprite();
  Vector2f getPos();
};

Bullet::Bullet(Texture& texture)
  : t(texture)
{
  bullet.setTexture(t);
}

The added advantage here is that you'll be using less memory (you really don't need to have the same image multiple times in memory).