I wanna try implement sprite group as in pygame. I acted according to this article (https://github.com/SFML/SFML/wiki/Tutorial%3A-Drawable-Group), but I confused. Firstly, I don't understand how to pass Drawable object to group. I typed the code as following:
struct Group : public sf::Drawable {
std::vector<std::reference_wrapper<const sf::Drawable>> sprites;
Group() : sprites{} {}
virtual ~Group() = default;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const {
for(const auto& sprite : sprites){
target.draw(sprite, states);
}
}
const sf::Drawable& operator[](std::size_t index){
return sprites[index];
}
std::size_t add(const sf::Drawable& sprite){
sprites.push_back(sprite);
return sprites.size() - 1;
}
const sf::Drawable& remove(){
const auto& sprite = sprites.back();
sprites.pop_back();
return sprite;
}
};
struct Box : public sf::Drawable, public sf::Transformable{
sf::Texture texture;
std::vector<sf::Vertex> vertices;
sf::PrimitiveType m_type;
virtual void draw(sf::RenderTarget &target, sf::RenderStates states) const{
states.transform *= getTransform();
states.texture = &texture;
target.draw(&vertices[0], vertices.size(), m_type, states);
}
Box(const std::string path, sf::PrimitiveType type, int length, float *coords){
for(int i = 0; i < length * 2; i++){
vertices.push_back(sf::Vertex(sf::Vector2f(coords[i], coords[i+1]),sf::Vector2f(coords[i], coords[i+1])));
i++;
}
if(!texture.loadFromFile(path)){
std::cerr << "Failed to loading file!" << std::endl;
}
m_type = type;
}
};
float coords[] = {
0.0f, 0.0f,
32.0f, 0.0f,
32.0f, 32.0f,
0.0f, 32.0f,
};
int main()
{
Group spriteGroup;
sf::RenderWindow window(sf::VideoMode(640, 480), "SFML works!");
std::vector<Box> boxes;
for(int i=0; i < 10; i++){
boxes.push_back(Box("../resources/box.png", sf::Quads, 4, coords));
spriteGroup.add(boxes[i]);
}
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::White);
window.draw(spriteGroup[1]);
window.display();
}
return 0;
}
In addition, I got these runtime errors:
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
well, i have almost same error as you have it, i'm using visual studio 2015 [v140]-for widow 8.1.
i made test code to draw colorful circle shapes with "sf::CircleShape". to show the the error
i suspect it might be a bug with my compiler version. i'm using visual studio 2015 [v140] for window 8.1.
here my test code:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 480), "test!");
std::vector<std::reference_wrapper<const sf::Drawable>> shapes_wrapper;
sf::CircleShape shape(32);
shape.setFillColor(sf::Color::Cyan);
shapes_wrapper.push_back(shape);
std::vector<sf::CircleShape> shapes;
for (int i = 0; i < 2; i++) {
shapes.push_back(sf::CircleShape(32));
if (i == 0) {
shapes.back().setFillColor(sf::Color::Blue);
shapes.back().setPosition(window.getView().getCenter() / 4.0f);
}
else {
shapes.back().setFillColor(sf::Color::Magenta);
shapes.back().setPosition(window.getView().getCenter() / 2.0f);
}
#if 0 // ugly error, it should accept it. <-- probably it's a bug
shapes_wrapper.push_back(shapes.back());
#endif
}
sf::CircleShape test_shape(32);
test_shape.setFillColor(sf::Color::Green);
test_shape.setPosition(window.getView().getCenter() - window.getView().getCenter() / 4.0f);
shapes_wrapper.push_back(test_shape);
sf::CircleShape center_shape(32);
center_shape.setFillColor(sf::Color::Yellow);
center_shape.setPosition(window.getView().getCenter());
shapes_wrapper.push_back(center_shape);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color::White);
for (const auto& shape : shapes)
window.draw(shape);
for (const auto& shape : shapes_wrapper)
window.draw(shape);
window.display();
}
return 0;
}
EDIT: it looks the std::vector of sf::CircleShape objects cause the problem, i replaced it with std::list and it works. also, i have test it with sf::CircleShape pointers ad it works as expected.
std::list<sf::CircleShape> shapes;
or with smart pointer
std::vector<std::unique_ptr<sf::CircleShape>> shapes;
both worked fine in my code.
EDIT 2:
alright, according to https://en.cppreference.com/w/cpp/container/vector/push_back
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
that means we have at least to use reserve() the vector to guarantee that no reallocation will happen by the subsequent of push_back()
fix: in my code it needs to add this:
std::vector<sf::CircleShape> shapes;
shapes.reserve(2);
while in yours it needs to add this:
std::vector<Box> boxes;
boxes.reserve(10);