Click here to Skip to main content
15,867,835 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
This is my first post on codeproject.com Right I am new to game programming and I am stuck with this problem since more than two hours now. Basically it is a small 2D game with bubbles and spiky things. I am stuck with the part where I need to check the collisions. I am getting the dreaded iterator cannot be referenced error. Moreover, its not crashing at the beginning or end of the loop its pretty random and I am not able to figure out if I am doing something wrong while erasing the element from list.
in the beginning of the program I have instantiated objects of these classes.
Bubbles* bubbles;
Spikies* spikies;
Both these classes have std::list of bubble instances( bubbleList)and spiky instances (spikyList) respectively

BubbleList::iterator bubbleIter;
SpikyList::iterator spikyIter;
bool isTouching = false;

bubbleIter = bubbles->bubbleList.begin();
if(!bubbles->bubbleList.empty())
{
    while( bubbleIter != bubbles->bubbleList.end() )
    {
        isTouching = false;
        for(spikyIter = spikies->spikyList.begin(); spikyIter != spikies->spikyList.end(); spikyIter++)
        {

            if( (*spikyIter)->mState == ALIVE)
                isTouching = (*bubbleIter)->boundingCircle->Intersects((*spikyIter)->boundingCircle);

            if(isTouching)
            {
                SAFE_DELETE(*bubbleIter);

                bubbleIter = bubbles->bubbleList.erase(bubbleIter);
                (*spikyIter)->mState = DEAD;


            }
        }
        //checking if we are not at the end of the list
        if( bubbleIter != bubbles->bubbleList.end())
            ++bubbleIter;
        //check if list is empty
        if( bubbles->bubbleList.empty() )
            break;
    }
}

Any input would be much appreciated. Thanks.

[Edit: Changed code tags to those used on this site - Avi Berger]
Posted
Updated 17-Mar-10 20:39pm
v3

Your logic isn't right for what it appears you want to do. You are not iterating through the two lists the way that you think you are. Once I started in on your code, I ended up doing a bit more than I intended. You will want to compare what I did with your own and figure out the reason for all the differences. You will also want to check that what I am presuming your intent was is correct. (Also, this is off the top of my head, I haven't tried compiling it.)

C++
BubbleList::iterator bubbleIter;
SpikyList::iterator spikyIter;
bool isTouching = false;

bubbleIter = bubbles->bubbleList.begin();
while( bubbleIter != bubbles->bubbleList.end() )
{
    isTouching = false;
    for( spikyIter = spikies->spikyList.begin();
         spikyIter != spikies->spikyList.end();
         spikyIter++ )
    {
        if( (*spikyIter)->mState == ALIVE &&
            (*bubbleIter)->boundingCircle->Intersects((*spikyIter)->boundingCircle) )
        {
            isTouching = true;
            (*spikyIter)->mState = DEAD;
        }
    }
    if( isTouching  )
    {
        SAFE_DELETE(*bubbleIter);
        bubbleIter = bubbles->bubbleList.erase(bubbleIter);
    }
    else
        ++bubbleIter;
}


At a second look over your code, I believe that I have spotted the immediate source of your reported error. It should be rectified by my revision above.

Consider the scenario that you have a bubble at the end of the bubble list that is touching a spiky that is not at the end of the spiky list.

In your original inner loop you will delete that bubble and remove it from the bubble list. In doing so, you advance your bubbleIter to bubbleList.end() - no longer an actual list entry. Since you are not at the end of the spiky list, your inner loop continues executing. It tries to check if the next spiky is touching the bubble now indicated by bubbleIter. But that is not a bubble, it is bubbleList.end(). You try to access it. Boom! Clear now? You really either wanted to terminate the inner loop early or defer deleting the bubble and advancing bubbleIter until after that loop finished.
 
Share this answer
 
v7
Try to extend your step condition :) :
C++
if (!IsTouching && bubbleIter != bubbles->bubbleList.end()) {
  ++bubbleIter;
}

...and this "scope" too :) :
if (isTouching)	{
  SAFE_DELETE(*bubbleIter);				
  bubbleIter = bubbles->bubbleList.erase(bubbleIter);
  (*spikyIter)->mState = DEAD;
  if (bubbleIter == bubbles->bubbleList.end()) {
    break; // there are no bubbles more :)
  }
}


Please note, that a bubble will be erased by the only one touching now,
so the only one spiky will be killed... :)

The code answer of Avi Berger does show
how to kill the all touched spikies by a bubble and
how to hold the procedure shorter, easier, more secure and readable :)

Have fun !
 
Share this answer
 
v3
Hey Avi Berger,
Thanks very much for the post. There was problem with my logic...working too late does slow down logical thinking. :-D Your code has resolved it but there is a small modification to the code. Perhaps, I did not explain the problem clearly. I am trying to burst the bubble and mark the spiky as dead both in the nested loops. In the inner if statement I had to break out of the loop cos the loop still iterates checking collisions with the bubble that is supposed to be dead. So here is the update.
Cheers!:thumbsup:

C++
if( (*spikyIter)->mState == ALIVE &&
    (*bubbleIter)->boundingCircle->Intersects((*spikyIter)->boundingCircle) )
{
    isTouching = true;
    (*spikyIter)->mState = DEAD;
    break;//so that we dont check collision with the dead bubble again
}
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900