-
Hi all,
here's my problem: I want to push some objects, that have textures and sprites into a vector from STL. I met some issues and I found on this forum that I have to override draw method. The problem is I just want to keep rest of my code untouched as long as it's possible, the best thing for me is to write same or similar code to original draw method.
Here is what I have:
*.h file:
class Wyswietlacz : public Drawable, public Transformable
{
public:
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
*.cpp file:
void Wyswietlacz::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
//here is what I need you to help me with
}
some example classes to show you how I want to use it:
class example1 : public Wyswietlacz
{
private:
Texture texture1;
Sprite sprite1;
// other stuff
};
class example2 : public Wyswietlacz
{
private:
Texture texture2;
Sprite sprite2;
// other stuff
};
int main()
{
vector<example1> EX1;
vector<example2> EX2;
// creating and pushing some objects into vectors
// setting Sprites in right places and all other things needed
// creating window
window.draw(EX1[0].sprite1);
window.draw(EX2[3].sprite2);
window.draw(EX1[7].sprite1);
window.draw(EX2[2].sprite2);
window.draw(EX2[7].sprite2);
return 0;
}
So I need help in what exactly should I write in those method's definition. I want it to work as originally. And, if it is possible, I'd love to see original draw definition (NOT declaration).
Sorry for my english and maybe stupid question :)
-
The documentation (http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1Drawable.php#details) is pretty verbose on that topic.
Let us know if you have trouble understanding it. :)
-
Thank you for fast reply.
Well, yes, I have troubles. I was trying to make something using those documentation, I also googled my answer for 3 days all my free time, so I read many ideas and so. The problem is I tried some of them and no one worked.
And the example you've linked. It looks for me as it is a class like my 'example1' and 'example2' classes, because that class from documentation has it's own Sprite to display. I want it to display Sprites from classes that inherit it.
Again, I'm sorry for my english.
-
You shouldn't inherit from a sprite, but your code isn't doing that anyways.
Since you put the sprite into the derived class, you need to override the draw function in the derived class.
Personally I'd suggest to add the sprite to the base class and implement the drawing there.
It's a bad idea to make the Entity hold the texture and the sprite, because whenever the entity is moved in memory the texture would need to be reset for the sprite, plus copying a texture costs quite a bit.
Additionally it's advised to stick to English names, that way you learn a bit more English and other people can easily read your code.
So here's an example that will
#include <SFML/Graphics.hpp>
#include <vector>
class Entity : public sf::Drawable, public sf::Transformable
{
public:
Entity(sf::Texture& tex);
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
private:
sf::Sprite m_sprite;
};
Entity::Entity(sf::Texture& tex)
: m_sprite(tex)
{
}
void Entity::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
target.draw(sprite, states);
}
class example1 : public Base
{
public:
example1(sf::Texture& tex)
: Base(tex)
{
}
};
class example2 : public Base
{
public:
example2(sf::Texture& tex)
: Base(tex)
{
}
};
int main()
{
std::vector<example1> EX1;
std::vector<example2> EX2;
sf::Texture tex;
// creating and pushing some objects into vectors
// pass the texture at object creation
// setting Sprites in right places and all other things needed
// creating window
window.draw(EX1[0]);
window.draw(EX2[3]);
window.draw(EX1[7]);
window.draw(EX2[2]);
window.draw(EX2[7]);
}
-
Oh, now that's clear to me :) Thank you!
EDIT:
You shouldn't inherit from a sprite, but your code isn't doing that anyways. (...)
I mean inherit from class Wyswietlacz, not from Sprite. Sorry for missleading sentence.
(...) Additionally it's advised to stick to English names, that way you learn a bit more English and other people can easily read your code. (...)
I'm writing it with people who don't know english so it's the only right way working on that project. I usualy don't use english names anyway.
-
Well, I had much to do so I didn't check your code earlier and I'm doing it now. I have this:
//Base.h:
class Base
{
public:
Texture texture;
Sprite sprite;
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
//Base.cpp:
void Base::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform(); // As in your code
target.draw(sprite, states);
}
//Example1:
class Example1 : public Base // Basicly I get texture and sprite from 'Base' class, so I can manipulate them
{
texture.loadFromFile(//file directory);
sprite.setTexture(texture);
}
//main:
int main()
{
vector<Example1> EX1;
Example1 exapmle = new Example;
EX1.push_back(example);
window.draw(EX1[0].sprite); //worked when I stored my classes in table doesn't, when changed to
//vector
window.draw(EX1[0]); //doesn't work either
return 0;
}
All I see is white shape of what that picture was. Maybe the problem is that the file is *.jpg?
-
Your vector of Example1 should be a vector of (unique) pointers to example one. Your vector stores copies but you are trying to push_back a pointer. NEVER use naked new unless you are experienced and you know what you are doing and you clean it up. From your code it looks like you dont know what you are doing with it AND you never clean it up so enjoy memory leaks.
-
class Example1 doesn't seem to have any public members or methods nor constructor. It doesn't look like a class at all really; it looks more like a function.
-
Your vector of Example1 should be a vector of (unique) pointers to example one. Your vector stores copies but you are trying to push_back a pointer. NEVER use naked new unless you are experienced and you know what you are doing and you clean it up. From your code it looks like you dont know what you are doing with it AND you never clean it up so enjoy memory leaks.
Well, I'm sorry, I simplified my code in last post, so it had not so much to do with the original one. I also used 'new' while in my code I create whole objects, not only pointers. The 'main' function looks in fact more like this:
class My_Class
{
private:
vector<Example1> EX1;
public:
void my_fun1()
{
for(int i=0; i<10; i++)
{
Example1 example;
example.do_things(); // method that
EX1.push_back(example);
}
}
void my_fun2()
{
my_fun1();
//much stuff
window.draw(EX1[0].sprite); // <- this worked when I stored my classes in table stopped, when
// changed to vector
window.draw(EX1[0]); // <-this doesn't work either
}
};
Whole code: //Base.h:
class Base
{
public:
Texture texture;
Sprite sprite;
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
//Base.cpp:
void Base::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform(); // As in your code
target.draw(sprite, states);
}
//Example1:
class Example1 : public Base // Basicly I get texture and sprite from 'Base' class, so I can manipulate them
{
texture.loadFromFile(/*file directory*/);
sprite.setTexture(texture);
}
//Another file:
class My_Class
{
private:
vector<Example1> EX1;
public:
void my_fun1()
{
for(int i=0; i<10; i++)
{
Example1 example;
example.do_things(); // Basicly a method that loads an image to texture, sets sprite and more
EX1.push_back(example);
}
}
int my_fun2()
{
my_fun1();
//much stuff
window.draw(EX1[0].sprite); // <- this worked when I stored my classes in table stopped, when
// changed to vector
window.draw(EX1[0]); // <-this doesn't work either
}
/* And preventing questions and pointing me mistakes; here are also:
- Constructor
- Destructor
- other methods (public, protected and private)
- other variables (in my language variables are only in non object c++, in object they are called another
name but I don't know how is it in english)
*/
};
class Example1 doesn't seem to have any public members or methods nor constructor. It doesn't look like a class at all really; it looks more like a function.
Are you really intrested in class members that are not involved in this case? All my algorithms of moving things on the screen, getting events etc.? It's about 300 lines of code, when you can see those few that are manipulating on sprites up here and in my previous post.
Sorry for my english, I hope it's not so incomprehensible :)
-
class Example1 doesn't seem to have any public members or methods nor constructor. It doesn't look like a class at all really; it looks more like a function.
Are you really intrested in class members that are not involved in this case? All my algorithms of moving things on the screen, getting events etc.?
No, but I am interested in how the Example1 class in constructed and how its copy constructor is implemented.
I'm not sure why you included code in that class that is not within a method of any sort.
This is a classic example of why a minimal and complete example (http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368) is suggested. It often ends with requiring one in the end anyway,
-
I think I don't understand you a bit. Sorry, I'm not so good in english. But I think I understand that you want to see the whole code, don't you? The other thing is, you suggest that I must have an initial list and an constructor that pushes the texture it gets into the texture the class own. Is it really needed? I do it like this:
class Base : public Drawable, public Transformable
{
public:
Texture texture;
Sprite sprite;
void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
class Example1 : public Base // Basicly I get texture and sprite from 'Base' class, so I can manipulate them
{
texture.loadFromFile(//file directory);
sprite.setTexture(texture);
}
This is exactly how I load and texture and connect it to sprite. Is THIS the problem I have? If I changed it, would it start displaying things properly?
Sorry 4 my english
-
I think my question is, when does the following code (inside the Example1 class) get executed?
texture.loadFromFile(//file directory);
sprite.setTexture(texture);
-
Oh, now I see I made another mistake. It schould be in method 'do_things()', where those two lines and many others are executed, but only those two are related to texture and sprite. I'm really sorry, now I understand what were you talking about. But I think it doesn't change much as in my code it is in a method and still doesn't work :(
EDIT:
I was searching solution whole afternoon, I've changed something and then I found some code that wroks and, in my opinion, is completly IDENTICAL to mine (I mean to those which I wrote today) but mine still displays only white shapes of sprites. Look at this:
My code:
Base.h
class Base : public Drawable, Transformable
{
public:
void set_up();
Texture texture;
Sprite sprite;
private:
void draw(RenderTarget &target, RenderStates states) const;
};
Base.cpp
void Base::set_up()
{
texture.loadFromFile(/*file directory*/);
sprite.setTexture(texture);
}
void Base::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = NULL;
target.draw(sprite, states);
}
Example.h
class Example
{
private:
vector<Base> base_objects;
void show(RenderWindow & win);
public:
void do_things();
};
Example.cpp
void Example::do_things()
{
for (int i = 0; i < 10; i++)
{
Base m;
base_objects.push_back(m);
}
}
void Example::show(RenderWindow & win)
{
win.clear();
win.draw(base_objects[0]);
win.display();
}
Code identical to mine:
Base.h https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Bullet.h
Base.cpp https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Bullet.cpp
Example.h https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Engine.h
Example.cpp https://github.com/sheadovas/Kurs_SFML/blob/master/Lekcja%207/Engine.cpp
Can you tell me, where is the difference between those two, because I'm pretty sure I did my best to display those sprites properly. As I already said I see only white shapes of my sprites :(
Sorry for long post, much code and bad english!
-
Can you tell me, where is the difference between those two
You're copying the Base instances multiple times, but the Base class doesn't handle copy properly. The other code doesn't copy anything, as far as I can tell.
-
Can you tell me what exactly should I do (how to write it properly)? I don't understand why is my Base class not handling with all those objects created and pushed into vector correctly. I'm not very skilled programer.
EDIT:
Ok, I've studied virtual methods and found all I knew about them wasn't true so I've learned how to handle them properly, how to override them and make them doing what I want them to do, but I met another problem and maybe it is unable to do it in a way I want to do it, but if it is possible to do, please help me with following:
That's my code now:
Board.h
class Board : public Drawable, Transformable
{
public:
bool set_up(int nrOfBoard, int level); // that method sets all sprites and loads
// from files coordinates of everything
private:
Texture texture; // texture of board
Sprite background; // sprite of board
struct adds
{
Vector2f coordinates;
Sprite add;
};
struct things
{
Vector2f coordinates;
Sprite thing;
};
struct oneBoard
{
vector<adds> add_s;
vector<things> thing_s;
};
vector<oneBoard> map_of_all_boards;
virtual void draw(RenderTarget &target, RenderStates states) const;
};
Board.cpp
void Board::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = NULL;
target.draw(background);
for (int i = 0; i < map_of_all_boards[0].add_s.size(); i++)
target.draw(map_of_all_boards[0].add_s[i].add, states);
for (int i = 0; i < map_of_all_boards[0].thing_s.size(); i++)
target.draw(map_of_all_boards[0].thing_s[i].thing, states);
}
As you can see I display 'map_of_all_boards[0]', the very first thing in my vector. I would like to change it and display those one which I want by changing:
virtual void draw(RenderTarget &target, RenderStates states) const;
in something like this:
virtual void draw(RenderTarget &target, RenderStates states, int board_number) const;
but I keep getting error:
error C2664: 'void sf::RenderTarget::draw(const sf::Vertex *,unsigned int,sf::PrimitiveType,const sf::RenderStates &)' : cannot convert argument 1 from 'int' to 'const sf::Drawable &'
Reason: cannot convert from 'int' to 'const sf::Drawable'
while I try to use it as following:
window.draw(Boards, 0); // Boards is an object of class Board
I understand why I get it. I only ask you now to advise me how can I display one element of my vector, how can I pass the information of which element method should pick to my overrided draw?
Any help welcome! Please, I need it fast!
Sorry for my english!
-
You can't. The only way would be to use another function
Boards.setNextElementToDraw(0);
window.draw(Boards);
... but that's extremely ugly.
You know, you're not forced to inherit from sf::Drawable and use this draw function. You can just avoid sf::Drawable and create the draw function that suits your needs.
Boards.draw(window, 0);
-
Well, that's what I did. I mean I made a function that tells my object of class Board which element to pick. And yes, I see how ugly it is :)
The second solution you suggested seems good and profesional. Although I'm not sure if I'm able to write it, I'll try it.
Which of them is better (quicker to execute)?
Thank you for reply :)
EDIT:
I've changed my code a bit again so it handles displaying some of my sprites but there are still some that are appear as white shapes. Can I ask once again to tell me, where my mistake is? I tried everything, nothig worked :(
My code now:
Board.h
class Board : public Drawable, Transformable
{
public:
bool set_up(int nrOfBoard, int level); // that method sets all sprites and loads
// from files coordinates of everything
int what_board;
private:
Texture texture; // texture of board
Sprite background; // sprite of board
struct oneBoard : public Drawable, public Transformable
{
vector<Sprite> adds;
vector<Sprite> things;
virtual void draw(RenderTarget &target, RenderStates states) const
{
for (int i = 0; i < adds.size(); i++)
target.draw(adds[i], states);
for (int i = 0; i < things.size(); i++)
target.draw(things[i], states);
}
};
vector<oneBoard> map_of_all_boards;
virtual void draw(RenderTarget &target, RenderStates states) const;
};
Board.cpp
bool Board::set_up(int nrOfBoard, int level)
{
// some stuff, also determining the number_of_boards
for (int i = 0; i < number_of_boards; i++)
{
Board board;
oneBoard one;
//again some stuff, determining amount_of_adds
for (int i = 0; i < amount_of_adds; i++)
{
Texture tex;
Sprite spr;
string directory;
Vector2f vec;
plik >> directory;
plik >> vec.x;
plik >> vec.y;
tex.loadFromFile(directory);
spr.setTexture(tex);
spr.setPosition(vec);
one.adds.push_back(spr);
}
// and again stuff, detrmining amount_of_things
for (int i = 0; i < amount_of_things; i++)
{
Texture tex;
Sprite spr;
string directory;
Vector2f vec;
plik >> directory;
plik >> vec.x;
plik >> vec.y;
tex.loadFromFile(directory);
spr.setTexture(tex);
spr.setPosition(vec);
one.things.push_back(spr);
}
// WEPCHNIECIE CALEGO POKOJU DO WEKTORA POKOI
map_of_all_boards.push_back(one);
plik.close();
}
}
void Board::which_board(int brd)
{
what_board = brd;
}
void Board::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
states.texture = NULL;
target.draw(background);
target.draw(map_of_all_boards[what_board]);
}
I tought that the way I load all that sprites can have an impact on my problem, so I decided to show you more code this time.
So my problem is: my code loads and displays proprely backgroung and loads properly sprites into adds and things. No doubt it does. But on the screen I see my background and white shapes of sprites from vectors adds and things. Any solution? Can you tell me, if part of my code is incorrect, how to fix it?
Sorry for my english :)
-
for (int i = 0; i < amount_of_things; i++)
{
Texture tex;
Sprite spr;
string directory;
Vector2f vec;
plik >> directory;
plik >> vec.x;
plik >> vec.y;
tex.loadFromFile(directory);
spr.setTexture(tex);
spr.setPosition(vec);
one.things.push_back(spr);
}
The texture is a local variable. You should really have a deeper look at C++, it's crucial to understand scopes, copy semantics and object ownership.
Furthermore, please avoid using namespace, it's a terrible habit that will lead to problems sooner or later.
-
(...) The texture is a local variable.(...)
I didn't know that it is needed. I tought that when I once push a texture to sprite using:
Texture tex;
Sprite spr;
spr.setTexture(tex);
the texture becomes a part of sprite and that sprite is a thing that is ready to be moved and displayed.
So if I make a structure of a texture and a sprite and then make a vector that structure's type my graphic should be displayed properly?
EDIT:
I tried it like I said. It didn't work.
Do you know what the problem is? I don't know how to do something, I ask you, but you don't give me precision answer. You keep telling me, that something is fundamental, something I should know etc. but I don't know it. If I knew I would do it properly. I don't know and that's why I ask you for help. Could anyone just write how can I make that textures visible for my sprites? I really need your help, when you write a code and comment it I could probably learn something but by keep telling me that I should know something, I search for it again and again and I can't find any answer to my questions. Is here anyone, who could help me, write that code and explain why did it in another way that I did?
Special "thank you in advance" to the person who will.
Sorry for my english.
-
I tought that when I once push a texture to sprite using:
Texture tex;
Sprite spr;
spr.setTexture(tex);
the texture becomes a part of sprite and that sprite is a thing that is ready to be moved and displayed.
Why do you assume that? This behavior is nowhere documented and very uncommon in C++. Even the opposite is documented, namely that the texture object must live as long as it's used.
So if I make a structure of a texture and a sprite
Don't do that. The whole reason why sf::Texture and sf::Sprite are two separate classes is to allow you to store them separately, and have multiple sprites that reference the same texture. This is precisely outlined in the tutorial, please read it carefully.
You should store textures in their own container (preferably not std::vector, because it invalidates pointers). There are also ready-to-use solutions like thor::ResourceHolder (http://www.bromeon.ch/libraries/thor/v2.0/tutorial-resources.html).
-
Why do you assume that?
Seemed logical to me. It's easier to move or change one object than many. If it doesn't work like that thank you for informating me. Now I know, now I know how to handle such situations in the future.
So if I make a structure of a texture and a sprite
Don't do that. The whole reason why sf::Texture and sf::Sprite are two separate classes is to allow you to store them separately, and have multiple sprites that reference the same texture. This is precisely outlined in the tutorial, please read it carefully.
Well, yes, that's something I didn't think about. That's good point of viev when you use one big texture, like a big tileset and you make multiple sprites from that. But my situation is one texture -> one sprite. This is why I want to store them together. Then I'll have the situation when pairs are in one place.
You should store textures in their own container (preferably not std::vector, because it invalidates pointers). There are also ready-to-use solutions like thor::ResourceHolder (http://www.bromeon.ch/libraries/thor/v2.0/tutorial-resources.html).
Should I use tables? I don't have time to learn a new library. I also tought about std::map. Would it work? Is it I definitly can't store those textures and sprites just like I want to or it is only the most painful way?
Thank you for fast replay and sorry for my english.
-
I tought that when I once push a texture to sprite[...]the texture becomes a part of sprite and that sprite is a thing that is ready to be moved and displayed.
Why do you assume that?
Seemed logical to me.
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).
It's easier to move or change one object than many.
This isn't true. Sprites are lightweight and can be copied, created and destroyed in real-time whereas textures are heavyweight and slow to copy, move, create or destroy.
Decoupling them gives a number of advantages. One simple advantage is the ability to use the same texture for multiple sprites.
-
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).
I red it 'till the end of "Ok, can I have my Sprite now" and gave up as I didn't found what I was looking for :/ That changes a lot. But now I (unexpectedly) changed my code once again. And now it loads textures directly to the structures. Then, when texture is in the right place and won't be moved from there I set textures to sprites. So I set textures that are in structure in vector in vector to the sprites that are in structure in vector in vector. And still dosen't work :(
-
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).
I red it 'till the end of "Ok, can I have my Sprite now" and gave up as I didn't found what I was looking for
You gave up when you got to "The White Square Problem" when because you didn't find the information on the problem that you are having with a white square?
But now I (unexpectedly) changed my code once again. And now it loads textures directly to the structures. Then, when texture is in the right place and won't be moved from there I set textures to sprites. So I set textures that are in structure in vector in vector to the sprites that are in structure in vector in vector. And still dosen't work :(
I don't understand what your code does from this description and what the result of it is.
Try storing your textures globally (not global scope but rather last the lifetime of the application) and pass reference/pointer to them to each class, function, method that uses them.
A simple local-sprite-using-long-term-texture could look something like this:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window; // set up window how you need it
sf::Texture texture;
// load and set up texture here
while (window.isOpen())
{
// event loop here
sf::Sprite localTempSprite;
localTempSprite.setTexture(texture);
window.clear();
window.draw(localTempSprite);
window.display();
}
return EXIT_SUCCESS;
}
-
This is explain in the initial tutorials (http://www.sfml-dev.org/tutorials/2.3/graphics-sprite.php#the-white-square-problem).
I read it 'till the end of "Ok, can I have my Sprite now" and gave up as I didn't found what I was looking for
You gave up when you got to "The White Square Problem" when because you didn't find the information on the problem that you are having with a white square?
I read the "Ok, can I have my sprite now?"and then gave up, the "The White Square Problem" is under it and I didn't saw it. Other words I read everything 'till end of "Ok, can I have my sprite now?" and closed the tab.
I don't understand how exactly the sprites work. As these objects have a pointer to the texture then why when I store my textures in std::vector, then call sprite.setTexture(textures_in_vector[4]); it doesn't work properly? Is it I can't have a pointer to something that is stored in a vector and the class Sprite has a pointer so the value the pointer is indicating to is unreachable?
Sorry for my english.
-
When you call sprite.setTexture, the sprite stores the address of (pointer to) the texture object. So if you copy or move the texture around, the address stored in the sprite becomes invalid and all you get is a white square instead of the texture data.
The problem is that objects can easily be copied/moved in C++, even if you don't want them to. When you use a vector, for example, you insert copies into it, not original objects. And when the vector needs to grow, it goes elsewhere in memory and moves all its elements. All these operations invalidate the sprite's textures that were already stored.
So there are usually three solutions to this problem:
1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.
2. If you don't need to share textures (ie. one texture, one sprite) then the class that encapsulates them needs to handle copy/move operations properly. When you copy an instance of a class that holds a sprite and its texture, both are copied, and the sprite copy needs to use the texture copy, not the original texture (as its the case by default). So you need to write the code that does it, in the copy/move constructor and copy/move assignment operators. If you let the compiler generate the copy/move code for you, it will be wrong, the sprites will end up pointing to texture objects that don't exist anymore.
3. Make sure that no copy or move ever happens, by reserving space in your vector or using containers that don't invalidate their elements (std::list). I don't like this approach, I don't consider it a clean solution (or a solution at all) to this design problem.
-
Basically, textures need lifetimes that are longer than the sprites that use them.
You need to know what operations on containers (etc) invalidates pointers, references and iterators pointing to textures.
This is essential C++ stuff you need to know for any object, not just textures.
-
When you call sprite.setTexture, the sprite stores the address of (pointer to) the texture object. So if you copy or move the texture around, the address stored in the sprite becomes invalid and all you get is a white square instead of the texture data.
At fitst I would like to thank you for briliant post with many useful informations for me. Now I see how much do I have to learn still to use C++ fluenltly. Thank you again. Still, as I'm qiuet noob in programing I have a few questions to you but I feel I'm beginning to understand what happens when my code is executed. That seems and for sure is really important.
(...)
So there are usually three solutions to this problem:
1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.
Is that something that is built-in in SFML or should it be a class wrote by myself? If it relays on me are there some other ways better than std::vector, std::list (which you metnioned in point 3 as not the best idea) and reallocing tables?
2. If you don't need to share textures (ie. one texture, one sprite) then the class that encapsulates them needs to handle copy/move operations properly. When you copy an instance of a class that holds a sprite and its texture, both are copied, and the sprite copy needs to use the texture copy, not the original texture (as its the case by default). So you need to write the code that does it, in the copy/move constructor and copy/move assignment operators. If you let the compiler generate the copy/move code for you, it will be wrong, the sprites will end up pointing to texture objects that don't exist anymore.
As my code looks now like this:
class CLASS
{
struct 1
{
Sprite spr;
Texture tex;
}
struct 2
{
Sprite spr;
Texture tex;
}
struct 3
{
vector<1> one;
vector<2> two;
}
vector<3> map;
}
Would it work, when I'm never touching those vectors after reading textures from file, if I matched sprites to the textures after reading last one thing at all into vector? I mean at first I read textures, other stuff, create some other variables and push everything to the vectors. The vectors are moved in memory a few times during that reading and creating variables. But then, do they finaly stand still at one place, that I could call spr.setTexture(tex); when nothing else would be pushed to the vectors or is it still possible, that dusring executing my programm vector would be moved (not intentionaly by me)?
3. Make sure that no copy or move ever happens, by reserving space in your vector or using containers that don't invalidate their elements (std::list). I don't like this approach, I don't consider it a clean solution (or a solution at all) to this design problem.
Well, that was what I liked most when I read all 3 your propositions :( But if you say it is bad...
Thank you for fast replay and I'm sorry for my english.
-
1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.
Is that something that is built-in in SFML or should it be a class wrote by myself?
SFML doesn't have it, but Thor does, as I mentioned earlier. You said you wouldn't want to use another library, but when you're considering yourself a beginner in these things, it may not be the best idea to write such a class from scratch ;)
If it relays on me are there some other ways better than std::vector, std::list (which you metnioned in point 3 as not the best idea) and reallocing tables?
You could use an associative container like std::map, and refer to the texture using some identifier (the key in the map). That's also a part of what thor::ResourceHolder does, it just simplifies many things on top of that.
But then, do they finaly stand still at one place, that I could call spr.setTexture(tex); when nothing else would be pushed to the vectors or is it still possible, that dusring executing my programm vector would be moved moved (not intentionaly by me)?
If you don't touch the vectors themselves, it's only possible if the object of the surrounding class (which contains the vector) is moved/copied.
And don't apologize for your English in every post, it's not that bad 8)
-
1. Use a texture manager, so that texture are managed and stored elsewhere and remain at the same location in memory, regardless of how you use them.
Is that something that is built-in in SFML or should it be a class wrote by myself?
SFML doesn't have it, but Thor does, as I mentioned earlier. You said you wouldn't want to use another library, but when you're considering yourself a beginner in these things, it may not be the best idea to write such a class from scratch ;)
If it relays on me are there some other ways better than std::vector, std::list (which you metnioned in point 3 as not the best idea) and reallocing tables?
You could use an associative container like std::map, and refer to the texture using some identifier (the key in the map). That's also a part of what thor::ResourceHolder does, it just simplifies many things on top of that.
The problem is more complex, I don't write it alone ;) But I'll try to convince our engraver to make one tileset for level, that would be more efective and simplify many things :) (Now I'm so smart, when you told me all that things :) )
But then, do they finaly stand still at one place, that I could call spr.setTexture(tex); when nothing else would be pushed to the vectors or is it still possible, that dusring executing my programm vector would be moved moved (not intentionaly by me)?
If you don't touch the vectors themselves, it's only possible if the object of the surrounding class (which contains the vector) is moved/copied.
Strange. I did it like I said, first made everything up, then called spr.setTexture(); and from then on never touched any vector or whole object. Still didn't worked.
And don't apologize for your English in every post, it's not that bad 8)
"it's not that bad" = still not perfect = still ther's something to apologize for, because it makes reading harder and I'm not an easy interlocutor; I write long posts and ask stupid questions ;)
-
Strange. I did it like I said, first made everything up, then called spr.setTexture(); and from then on never touched any vector or whole object. Still didn't worked.
You could use a debugger to check whether the addresses of the sf::Texture objects change, and if they do, where this happens.
You could also declare a vector of non-copyable but movable objects (e.g. std::vector<std::unique_ptr<int>>) in the same place, and see whether a compiler error resulting from a copy attempt occurs.
-
Now I'm like John Snow; I know nothing.
I was tired of keeping trying to make that code work. As I wrote yesterday, I've made some changes and compiled the project. Once again I saw white squares and as I had a hard day I haven't time to write code. Today I entered the forum, saw your post and tought "Great idea, let's see how it works!". So I, making no changes from yesterday, debugged code and started a "new game". Everything was set up in it's place, displayed fullly properly. I have no idea why it didn't worked yesterday :o
All in all thank you all for your time you spended here reading my sh*tty code and trying to help me. Now I know more about SFML and object oriented programing in C++. Thakns to you I started reading some more materials about both and I find it really helpful so far.
The solution to the problem for all that could look for this in the future:
1. Ensure that you don't move your Texture objects in memory after calling sprite.setTexture(texture);.
2. If you do you can do two things:
a) change the code to don't move the Texture
b) change the code to call sprite.setTexture(texture); always right after moving the Texture
In my opinion the case is closed, if I had some problems with it in the future I'll probably be able to handle with it on my own (thanks to you ofc ;)).
You guys are awesome! Thank you once again for what you did for me, for your patience and nerves :)
Best regards,
Skorpion