После выполнения расчета шага физики можно обработать все тела и соединения. Скорее всего, вы будете проверять позиции тел, чтобы иметь возможность обновить позиции объектов в игре и прорисовать их на экране. Можно выполнять расчет шага физики в любом месте игрового цикла, но следует быть осторожным с порядком выполнения операций. Например, если необходимо в текущем кадре создать новое тело и сразу проверить пересечение объектов с ним, то нужно сначала создать тело, расположить его в нужном месте мира, запустить расчет шага физики, и только потом проверять произошло ли столкновение.
Как уже обсуждалось в уроке Heiioworid, следует использовать фиксированную длительность шага. Использование больших шагов повысит производительность в приложениях с низкой частотой кадров. Но не стоит использовать шаг длиннее 1/30 секунды. Обычно 1/60 секунды достаточно для высококачественного моделирования.
Количество итераций определяет, сколько раз будут произведены расчеты над всеми телами и соединениями в мире. Большее число итераций всегда обеспечивает лучшее качество моделирования. Но не стоит сочетать маленький шаг с большим количеством итераций. 60Гц (Герц) и 10 итераций гораздо лучше 30Гц и 20 итераций.
Примечание переводчика
Дело здесь в том, что при делении очень маленького числа (длины шага) на очень большое (кол-во итераций) мы кроме всего прочего можем вообще ноль получить.
Пример погрешности при работе с маленькими числами:
float А = 0.0001f; int В = А*10000;
В MSVS2008 на стандартных настройках В равно 0 а совсем не 1.
kkray
4.3.2. Просмотробъектовмира
Как упоминалось ранее, мир является "контейнером" для всех объектов и соединений. Поэтому, из мира можно получить список всех тел и соединений мира, а затем сделать что-нибудь с каждым из них. Например, следующий код заставляет все тела "проснуться":
for (b2Body* b = myWorld->GetBodyList(); b; b = b->GetNext()) {
b->WakeUp() ; }
К сожалению, в жизни не все так просто. Например, следующий вариант кода будет работать неправильно:
for (b2Body* b = myWorld->GetBodyList(); b; b = b->GetNext())
{
GameActor* myActor = (GameActor*)b->GetUserData(); if (myActor->IsDead() )
{
// ОШИБКА: после этой операции GetNext возвратит мусор
myWorld->DestroyBody(b); } }
В этом коде все будет работать правильно только до момента удаления тела. После удаления тела, указатель на следующее тело (который хранится внутри тела) станет неправильным. Поэтому функция b2Body::GetNext() вернет указатель на мусор. Во избежание этого, необходимо сохранять указатель на следующее тело перед удалением, как в примере ниже.
b2Body* node = myWorld->GetBodyList(); while (node)
{
b2Body* b = node;
node = node->GetNext();
GameActor* myActor = (GameActor*)b->GetUserData(); if (myActor->IsDead())
{
myWorld->DestroyBody(b);
} }
Данный код производит безопасное удаление текущего тела. Однако, может потребоваться функция удаляющая сразу несколько тел. В таком случае надо быть осторожным. Пример такой функции приведен ниже, но точный вид функции будет зависеть от вашего приложения.
b2Body* node = myWorld->GetBodyList(); while (node)
{
b2Body* b = node;
node = node->GetNext();
GameActor* myActor = (GameActor*)b->GetUserData(); if (myActor->IsDead())
{
bool otherBodiesDestroyed = GameCrazyBodyDestroyer(b); if (otherBodiesDestroyed)
{
node = myWorld->GetBodyList();
} } } Здесь, функция GameCrazyBodyDestroyer производит удаление тела и/или других тел,
поэтому, если удаляется несколько тел, то указатель node на следующее тело может оказаться неправильным и надо начинать просмотр тел с начала.
4.3.3. ААВВ запросы
Иногда требуется определить все фигуры находящиеся
в определенном регионе. Класс b2World содержит такую функцию и скорость ее работы высока. Функция принимает в качестве параметров ААВВ в мировых координатах и возвращает массив всех фигур, которые пересекаются с ААВВ (или находятся полностью в нём). Слово "пересекаются" не совсем правильно, так как проверка на пересечение происходит между ААВВ региона и ААВВ самих фигур. Например, следующий код находит все тела находящиеся в ААВВ и будит их.
Ь2ААВВ aabb;
aabb.lowerBound.Set(-1.Of, -1.Of); aabb.upperBound.Set(1.Of, 1.Of); const int32 k_bufferSize = 10; b2Shape *buffer[k_bufferSize];
int32 count = myWorld->Query(aabb, buffer, k_bufferSize); for (int32 1=0; 1 < count; ++1)
{
buffer[1]->GetBody()->WakeUp();
}
Глава 5. Тела
Содержание
5.1. О телах 5.2. Определение тела 5.2.1. Масса 5.2.2. Позиция и угол 5.2.3. Торможение 5.2.4. Параметры сна 5.2.5. Снаряды 5.3. Фабрика тел 5.4. Использование тел 5.4.1. Данные о массе 5.4.2. Информация о состоянии тела 5.4.3. Положение и скорость 5.4.4. Силы и импульсы 5.4.5. Преобразование координат 5.4.6. Списки
5.1. Отелах
У тел есть положение и скорость. К ним можно применять силы, моменты и импульсы. Тела могут быть статичными или динамичными, статичные тела никогда не перемещаются и не взаимодействуют с другими статичными телами.
Тела основа всех игровых форм. Они состоят из фигур и перемещаются вместе с ними. Тела прежде всего являются "твердыми". Это означает, что две фигуры, присоединенные к одному телу, всегда будут оставаться неподвижными друг для друга.