Начальный шаблон для box2D
Дата публикации: 19.04.2012
Последнее обновление: 20.04.2012
Данный шаблон — это своего рода введение по работе с box2d.
Что качать
- библиотека box2web — порт на Javascrpt известной библиотеки box2d написанной на C.
В Сети несколько разновидностей данного порта. Данный выделяется своей регулярной обновляемостью и большей схожестью синтаксиса с оригиналом.
Быстрый старт
<style>
canvas {
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
}
body {
-webkit-transform: translateZ(0); // загадочное правило, которое разгоняет Safari
}
</style>
<script src="js/box2dweb-2.1.a.3.min.js"></script>
[...]
<canvas id="static" width="600" height="400"></canvas>
<canvas id="dynamic" width="600" height="400"></canvas>
window.onload = function()
{
/* предзагрузка текстур */
var images = [];
images.push(new Image());
images[0].src = "img/grass.jpg";
images.push(new Image());
images[1].src = "img/brick.jpg";
loadImages(images, start); //функция для подгрузки изображений
/* запускаем сцену после загрузки всех необходимых компонентов */
function start(){
var canvasStatic = document.getElementById("static"), // канва для сттических тел
ctxStatic = canvasStatic.getContext("2d"),
canvasDynamic = document.getElementById("dynamic"), // для динамических
ctxDynamic = canvasDynamic.getContext("2d"),
world,
canvasW = canvasStatic.offsetWidth,
canvasH = canvasStatic.offsetHeight,
arrStaticBodies = [], // массив статических объектов
arrDynamicBodies = []; // массив динамических объектов
/* подключаем необходимые модули для нашей сцены */
var b2Vec2 = Box2D.Common.Math.b2Vec2,
b2BodyDef = Box2D.Dynamics.b2BodyDef,
b2Body = Box2D.Dynamics.b2Body,
b2FixtureDef = Box2D.Dynamics.b2FixtureDef,
b2Fixture = Box2D.Dynamics.b2Fixture,
b2World = Box2D.Dynamics.b2World,
b2MassData = Box2D.Collision.Shapes.b2MassData,
b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,
b2CircleShape = Box2D.Collision.Shapes.b2CircleShape,
b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
/*
создание мира
задаем общие силы
*/
function createWorld()
{
var gravity = new b2Vec2(0, 10); /*
задаем гравитацию через вектор
по оси x = 0
по y = 10
*/
var doSleep = true; // указываем что "спящие" тела не учасвствуют в моделировании
world = new b2World(gravity, doSleep); // создаем новый мир
return world;
}
/* объекты сцены ---------------------------------------- */
/*
объект Ground
св-ва, форма и расположение земли
получает:
- world - мир, куда будет добавлена земля
- width/height - размеры в метрах
возвращает созданное тело
*/
var Ground = function(world, width, height)
{
this.bodyDef = new b2BodyDef(); // определение св-в тела: позиция, амортизация
this.fixDef = new b2FixtureDef; // определяем физические свойства объекта + фигура
this.fixDef.friction = 0.5; // трение
this.fixDef.restitution = 0.5; // восстановление
this.fixDef.shape = new b2PolygonShape;
/* с помощью userData задаем объекту свои параметры */
this.bodyDef.userData = new StylingStatic({texture: images[0], width: width, height: height});
this.fixDef.shape.SetAsBox(width/2 , height/2); // задаем длину и ширину (половины, т.к. относительно центра фигуры)
this.bodyDef.position.Set(width/2 , 3.9); // позиция центра объекта
var ground = world.CreateBody(this.bodyDef);
ground.CreateFixture(this.fixDef); // загружаем в мир созданный объект
return ground;
}
/*
объект Wall - стены
получает:
- world - мир, куда будет добавлена
- width/height - размеры в метрах
- posX/posY - позиция центра (в местрах)
возвращает созданное тело
*/
var Wall = function(world, width, height, posX, posY)
{
this.bodyDef = new b2BodyDef();
this.fixDef = new b2FixtureDef; // определяем физические свойства объекта + фигура
this.fixDef.friction = 0.5; // трение
this.fixDef.restitution = 0.5; // восстановление
this.fixDef.shape = new b2PolygonShape;
this.bodyDef.userData = new StylingStatic({texture: images[1], width: width, height: height});
this.fixDef.shape.SetAsBox(width/2 , height/2); // задаем длину и ширину (половины, т.к. относительно центра фигуры)
this.bodyDef.position.Set(posX , posY); // позиция центра объекта
var wall = world.CreateBody(this.bodyDef);
wall.CreateFixture(this.fixDef); // загружаем в мир созданный объект
return wall;
}
/*
объект Ball
св-ва, форма, положение, силы объекта шар
получает:
- world - мир куда добавлем тело
- posX/posY - начальные координаты
- R - радиус (в метрах)
возвращает созданное тело
*/
var Ball = function(world, posX, posY, R)
{
this.bodyDef = new b2BodyDef();
this.fixDef = new b2FixtureDef; // определяем физические свойства объекта + фигура
this.fixDef.density = 10; // плотность. на ее основании можно определить массу
this.bodyDef.type = b2Body.b2_dynamicBody; // динамическое тело, на него дейсвтуют законы сцены
this.fixDef.shape = new b2CircleShape(R); // форма - круг с радиусом 0.2м
this.bodyDef.position.x = posX; // начальные координаты
this.bodyDef.position.y = posY;
this.bodyDef.userData = new StylingBall({fillStyle: "red", strokeStyle: "green"});
var ball = world.CreateBody(this.bodyDef);
ball.CreateFixture(this.fixDef);
return ball;
}
/*
стилизирование объектов
для примера один для заливки текстурой, другой просто цветом
*/
var StylingStatic = function(option)
{
this.width = option.width;
this.height = option.height;
this.fillStyle = option.fillStyle;
this.strokeStyle = option.strokeStyle;
this.texture = option.texture;
return this;
}
var StylingBall = function(option)
{
this.fillStyle = option.fillStyle;
this.strokeStyle = option.strokeStyle;
return this;
}
/* функции отрисовки -------------------------------------------- */
/* функция отрисовки статических тел */
function staticDraw(arrBodies)
{
for (var i = arrBodies.length; i--;)
{
var body = arrBodies[i];
ctxStatic.save();
var bodyPos = body.m_xf.position; // св-во объекта, содержащее текущие координаты
// накладываем текстуру
var ptrn = ctxStatic.createPattern(body.m_userData.texture,"repeat");
ctxStatic.fillStyle = ptrn;
/*
учитываем, что позиция объекта - это его центр, а fillRect заливает относительно верхнего левого угла,
плюс масштаб
*/
ctxStatic.fillRect((bodyPos.x-body.m_userData.width/2)*scale, (bodyPos.y-body.m_userData.height/2)*scale, body.m_userData.width*scale, body.m_userData.height*scale);
ctxStatic.restore();
}
return;
}
/* функция отрисовки динамических тел */
function dynamicDraw(arrBodies)
{
for (var i = arrBodies.length; i--;)
{
var body = arrBodies[i];
ctxDynamic.save();
ctxDynamic.lineWidth = 2;
ctxDynamic.fillStyle = body.m_userData.fillStyle;
ctxDynamic.strokeStyle = body.m_userData.strokeStyle;
var bodyPos = body.m_xf.position; // св-во объекта, содержащее текущие координаты
ctxDynamic.beginPath();
ctxDynamic.arc(bodyPos.x*scale, bodyPos.y*scale, body.m_fixtureList.m_shape.m_radius*scale, 0, Math.PI*2, false);
ctxDynamic.closePath();
ctxDynamic.stroke();
ctxDynamic.fill();
ctxDynamic.restore();
}
return;
}
/* отрисовка объектов сцены ---------------------------------------- */
/* init scene -------------------------------------- */
var scale = 100; // масштаб 100px = 1м
createWorld(); // создаем мир
/* создаем и рисуем статику */
var ground = new Ground(world, 4, 0.1); // создаем землю
arrStaticBodies.push(ground);
var wall_1 = new Wall(world, 1, 1.5, 4.5, 3.2);
arrStaticBodies.push(wall_1);
var wall_2 = new Wall(world, .05, .5, 2, 3.6);
arrStaticBodies.push(wall_2);
staticDraw(arrStaticBodies);
/* создаем динамику */
ball_1 = new Ball(world,.02,.02,0.2); // создаем первый мяч
arrDynamicBodies.push(ball_1);
ball_1.ApplyImpulse(new b2Vec2(4,1), ball_1.GetWorldCenter()); // начальный импульс шару
/* для отладки физики анимации ----------------------------- */
var debugDraw = new b2DebugDraw();
debugDraw.SetSprite(ctxStatic);
debugDraw.SetDrawScale(scale);
debugDraw.SetFillAlpha(0.5);
debugDraw.SetLineThickness(1.0);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
world.SetDebugDraw(debugDraw);
/* / для отладки физики анимации ----------------------------- */
function update() {
world.Step(
1 / 60 // 60 кадров в секу - менять не желатально
, 10 // предельные значения обработки изменения скорости объектов
, 10 // и их положений. Большее число - большая точность, но худшая производительность
);
//world.DrawDebugData(); // это
// world.ClearForces(); // и это нужно раскоментировать для отладки физики
/* перерисовываем только динамику */
ctxDynamic.clearRect(0, 0, 600, 400);
dynamicDraw(arrDynamicBodies);
requestAnimFrame(update);
};
requestAnimFrame(update);
};
}
Материалы
- Проект box2d
- Перевод документации на русский
- Box2D & JavaScript tutorials by Seth Ladd
- Box2D JaveScript Tutorial
Показать комментарии
