15 февр. 2011 г.

Box2D Engine

Физика на Flash. Box2D Engine

Быстрый, удобный и мощный физический движок с открытым исходным кодом. Под катом — ссылки, небольшой туториал и пример использования.


Ссылки

Сам проект Box2D находится по этому адресу — http://www.box2d.org/, там можно почитать о его возможностях, пообщаться на форуме и т.д.
С него был сделан AS3 порт, домашняя страница — http://box2dflash.sourceforge.net/. На ней выложен клип, показывающий возможности этого движка.

Использование (самое базовое)

1. Создаём «мир», все расчёты происходят только в пределах этого мира, объект, выходящий за его границы, выпадает из расчётов. Так что делаем с запасом (WIDTH и HEIGHT — размеры окна):

// world bounding box
var worldAABB : b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-WIDTH, -HEIGHT);
worldAABB.upperBound.Set(2*WIDTH, 2*HEIGHT);

// create world. zero gravity + use "sleeping" for objects
m_world = new b2World(worldAABB, b2Vec2.Make(0, 0), true);

2. Добавляем объект в мир.
Объект характеризуется двумя составляющими.
Первая — геометрическое представление объекта (его «поверхность»). Каждый объект может состоять из нескольких shape, которые представляют собой выпуклые многоугольники или окружности (но ничего не мешает расширить базовый shape и написать свой собственный).
Здесь же задаётся плотность, сила трения и т.д.

// shape definition
var bodyShapeDef : b2PolygonDef = new b2PolygonDef();
// as rectangle
bodyShapeDef.SetAsBox(w/2, h/2);
// density
bodyShapeDef.density = 1.0;
// friction
bodyShapeDef.friction = 0.3;

Вторая — сам объект, его положение, масса, момент инерции и т.д.
Описание объекта:

// object definition
var bodyDef : b2BodyDef = new b2BodyDef();
// world position
bodyDef.position.Set(xc, yc);
// linear "friction with world"
bodyDef.linearDamping = 0.3;
// angular "friction with world"
bodyDef.angularDamping = 0.3;

Создание объекта (он автоматически регистрируется в мире). Задание ему ранее созданного геометрического представления, и (очень удобно) автоматический расчёт всех физических параметров на основе его плотности и формы.

// create object from definition
var body : b2Body = m_world.CreateBody(bodyDef);
// create object shape from shape definition
body.CreateShape(bodyShapeDef);
// calculate mass, center of mass and inertia
// based on shape
body.SetMassFromShapes();

Есть ещё третья (необязательная) составляющая объекта — его представление на экране. На начальных этапах разработки можно воспользоваться классом b2DebugDraw, который показывает все объекты, связи между ними и т.д. Но как связать, к примеру собственный MovieClip и физический объект?
Самая часто используемая практика — воспользоваться полем userData созданного объекта.
Запоминаем экранное представление в этом поле:

// save screen object in userData field
body.SetUserData(bodyDisplayObject);

3. Эмуляция
Тут всё просто. У мира есть функция Step, которая принимает время шага в миллисекундах секундах и кол-во итераций, которые надо проделать на этом шаге. После эмуляции проходим по всем объектам мира, смотрим, если поле userData содержит экранное представление — то обновляем положение/вращение этого представления в соответствии с полями физического объекта.

// calculate physics
// using 10 steps of physics for each frame
m_world.Step(dt, 10);

// loop for all physic objects
for(var body : b2Body = m_world.GetBodyList(); body; body = body.GetNext())
{
// if userData is not a shape, then skip this object
if(!(body.GetUserData() is Shape))
continue;

// update screen object to be equal physical object
body.GetUserData().x = body.GetPosition().x;
body.GetUserData().y = body.GetPosition().y;
body.GetUserData().rotation = body.GetAngle() * 180.0 / Math.PI;
}
____________________

Пример можно увидеть здесь: http://www.rexxar.ru/snake/

5 комментариев: