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

Author Topic: How to implement sprite group?  (Read 2139 times)

0 Members and 1 Guest are viewing this topic.

gurbuz

  • Newbie
  • *
  • Posts: 2
    • View Profile
How to implement sprite group?
« on: January 10, 2020, 12:04:44 pm »
I wanna try implement sprite group as in pygame. I acted according to this article, 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)

« Last Edit: January 10, 2020, 12:22:24 pm by gurbuz »

Mortal

  • Sr. Member
  • ****
  • Posts: 284
    • View Profile
Re: How to implement sprite group?
« Reply #1 on: January 10, 2020, 03:28:49 pm »
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

Quote
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);
« Last Edit: January 10, 2020, 06:48:31 pm by Mortal »