Search code examples
c++box2dsfmlstdvector

Collectible not deleting on contact


I have created collectible objects and a vector to store them, for easy and efficient deletion on contact.

I know that my contact listener works, and that my marked, GetBody and SetUserData functions for my collectibles also work.

I have tried checking each individual collectible object for contact, which does work, although throws a user data error for other reasons.

I know that this works because if I use the following code:

    if (m_coin2->marked())
    {
        m_coin2->setFillColor(sf::Color::Blue);
    }

The coin object in question does in fact turn blue.

This is my game header file (relevant code only):

class Game : public sf::Drawable {
private:
    //Collectibles
    Collectible* m_coin;
    Collectible* m_coin2;
    Collectible* m_coin3;
    Collectible* m_coin4;
    Collectible* m_coin5;
    Collectible* scoreBlock;

    Character* m_character;

    //score
    int score = 0;
public:
    std::vector<Collectible> m_coins;
};

This is my game.cpp file (relevant parts only):

//In the constructor
    //create collectibles
    //hud elements
    scoreBlock = new Collectible(m_pWorld, sf::Vector2f(scoreText.getPosition().x + .6f, -2.6f), sf::Vector2f(0.5f, 0.5f), 0.f, &m_collect);
    //collectibles
    m_coin = new Collectible(m_pWorld, sf::Vector2f(4.f, 2.15f), sf::Vector2f(0.3f, 0.3f), 0.f, &m_collect);
    m_coin2 = new Collectible(m_pWorld, sf::Vector2f(16.5f, -0.6f), sf::Vector2f(0.3f, 0.3f), 0.f, &m_collect);
    m_coin3 = new Collectible(m_pWorld, sf::Vector2f(30.f, 0.4f), sf::Vector2f(0.3f, 0.3f), 0.f, &m_collect);
    m_coin4 = new Collectible(m_pWorld, sf::Vector2f(20.f, 1.4f), sf::Vector2f(0.3f, 0.3f), 0.f, &m_collect);
    m_coin5 = new Collectible(m_pWorld, sf::Vector2f(47.f, -1.f), sf::Vector2f(0.3f, 0.3f), 0.f, &m_collect);

m_coins = { *m_coin, *m_coin2, *m_coin3, *m_coin4, *m_coin5 };

//In the update function
    for (auto it = m_coins.begin(); it != m_coins.end(); it++)
    {
        if (it->marked())
        {
            m_pWorld->DestroyBody(it->GetBody());
            m_coins.erase(it);
            it->SetUserData();
            score++;
        }
    }

At the moment, this does nothing on contact between the player and the collectible, I think it may be something to do with the way I initialised the vector?

Any help is appreciated, thanks.


Solution

  • If you iterate through a vector, you better do not use the erase function of the vector in the iteration loop. Use a while loop instead. Or the problem is that you only use a copy of the coins and not the pointer to the coins.

    That's what I would do:

    ...
    std::vector<Collectible*> m_coins;
    ...
    
    m_coins = { m_coin, m_coin2, m_coin3, m_coin4, m_coin5 };
    
    //In the update function
         auto it = m_coins.begin();
         while (it != m_coins.end())
         {
             if ((*it)->marked())
             {
                m_pWorld->DestroyBody((*it)->GetBody());
                (*it)->SetUserData();               
                m_coins.erase(it);  
                score++;
             }
             it++;
         }