Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Box2d: анатомия коллизий

Anna | 24.06.2014 | нет комментариев

В Box2D принято считать, что друг с ином сталкиваются тела, впрочем на самом деле при расчете коллизий применяются фикстуры (fixtures, переводы слова существуют, но я не уверен, есть ли среди них устоявшийся). Объекты могут сталкиваться различными методами, следственно библиотека предоставляет огромное число уточняющей информации, которая может быть использована в игровой логике. Скажем, вы можете захотеть узнать следующее:

  • Когда соударение начинается и заканчивается
  • Точку соприкосновения фикстур
  • Вектор нормали к линии контакта фикстур
  • Какая энергия была приложена и итог коллизии

Традиционно соударение происходит дюже стремительно, впрочем в этой статье мы попытаемся взять одну определенную коллизию и замедлить ее, Дабы поспеть разглядеть детали протекающего и информацию, которую дозволено извлечь из события.

В нашем сценарии будут сталкиваться две полигональные фикстуры в мире с нулевой гравитацией (Дабы отменнее контролировать процесс). Первая фикстура — неперемещаемый квадрат, вторая — движущийся горизонтально по направлению к квадрату треугольник.

Все настроено таким образом, Дабы нижняя часть треугольника столкнулась с верхним углом квадрата. Тонкости реализации этого процесса выходят за рамки статьи — основное внимание уделим тому, какую информацию дозволено извлечь на всяком этапе соударения. Если есть желание независимо запустить предлагаемый пример, начальный код прилагается.

Приобретении информации о соударении

Информация о соударении содержится в объекте типа b2Contact. Из него дозволено узнать, какие именно фикстуры сталкиваются, и определить их расположение и направление результирующих толчков. Существует два метода приобретения объектов b2Contact в Box2D. 1-й — перебрать нынешний список контактов всякого тела объекта, 2-й — применять слушатель контактов. Разглядим всякий из них, Дабы дальше было внятнее, о чем идет речь.

Проверка списка контактов

В всякий момент дозволено перебрать все контакты мира (имеется в виду b2World)

  for (b2Contact* contact = world->GetContactList(); contact; contact = contact->GetNext())
      contact->... //do something with the contact

либо получить контакты тела определенного объекта

for (b2ContactEdge* edge = body->GetContactList(); edge; edge = edge->next)
      edge->contact->... //do something with the contact

Если выбран данный подход, дюже значимо помнить, что присутствие контакта в этих списках не обозначает, что фикстуры соприкасаются — это значит только, что пересекаются их AABB. Если требуется удостовериться, что контактируют сами фикстуры, воспользуйтесь способом IsTouching(). К этому вопросу мы еще возвратимся.

Слушатели контактов

Проверка списка контактов становится неэффективной в обстановках, когда соударения происходят Зачастую и в крупных числах. Устанавливая слушателей контактов, вы отдаете поручение Box2D информировать, когда происходит что-то увлекательное, взамен того, Дабы вручную следить за началом и заключением соударений. Слушатель контактов — это объект класса b2ContactListener, часть функций которого замещается при необходимости.

  void BeginContact(b2Contact* contact);
  void EndContact(b2Contact* contact);
  void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
  void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);

Должен подметить, что в зависимости от обстановки, некоторые события дают нам не только объектb2Contact. В процессе выполнения функции Step, когда Box2D определяет, что случился контакт, он исполняет обратный вызов определенных функций слушателя, Дабы уведомить вас. Фактическое применение “обратных вызовов при коллизиях” рассматривается в отдельной статье. Тут мы все внимание сфокусируем на том, что дозволено узнать, обрабатывая события соударений.

В всеобщем случае я рекомендую способ слушателей контактов. На 1-й взор он может показаться несколько несуразным, впрочем он больше результативен и пригоден в долгосрочной перспективе. До сих пор мне не встречалась обстановка, когда проверка списка контактов давала бы ощутимый выигрыш.

Вне зависимости от метода приобретения контактов, они содержат идентичную информацию. Особенно значимые данные о пересекающихся фикстурах дозволено получить так

b2Fixture* a = contact->GetFixtureA();
  b2Fixture* b = contact->GetFixtureB();

Когда происходит обход списка контактов определенного объекта, допустимо, одна из фикстур коллизии вестима, но если применяется слушатель контактов, придется всецело положиться на эти функции, Дабы осознать, что с чем сталкивается. Отчетливо заданного порядка фикстур не существует, так что Зачастую доводится устанавливать пользовательские данные (user data), Дабы осознать, какому именно объекту принадлежит фикстура либо тело. Располагая объектом фикстуры, дозволено воспользоваться способомGetBody(), Дабы получить ссылку на тело.

Соударение шаг за шагом.

Сейчас давайте подробнее разглядим последовательность событий, протекающих при соударении. Верю, картинок с изложением всякого шага будет довольно для понимания материала. Допустимо, вы захотите загрузить исходники к уроку, Дабы запускать их во время чтения. Тестовая программа разрешает ставить симуляцию на паузу, перезапускать и исполнять ее по шагам.

Начнем с обстановки, когда AABB фикстур не пересекаются, так мы сумеет проследить историю всецело. Кликните флажок «AABBs», Дабы увидеть фиолетовые прямоугольные области вокруг всякой фикстуры.

AABB фикстур начинают перекрываться

Невзирая на то, что сами фикстуры еще не пересеклись, на этом этапе теснее создается экземплярb2Contact и добавляется в список контактов мира и списки всякого тела. Если вы просматриваете эти списки, то по наличию объектов b2Contact дозволено судить о том, что в тезисе контакт допустим, правда фикстуры не непременно пересеклись.

Итог: контакт существует, но IsTouching() возвращает вранье

Продолжаем симуляцию, пока не пересекутся непринужденно фикстуры…

Фикстуры начинают пересекаться.

Приблизив верхний угол квадрата, дозволено увидеть переход, как на следующих изображениях

Шаг n

Шаг n 1 (не bullet-объекты)

Все это происходит за один шаг симуляции, значит, реальную точку пересечения (к которой ведет пунктирная линия на рисунке выше), мы проскочили. Это происходит потому, что Box2D вначале смещает все тела и только потом проверяет пересечения, по крайней мере, это его поведение по умолчанию. Если вам необходима настоящая точка соприкосновения, то необходимо сделать следующее

bodyDef.bullet = true; //before creating body, or      
  body->SetBullet(true); //after creating body

Шаг n 1 (треугольник — bullet-объект)

Bullet-тела, расходуют огромнее процессорного времени на расчеты и для большинства приложений не требуются. Легко помните о том, что при обыкновенных настройках, изредка коллизии могут пропускаться — в нашем примере, если бы треугольник двигался довольно стремительно, он мог бы пролететь через угол квадрата, не инициировав соударения. Если у вас есть дюже стремительно перемещающиеся тела, контакты которых не обязаны пропускаться, скажем, мммм… пули :) тогда их необходимо объявлять как bullet-объекты. Последующее изложение будет вестись для Сейчас возвратимся к последовательности событий.

Реакция на соударение

( (b2Contact::Update, b2Island::Report))
Шаг_столкновения

Шаг_столкновения 1

Шаг_столкновения 1

Когда фикстуры перекрываются, реакция Box2d по умолчанию — приложить толчок к всякой из них, Дабы направить в различные стороны. Впрочем это не неизменно получается сделать за один шаг моделирования. Как показано на рисунках для нашего примера, две фикстуры будут перекрываться на протяжении 3 шагов, пока отскок не состоится, и они окончательно не разделятся.

В это время мы можем встрять и настроить поведение модели, как нам захочется. Если применяется подход со слушателем контактов, способы PreSolve и PostSolve будут вызываться на всяком шаге, пока фикстуры перекрываются, давая вероятность модифицировать контакт перед тем, как он будет обработан стандартными средствами реакции на коллизию (PreSolve), и узнать, какие толчки были приложены Box2D (PostSolve)

Для большей наглядности приведу итог printf, которая размещена в в функцию Step и всякий способ слушателя контактов:

        ...
        Step
        Step
        BeginContact
        PreSolve
        PostSolve
        Step
        PreSolve
        PostSolve
        Step
        PreSolve
        PostSolve
        Step
        EndContact
        Step
        Step
        ...

Итог: PreSolve and PostSolve вызываются несколько раз

PreSolve and PostSolve

Оба эти способа получают в качестве параметра указатель на b2Contact, так что мы имеем доступ к той же информации о точках и нормалях, что и в BeginContact. PreSolve дает на вероятность изменить колляции контакта перед расчетом реакции на соударение и даже отменить реакцию всецело. PostSolve разрешает получить информацию о вычисленной реакции.

В PreSolve дозволено сделать следующие настройки объекта контакта:

  void SetEnabled(bool flag);//non-persistent - need to set every time step

  //these available from v2.2.1
  void SetFriction(float32 friction);//persists for duration of contact
  void SetRestitution(float32 restitution);//persists for duration of contact

Вызов SetEnabled(false) деактивирует контакт, значит, реакция на соударение просчитываться не будет. Это может потребоваться, когда нужно временно дозволить объектам пролетать друг через друга. Типичный пример — односторонняя стена либо платформа, когда игрок может пройти через традиционно непроходимый объект при определенных условиях, которые дозволено проверить только во время выполнения — скажем, позиция игрока либо направление его движения.

Значимо помнить, что на дальнейшей итерации контакт вновь активируется, так что если необходимо отключить его на продолжительное время, придется делать это на всяком шаге.

Помимо ссылки на контакт, PreSolve содержит 2-й параметр, из которого дозволено получить колляции коллизии (точки и нормаль) с предыдущего шага моделирования. Если кто-то знает, для чего это может сгодиться — расскажите мне :D

PostSolve вызывается позже того, как реакция на соударение была рассчитана и применена. У способа есть 2-й параметр, содержащий информацию о приложенном в итоге толчке. Традиционно он применяется для проверки, не превысила ли реакция некоторое пороговое значения, в итоге чего объект дозволено разломать и т.п. В статье “ sticky projectiles” содержится пример применения функции PostSolve для определения, должна ли стрела застревать в мишени.

Возвращаемся к сценарию соударения

Фикстуры огромнее не перекрываются

(b2Contact::Update)
AABB все еще перекрываются, так что контакт пока остается в соответствующих списках мира и тела.

(увеличенный масштаб)

Результат:

  • Вызывается EndContact
  • IsTouching() возвращает вранье

Так продолжается до тех пор, пока AABB не перестанут перекрываться

AABB фикстур не перекрываются

(b2ContactManager::Collide)

Итог: контакт удаляется из списка контактов мира и тела.

Способ EndContact получает указатель на b2Contact, когда фикстуры теснее не соприкасаются, так что в нем теснее не содержится востребованной информации. Тем не менее EndContact является неотделимым элементом слушателя контактов, так как разрешает контролировать, когда игровые объекты покидают зону соприкосновения.

Результат

Верю, что в статье дан внятный обзор того, что происходит милисекунда за милисекундой в недрах механизма расчета соударений Box2D. Допустимо, это было не самое увлекательное чтение, впрочем позже постижения различных вопросов на форумах меня не покидало чувство, что некоторые детали Зачастую упускаются, в итоге огромное число времени расходуется на то, Дабы разобраться, что вообще происходит… Также я подметил тенденцию, когда реализовывать слушатель контактов не решаются, в то время как это требует значительно меньших усилий по сопоставлению с последующими задачами. Познание описанных деталей должно дать лучшее осознавание пророческой, тот, что дозволено реализовать, усовершенствовать дизайн и сэкономить время.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB