Hello,
I’ve been trying to create resource (sprites) manager, but ended up having problem. Idea was like this: image and texture are being loaded into memory only once (those files might be big), Sprites that are being created should point to those resources instead.
That’s for the vision, below something I’ve got so far:
Hpp class file
#ifndef OBJECTS_H
#define OBJECTS_H
#include <SFML/Graphics.hpp>
#include <memory>
class Objects {
public:
Objects();
virtual ~Objects();
void draw ( sf::RenderWindow *window );
protected:
void create ( void );
sf::Sprite foo ( void );
private:
sf::Image image;
sf::Texture texture;
//std::vector < sf::Sprite > sprites; // First approach -> Without pointers, it's working
std::vector < sf::Sprite* > sprites;
//std::vector < std::unique_ptr < sf::Sprite > > sprites; // Third approach - smart ptr's
};
#endif // OBJECTS_H
Cpp Class file:
#include "Objects.hpp"
Objects::Objects() {
image.loadFromFile ( "image.png" ); // just some red 20x20 px square
texture.loadFromImage( image );
create();
}
Objects::~Objects() {
//dtor
}
// Objects::create
void Objects::create ( void ) {
sf::Sprite sprite;
sprite.setTexture( texture );
// sprites.push_back ( sprite ); // First approach - works, but we have unnecesary textures per sprite resisting in memory?
sprites.push_back( &sprite ); // Second approach - not working
// sprites.push_back( std::unique_ptr < sf::Sprite > ( &sprite ) ); // Third approach, not working as well
}// Objects::create
// Objects::draw
void Objects::draw ( sf::RenderWindow *window ) {
//window->draw ( ( sprites[0] ) ); // First working approach
window->draw ( ( *sprites[0] ) ); // Second and Third approach - not working
}// Objects::draw
In main.cpp, I’m, just creating class object and invoking draw function:
#include <SFML/Graphics.hpp>
#include "Objects.hpp"
int main() {
Objects o;
sf::RenderWindow window(sf::VideoMode( 800, 600 ), "Texture Loading Test!" );
while ( window.isOpen() ) {
sf::Event event;
while ( window.pollEvent( event ) ) {
if ( event.type == sf::Event::Closed ) {
window.close();
}
}// while
window.clear();
o.draw( &window );
window.display();
}// while
return 0;
}
As for Me... it should work :), but (surprise)… it’s not. I believe we have some kind of memory leek here. I assume, the problem lies here (passing reference to object, pointing to null texture):
void Objects::create ( void ) {
sf::Sprite sprite;
sprite.setTexture( texture );
sprites.push_back( &sprite );
I know I can ignore the pointers approach, and just stick to “first approach” mentioned above, but to my knowledge it will create unnecessary textures, resisting in memory (for example, creating 100 of sprites will create 100 of additional textures) – is my reasoning correct?
I must say, I’ve got no clue how to fix this... :( Any suggestions/hints/leads are most welcomed.
Thank You for help in advance.
void Objects::create ( void ) {
sf::Sprite sprite;
sprite.setTexture( texture );
sprites.push_back( &sprite );
}
You may need to brush up on how scope works in C++. Your sprite variable is a local variable to the Objects::create() function. That means when the create function is finished, sprite will be destroyed. With that in mind, you can see how the above code is problematic. First the sprite variable is created and a texture is assigned to it, then the address of that variable is pushed onto a vector, and finally the sprite variable is destroyed. That means the address saved in the vector is now pointing to invalid memory. The sprite it used to point to no longer exists. (I didn't look through all of your code, so you may have other issues as well. This is just one I happened to notice when quickly glancing at it.)
As for your question on sprites and textures, the SFML tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php) do a good job of explaining them. In short, textures are big objects that contain your image data. Sprites are small objects that act as a "view" into the texture. Internally the sprite doesn't copy the texture, but instead is just holding a pointer to it. Creating a bunch of sprites won't create a bunch of unnecessary textures. In this case they will all just make use of the same texture.