SFML community forums

Help => Graphics => Topic started by: Bogdan on February 28, 2015, 08:27:26 pm

Title: Counting sprites of specific type in vector
Post by: Bogdan on February 28, 2015, 08:27:26 pm
Hi,

is there a way to count sprites (of specific type) in a vector?

The following code doesn't work and I don't know why? Many thanks in advance for any help.

            int mycount = std::count (EnemyVector.begin(), EnemyVector.end(), sprite);
            std::cout << "number of red squares: " << mycount  << std::endl;

#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    sf::RenderWindow mMainWindow(sf::VideoMode(600,600), "Map", sf::Style::Close);
    mMainWindow.setFramerateLimit(60);
    mMainWindow.setKeyRepeatEnabled(false);

        sf::Image image;
    image.create(50, 50, sf::Color::Red);
        sf::Texture texture;
        texture.loadFromImage(image);

    std::vector<sf::Sprite> EnemyVector;

    while (mMainWindow.isOpen())
    {
        sf::Event event;

        bool creating = false;
                bool rightclick = false;
       
        sf::Vector2i mousePos;

        while (mMainWindow.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                mMainWindow.close();
                break;
            case sf::Event::KeyPressed:
                                if (event.key.code == sf::Keyboard::A)
                                {
                                        creating = true;
                                        break;
                                }
            case sf::Event::MouseButtonPressed:
                                if (event.mouseButton.button == sf::Mouse::Right)
                                {
                                        rightclick = true;
                                        mousePos = sf::Vector2i (event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
                break;
            }
                }
        if (creating)
        {
            sf::Sprite sprite;
            mousePos = (mousePos == sf::Vector2i(0, 0) ? sf::Mouse::getPosition(mMainWindow) : mousePos);
                        sprite.setTexture(texture);

            sprite.setOrigin(static_cast<float>(sprite.getTextureRect().width) / 2, static_cast<float>(sprite.getTextureRect().height) / 2);
            sprite.setPosition(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
            EnemyVector.push_back(sprite);

                        int mycount = std::count (EnemyVector.begin(), EnemyVector.end(), sprite);
                        std::cout << "number of red squares: " << mycount  << std::endl;
                }
                if (rightclick)
                {
                        for (auto& SpriteIt = EnemyVector.rbegin(); SpriteIt != EnemyVector.rend(); ++SpriteIt)
            {
                sf::Vector2f mousecoords(mMainWindow.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)));
                if (SpriteIt->getGlobalBounds().contains(mousecoords))
                                {
                                        EnemyVector.erase( std::next(SpriteIt).base() );

                                        sf::Sprite sprite;
                                        int mycount = std::count (EnemyVector.begin(), EnemyVector.end(), sprite);
                                        std::cout << "number of red squares: " << mycount  << std::endl;
                                        break;
                                }
            }
        }

        mMainWindow.clear();
        for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
        {
            mMainWindow.draw(*enemy);
        }
        mMainWindow.display();
    }
    return 0;
}
 
Title: Re: Counting sprites in vector
Post by: zsbzsb on February 28, 2015, 08:31:10 pm
Maybe RTFM? I have lost count how many times we have said this isn't a general C++ help forum..... I mean you can find the answer in like 10 seconds top with google.

(click to show/hide)
Title: Re: Counting sprites in vector
Post by: Bogdan on February 28, 2015, 08:39:14 pm
I know about vector.size, but what if I have different/many sprite types in one vector, for example red, blue, green etc. squares and want to count the red ones?
Title: Re: Counting sprites in vector
Post by: StormWingDelta on February 28, 2015, 08:58:58 pm
It'd be easier to make a sorted version of the vector of sprites and than keep track of the numbers in a map.  Than again it depends on what you are up to for the most part.  Since this is C++ info and not SFML info it is why you are getting chewed out.


https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=C%2B%2B+counting+the+number+of+occurrences+an+object+in+a+vector&spell=1

http://www.mochima.com/tutorials/STL_algorithms.html

http://www.geeksforgeeks.org/count-number-of-occurrences-in-a-sorted-array/

I could look up more but sites like stackoverflow are more helpful for this kind of thing.  Also there should be some info on CPPReference and a few other sites to speed things a long.

What I normally do is leave my normal vector alone and make a sorted copy of it.  Than use a map to hold at least one of each object that is different and a counter.  Sure it isn't the best solution but it has worked fine for some time.
Title: Re: Counting sprites of specific type in vector
Post by: Bogdan on February 28, 2015, 09:58:55 pm
Is this really a pure cpp problem? In clean cpp it works just fine with numbers:

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
        std::vector<int> EnemyVector1;
        EnemyVector1.push_back(10);
        EnemyVector1.push_back(10);
        EnemyVector1.push_back(10);
        int mycount = std::count (EnemyVector1.begin(), EnemyVector1.end(), 10);
        std::cout << "number of 10s: " << mycount  << std::endl;
        system( "pause" );
}


But he doesn't seem to accept "sprite", whatever I try (counting, sorting....). In the code above it's the "sprite" in the following line, that causes a cryptic error:
int mycount = std::count (EnemyVector.begin(), EnemyVector.end(), sprite);

I don't understand why it can't simply count the sprites. Isn't it an sfml based problem? It wouldn't be difficult to make variables as counters, that increment whenever a sprite of a specific type is created (for example increment variable a by hitting button A and increment variable b by hittung button B), but if I want to remove a sprite by mouse click, it will not recognise which sprite type/color has been removed.
Title: Re: Counting sprites of specific type in vector
Post by: Laurent on February 28, 2015, 10:25:03 pm
Quote
I don't understand why it can't simply count the sprites
Because it has no operator ==.

So in this case, reading the doc would actually have helped you ;)

Quote from: http://www.cplusplus.com/reference/algorithm/count/
T shall be a type supporting comparisons with the elements pointed by InputIterator using operator==

But the problem here is not how to make std::count work with sprites, that is just the solution you think you need. If you tell us about the problem you try to solve, we'll be able to show you the right solution (which probably doesn't involve std::count).
Title: Re: Counting sprites of specific type in vector
Post by: StormWingDelta on March 01, 2015, 01:41:28 am
Well to fully use count you need to do operator overloading.  Open up a blank C++ project and make a custom class with several different sub classes.  You'll have the same issues if you don't tell C++ how to compare your classes & objects.  Since it doesn't know how to do that for you by default.  It knows how to compare datatypes like numbers already so that is why it works.


We also need to know what kind of check are you wanting to do.  Type Only, Static Stats Only, Changing Stats Only, Location, Action, etc.  Judging from what you are saying I'd say Type Comparison is what you are looking for.


Was trying to come up with an example but even I need to work on my C++ more.  In this case it can get count partly working but it still needs changes for it to work with subclasses.  Think of it as a challenge to figure it out. :)

in .h file
bool operator ==(const TypeCheckedOBJ &)const;
bool operator !=(const TypeCheckedOBJ &rightside)const
{
        return !(*this == rightside);
}

 

in .cpp file

bool TypeCheckedOBJ::operator ==(const TypeCheckedOBJ &rightside)const
{
        return (typeid(*this) == typeid(rightside));
}
 

in main
TypeCheckedOBJ test1("Test1"), test2("Test2");
TypeCheckedOne test3("Test3"), test4("Test4");
TypeCheckedTwo test5("Test5"), test6("Test6");

vector<TypeCheckedOBJ> objlist;
objlist.push_back(test1);
objlist.push_back(test2);
objlist.push_back(test3);
objlist.push_back(test4);
objlist.push_back(test5);
objlist.push_back(test6);

cout << "Count Test_1: " << count(objlist.begin(), objlist.end(), test1) << endl;
cout << "Count Test_2: " << count(objlist.begin(), objlist.end(), test3) << endl;
cout << "Count Test_3: " << count(objlist.begin(), objlist.end(), test5) << endl;
 
I made a base class and two sub classes off of it to test.  In this case count likely fails for the sub classes because everyone is because changed to the base class.  From here though it should be easy to find a solution.  Since this is a pure C++ issue hunt around some site that help C++ programmers.


Keep in mind this code above is what can be used with any class if you change out the class names.  Meantime I'll keep working on this for when it might be useful again.

Keep in mind though there are many other ways but since you wanted to use count I wanted to see if count was even usable.  It is just there might be more work than it is worth to get it to fully work.
Title: Re: Counting sprites of specific type in vector
Post by: Bogdan on March 01, 2015, 12:23:07 pm
Ok, as I see that this code doesn't work for me, I have another, more simple approach.
But the problem with it is, that it only works with red squares. The question is, how to detect if a red or a blue square was erased. Knowing this, I could make a simple if condition, that decrements the right variables.


#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>

int main()
{
    sf::RenderWindow mMainWindow(sf::VideoMode(600,600), "Map", sf::Style::Close);
    mMainWindow.setFramerateLimit(40);
    mMainWindow.setKeyRepeatEnabled(false);

        sf::Image image;
    image.create(50, 50, sf::Color::Red);
        sf::Texture texture;
        texture.loadFromImage(image);

        sf::Image image2;
    image2.create(50, 50, sf::Color::Blue);
        sf::Texture texture2;
        texture2.loadFromImage(image2);

    std::vector<sf::Sprite> EnemyVector;

                int numberofredsquares = 0;
                int numberofbluesquares = 0;

    while (mMainWindow.isOpen())
    {
        sf::Event event;

        bool creating = false;
                bool creating2 = false;
                bool rightclick = false;
       
        sf::Vector2i mousePos;

        while (mMainWindow.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                mMainWindow.close();
                break;
            case sf::Event::KeyPressed:
                                if (event.key.code == sf::Keyboard::A)
                                {
                                        creating = true;
                                        break;
                                }
                                if (event.key.code == sf::Keyboard::B)
                                {
                                        creating2 = true;
                                        break;
                                }
            case sf::Event::MouseButtonPressed:
                                if (event.mouseButton.button == sf::Mouse::Right)
                                {
                                        rightclick = true;
                                        mousePos = sf::Vector2i (event.mouseButton.x, event.mouseButton.y);
                                        break;
                                }
                break;
            }
                }
        if (creating)
        {
            sf::Sprite sprite;
            mousePos = (mousePos == sf::Vector2i(0, 0) ? sf::Mouse::getPosition(mMainWindow) : mousePos);
                        sprite.setTexture(texture);

            sprite.setOrigin(static_cast<float>(sprite.getTextureRect().width) / 2, static_cast<float>(sprite.getTextureRect().height) / 2);
            sprite.setPosition(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
            EnemyVector.push_back(sprite);
                        numberofredsquares++;
                        std::cout << "number of red squares: " << numberofredsquares << std::endl;
                }
                if (creating2)
        {
            sf::Sprite sprite2;
            mousePos = (mousePos == sf::Vector2i(0, 0) ? sf::Mouse::getPosition(mMainWindow) : mousePos);
                        sprite2.setTexture(texture2);

            sprite2.setOrigin(static_cast<float>(sprite2.getTextureRect().width) / 2, static_cast<float>(sprite2.getTextureRect().height) / 2);
            sprite2.setPosition(static_cast<float>(mousePos.x), static_cast<float>(mousePos.y));
            EnemyVector.push_back(sprite2);
                        numberofbluesquares++;
                        std::cout << "number of blue squares: " << numberofbluesquares << std::endl;
                }
                if (rightclick)
                {
                        for (auto& SpriteIt = EnemyVector.rbegin(); SpriteIt != EnemyVector.rend(); ++SpriteIt)
            {
                sf::Vector2f mousecoords(mMainWindow.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y)));
                if (SpriteIt->getGlobalBounds().contains(mousecoords))
                                {
                                        EnemyVector.erase( std::next(SpriteIt).base() );
                                        numberofredsquares--;
                                       
                                        std::cout << "number of red squares: " << numberofredsquares << std::endl;
                                        break;
                                }
            }
        }

        mMainWindow.clear();
        for (auto& enemy = EnemyVector.begin(); enemy != EnemyVector.end(); ++enemy)
        {
            mMainWindow.draw(*enemy);
        }
        mMainWindow.display();
    }
    return 0;
}

Title: Re: Counting sprites of specific type in vector
Post by: Laurent on March 01, 2015, 01:02:52 pm
A few solutions, to apply directly or for inspiration:

1.
if (SpriteIt->getTexture() == &texture1)
    red;
else
    blue;

2. Store blue sprites and red sprites in two separate containers.

3. Wrap sf::Sprite in your own class which adds an attribute that allows you to directly query its color.