В этой статье описывается библиотека Box2D для C++, которая используется для моделирования физики в реальном времени в 2D играх.
Содержание
Физика 2d с помощью библиотеки Box2d
Box2d – это библиотека, написанная на C++, которая позволяет создавать очень реалистичные симуляции двухмерного мира.
Его преимущества – скорость и тот факт, что его можно использовать без каких-либо (выдающихся) навыков физики 😛
Он также имеет порты для других языков (включая Java, JavaScript и Flash).
С помощью Box2d было написано множество игр, включая очень популярную Angry Birds! (Когда вы немного узнаете о боксе, вы поймете, что они вовсе не так уж усердно над ним работали. Все благодаря Box2d!).
Библиотеку можно скачать отсюда: https://code.google.com/p/box2d/downloads/detail?name=Box2D_v2.3.0.7z&can=2&q=
Более новые версии библиотеки могут быть размещены на других серверах.
Несколько базовых определений
- Жесткое тело – тело, которое не может изменить свою форму. Все тела, моделируемые Box2d, являются жесткими телами.
- ограничение (сустава) – действие, которое ограничивает движение тела в той или иной степени
- Статическое тело – тело, не имеющее массы (или имеющее бесконечную массу). На него не действуют никакие силы (включая гравитацию). Он сталкивается с динамическими телами. Он не может самостоятельно изменить свое положение.
- Кинематическое тело – тело, не имеющее массы (или имеющее бесконечную массу). На него не действуют никакие силы (включая гравитацию). Он сталкивается с динамическими телами. Когда ему придается скорость, он не меняет своей скорости.
- Динамическое тело – “нормальное” тело. Оно имеет массу, на него действуют все силы, оно сталкивается со всеми другими телами
Ваша первая симуляция!
Простейший пример симуляции Box2d.
Программа имитирует падение блока на платформу, висящую в воздухе.
Обсуждайте в комментариях.
#include <Box2d/Box2d.h> // прикрепляем заголовок
// не забывайте о правильных либах!
int main()
{
b2World world( b2Vec2( 0.0f, - 10.0f ) ); // создадим мир с гравитацией 10, направленной вниз.
////
// теперь мы создадим "землю" как статичное тело - она будет "висеть" на месте
b2BodyDef groundDef; // тела по умолчанию статичны
groundDef.position.Set( 0.0f, - 10.0f ); // регулировка положения тела
b2Body * ground = world.CreateBody( & groundDef ); // здесь мы создаем тело. Ему еще не присвоена форма.
b2PolygonShape groundShape; // и поэтому мы делаем его
groundShape.SetAsBox( 100.0f / 2, 20.0f / 2 ); // и задается в виде прямоугольника со сторонами 100 и 20
ground->CreateFixture( & groundShape, 1.0f ); // ...а затем подключаем его к телу. Второй параметр - плотность.
////
// мы создаем падающий "блок" как динамическое тело - он сможет нормально двигаться и падать
b2BodyDef boxDef;
boxDef.type = b2_dynamicBody; // нам нужно сообщить Box2d, что тело должно быть динамическим
boxDef.position.Set( 0.0f, 4.0f ); // как и прежде
b2Body * box = world.CreateBody( & boxDef ); // любой
b2PolygonShape boxShape;
boxShape.SetAsBox( 2.0f / 2, 2.0f / 2 ); // как и раньше
// Далее мы создадим форму для блока
// мы хотим установить дополнительные параметры, такие как трение, поэтому нам нужно использовать более длинный метод, чем раньше
b2FixtureDef boxFixDef; // создаем определение фикции (фрагмента тела)
boxFixDef.shape = & boxShape; // задаем форму...
boxFixDef.density = 1.0f; // ... плотность...
boxFixDef.friction = 0.3f; // ... и трение
box->CreateFixture( & boxFixDef ); // создаем фикцию.
// Отлично, у нас готовы все элементы нашей симуляции!
////
float time = 1.0f; // наш мир на секунду смоделирует
int steps = 100.0f; // разделим симуляцию на 100 шагов
float timeStep = time / steps; // поэтому мы будем обновлять физику каждые 1/100 секунды..
// Эти два значения влияют на точность моделирования. Чем больше число, тем точнее будет физика, но тем медленнее
int velocityIt = 8, positionIt = 3; // Автор Box2d рекомендует значения 8 и 3, поэтому мы не будем их менять
// Ну, вот и все.!
for( int i = 0; i < steps; i++ )
{
world.Step( timeStep, velocityIt, positionIt ); // вот волшебная линия. Вот симуляция нашего мира
// мы используем уже рассчитанные значения
b2Vec2 pos = box->GetPosition(); // получаем положение блока
printf( " Шаг %i : %4.2f, %4.2f", i, pos.x, pos.y ); // и распечатываем его
}
// и все. Класс b2World сам позаботится об удалении наших творений:)
}
Code language: PHP (php)
Результат должен быть примерно таким:
Шаг 0 : 0.00, 4.00
Шаг 1 : 0.00, 3.99
Шаг 2 : 0.00, 3.98
...
Шаг 97 : 0.00, 1.25
Шаг 98 : 0.00, 1.13
Шаг 99 : 0.00, 1.01
Code language: CSS (css)
Только эта строка требует обсуждения:
groundShape.SetAsBox( 100.0f / 2, 20.0f / 2 ); // и задается в виде прямоугольника со сторонами 100 и 20
Code language: JavaScript (javascript)
Ну, метод SetAsBox() берет половину длины сторон прямоугольника. Об этом следует помнить.
Как работает Box2d?
Box2d-симуляция представлена миром – класс b2World.
К каждому миру можно добавить тела – класс b2Body (и привязки, но об этом подробнее позже).
Каждое тело состоит из так называемых фикстур – класс b2Fixture
Фигуры – это разные части одного тела. Им можно приписать трение, плотность и сопротивление.
Кроме того, каждый рисунок имеет свою собственную форму.
Фигуры в одном теле не могут перемещаться относительно друг друга.
Это означает, что фикции, прикрепленные к одному телу, движутся вместе.
Все классы Box2d имеют суффикс b2.
Box2d основан на концепции так называемой фабрики.
Это означает, что схема создания ребенка будет выглядеть следующим образом:
Owner wl; // будущий владелец объекта cos
classDef cosDef; // класс, содержащий все параметры, необходимые для создания класса Class
// заполнение полей cosDef
Class * cos = wl.addClass( cosDef ); // и здесь владелец выделяет и создает новый объект Class, используя значение из cosDef
//...
wl.destroyKlasa( cos ); // после этого владелец уничтожает и разбирается с этим объектом
Code language: JavaScript (javascript)
Симуляция Box2d не является “непрерывной”, а аппроксимируется в дискретные моменты времени с помощью функции b2World::Step().
Обновляет симуляцию на заданное время (приращение времени с момента предыдущего вызова)
Итак, общий план программы, использующей Box2d, выглядит следующим образом:
b2World world( /*...*/ );
// добавление тел, фикций и связей
// инициализация других ресурсов программы
while( /*...*/ )
// основной цикл
{
float deltaTime = /*...*/; // приращение времени (в секундах)
world.Step( deltaTime, /*...*/ );
// Остальная часть логики программы/игры, рендеринг, обработка событий и т.д.
}
Code language: JavaScript (javascript)