b2Contact of the contact manager is linked list data. So,
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
means start from m_contactList and loop untilc->next
meetsNULL
I don't know how your contact listener works, but you have to pay attention to the timing of the world step, collision check and destroy. Because, the contact listener is called each time when there's a contact while world is stepping. So if your contact listener is designed to store contact data, then you have to process all the contact data between world step and destroy. (If you don't, there might be dangling pointers of the destroyed body in contact data)
If you want to destroy coins when they fill the array, you'd better check the array if there is same object.
Box2D Infinite Loop (b2World::SolveTOI)
-
28-06-2022 - |
Question
I'm using Box2D and Cocos2D for iOS.
From time to time, the game freezes and it is caused by an infinite loop on b2World::SolveTOI.
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
{
// Invalidate TOI
c->m_flags &= ~(b2Contact::e_toiFlag | b2Contact::e_islandFlag);
c->m_toiCount = 0;
c->m_toi = 1.0f;
}
I have a game where a "hero" has to collect coins. Coins are bodies, and through the contact listener I'm adding bodies in an array in order to destroy them later when the array is full (count = 2).
Here is how I add bodies to the array:
+ (void) addBodyToDestroy:(b2Body *)body {
[toDestroyArray addObject:[NSValue valueWithPointer:body]];
}
And here is how I destroy them:
+ (void) destroyAllBodies {
b2World *world = [InGame getWorld];
for (NSValue *bodyValue in toDestroyArray)
{
b2Body *body;
body = (b2Body*)[bodyValue pointerValue];
world->DestroyBody(body);
body = NULL;
}
[toDestroyArray removeAllObjects];
}
What I find very weird is that it doesn't freeze every time, just sometimes, and I can't get to know what seemes to block...
Solution : The body was added more than once into the array to be destroyed, so when the array was full, it was destroyed more than once, which caused the infinite loop.
Solution
OTHER TIPS
for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next)
is quite an unusual for loop, at least from my experience. I can clearly explain what it does, and maybe this will help you.
This is how a for loop works:
for( /*code called at beginning, usually to create a counting variable*/;/*code that is checked for a boolean value every loop. True means loop again, false means stop. Usually this is checking the value of the counting variable.*/;/*code that is called at the end of each loop. Usually this is advancing the counting variable*/) {
//Code inside the loop that does stuff many times
}
So for this loop:
The loop starts. a new
b2Contact
pointer namedc
is created and is assigned to the value of them_contactList
property ofm_contactManager
.The loop checks the value of
c
and determines a value of eithertrue
orfalse
. In this case, sincec
appears to be an instance of an object, it probably is checking whetherc
isnil
or not.At the end of each loop,
c
is set to point to them_next
member ofc
. This is quite strange asc
is no longerm_contactList
but something contained bym_contactList
. Then again this could be perfectly normal. You should know what your code does.