Безкраен цикъл на Box2D (b2World::SolveTOI)

Използвам Box2D и Cocos2D за iOS.

От време на време играта замръзва и това е причинено от безкраен цикъл на 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;
    }

Имам игра, в която "герой" трябва да събира монети. Монетите са тела и чрез слушателя на контакти добавям тела в масив, за да ги унищожа по-късно, когато масивът е пълен (брой = 2).

Ето как добавям тела към масива:

+ (void) addBodyToDestroy:(b2Body *)body {
[toDestroyArray addObject:[NSValue valueWithPointer:body]];
}

И ето как ги унищожавам:

+ (void) destroyAllBodies {

b2World *world = [InGame getWorld];

for (NSValue *bodyValue in toDestroyArray)
{
    b2Body *body;
    body = (b2Body*)[bodyValue pointerValue];
    world->DestroyBody(body);
    body = NULL;
}

[toDestroyArray removeAllObjects];
}

Това, което намирам за много странно, е, че не замръзва всеки път, а само понякога, и не мога да разбера какво изглежда да блокира...

Решение: Тялото беше добавено повече от веднъж в масива за унищожаване, така че когато масивът беше пълен, той беше унищожен повече от веднъж, което причини безкрайния цикъл.


person thegameg    schedule 09.09.2013    source източник
comment
Опитахте ли да добавите точки на прекъсване и NSLogs?   -  person WolfLink    schedule 10.09.2013
comment
Да, проблемният цикъл е този: for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) Но не съм сигурен, че наистина разбирам какво прави, изглежда, че m_contactManager.m_contactList не свършва.   -  person thegameg    schedule 10.09.2013


Отговори (2)


  1. b2Контактът на мениджъра на контактите е свързан списък с данни. И така, for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) означава започване от m_contactList и цикъл, докато c->next срещне NULL

  2. Не знам как работи вашият слушател за контакти, но трябва да обърнете внимание на времето на световната стъпка, проверката на сблъсък и унищожаването. Защото слушателят на контакт се извиква всеки път, когато има контакт, докато светът стъпва. Така че, ако вашият слушател на контакти е проектиран да съхранява данни за контакт, тогава трябва да обработите всички данни за контакт между стъпката на света и унищожаването. (Ако не го направите, може да има висящи указатели на унищоженото тяло в данните за контакт)

  3. Ако искате да унищожите монети, когато запълнят масива, по-добре проверете масива дали има същия обект.

person onnlv    schedule 10.09.2013
comment
Беше моят контактен слушател. Не проверявах дали тялото вече е в масива, така че мисля, че се опитвах да го унищожа повече от веднъж. Използвах userData, за да избегна масива и работи! - person thegameg; 10.09.2013

for (b2Contact* c = m_contactManager.m_contactList; c; c = c->m_next) е доста необичаен for цикъл, поне от моя опит. Мога ясно да обясня какво прави и може би това ще ви помогне.

Ето как работи цикъл for:

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
}

Така че за този цикъл:

  1. Цикълът започва. създава се нов b2Contact указател с име c и се присвоява на стойността на свойството m_contactList на m_contactManager.

  2. Цикълът проверява стойността на c и определя стойност на true или false. В този случай, тъй като c изглежда като екземпляр на обект, вероятно се проверява дали c е nil или не.

  3. В края на всеки цикъл c е настроен да сочи към члена m_next на c. Това е доста странно, тъй като c вече не е m_contactList, а нещо, съдържащо се от m_contactList. След това отново това може да е напълно нормално. Трябва да знаете какво прави вашият код.

person WolfLink    schedule 10.09.2013
comment
Да, наясно съм с това. Но необичайното е, че c никога не е nil, така че никога не излизам от цикъла. Това, което ми е любопитно и изглежда не мога да разбера, е какво прави този цикъл за двигателя на Physics? - person thegameg; 10.09.2013
comment
Откъде взехте този цикъл? - person WolfLink; 11.09.2013
comment
Това е от b2World клас на Box2D. - person thegameg; 12.09.2013