Бесконечный цикл 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, поэтому я никогда не выхожу из цикла. Что мне любопытно, и я не могу понять, что делает этот цикл для физического движка? - person thegameg; 10.09.2013
comment
Откуда у тебя эта петля? - person WolfLink; 11.09.2013
comment
Это из класса b2World Box2D. - person thegameg; 12.09.2013