Интеграция физического движка Box2DJS с рендерерами совсем не сложна. Для примера можно взять популярный pixi.js.
Для начала создадим мир Box2d
// определяем ограничительный прямоугольник мира
var worldAABB = new b2AABB();
worldAABB.minVertex.Set(-1000, -1000);
worldAABB.maxVertex.Set(1000, 1000);
// определяем гравитацию
var gravity = new b2Vec2(0, 300);
// разрешаем телам быть в покое
var doSleep = true;
// создаем мир
var world = new b2World(worldAABB, gravity, doSleep);
// определяем время 1 шага эмуляции
var timeStep = 1 / 60;
// количество итераций для рассчетов эмуляции
var iteration = 1;
Затем, выполняем стандартный код для pixi.js из примеров, немного его расширив и модифицировав.
// создаем экземпляр сцены pixi
var stage = new PIXI.Stage(0x004466);
// создаем экземпляр рендерера (я определил 2d, но можно выставить WebGL или автомат)
var renderer = new PIXI.CanvasRenderer(400, 300);
// добавляем рендерер в DOM
document.body.appendChild(renderer.view);
requestAnimFrame(animate);
// создаем спрайты pixi
// создаем текстуру стен из файла
var bricksTexture = PIXI.Texture.fromImage("bricks.png");
// создаем спрайты стен
var leftWall = new PIXI.Sprite(bricksTexture);
var rightWall = new PIXI.Sprite(bricksTexture);
// определяем точки привязки стен
leftWall.anchor.x = 0.5;
leftWall.anchor.y = 0.5;
rightWall.anchor.x = 0.5;
rightWall.anchor.y = 0.5;
stage.addChild(leftWall);
stage.addChild(rightWall);
// создаем текстуру земли из файла
var grassTexture = PIXI.Texture.fromImage("grass.png");
// создаем спрайт земли
var ground = new PIXI.Sprite(grassTexture);
// определяем точку привязки земли
ground.anchor.x = 0.5;
ground.anchor.y = 0.5;
stage.addChild(ground);
// создаем текстуру кролика из файла
var bunnyTexture = PIXI.Texture.fromImage("bunny.png");
// создаем спрайт кролика
var bunny = new PIXI.Sprite(bunnyTexture);
// определяем точку привязки кролика
bunny.anchor.x = 0.5;
bunny.anchor.y = 0.5;
stage.addChild(bunny);
Затем, для большего удобства, определим функцию добавления тела в мир Box2d
function addBody(sprite, x, y, width, height, density) {
// определение формы тела
var shapeDef = new b2BoxDef();
// размеры (из-за особенностей реализации Box2d, ополовиниваем размеры)
shapeDef.extents.Set(width * 0.5, height * 0.5);
// определение тела
var bodyDef = new b2BodyDef();
bodyDef.AddShape(shapeDef);
bodyDef.position.Set(x, y);
// если тело не статическое (имеет плотность)
if (density) {
shapeDef.density = density;
// трение
shapeDef.friction = 0.4;
// упругость
shapeDef.restitution = 1.2;
// немного повернем
bodyDef.rotation = 0.8;
}
body = world.CreateBody(bodyDef);
// приколотим спрайт к телу
body.m_userData = sprite;
}
Теперь можно очень резво добавить 4 тела сразу.
addBody(ground, 200, 292, 400, 16);
addBody(leftWall, 5, 150, 10, 300);
addBody(rightWall, 395, 150, 10, 300);
addBody(bunny, 200, 150, 25, 37, 0.5);
Для рисования тел мира Box2d на холсте определим специальную функцию.
function draw() {
var body, sprite;
for (body = world.m_bodyList; body; body = body.m_next) {
// выбираем спрайт из тела
sprite = body.GetUserData();
if (sprite) {
sprite.position = body.GetCenterPosition();
sprite.rotation = body.GetRotation();
}
}
}
Эта функция очень прямолинейна. Вроде и объяснять здесь нечего.
Наконец, рисуем всё наше творчество на холсте раз в 17 мс примерно.
function animate() {
requestAnimFrame(animate);
// вычисляем шаг эмуляции Box2d
world.Step(timeStep, iteration);
// рисуем спрайты pixi, руководствуясь новыми параметрами мира Box2d
draw();
// рисуем сцену pixi
renderer.render(stage);
}
На этапе разработки сцены может понадобиться отладочная отрисовка Box2d. Для этого после определения var renderer следует назначить контекст рисования:
world.SetDebugDraw({
ctx : renderer.view.getContext('2d'),
width : 400,
height : 300
});
А в функции animate убрать вызовы draw() и renderer.render(stage) добавив при этом:
world.DebugDraw();
Данный пример совсем тривиален. Стоит, конечно же, обернуть логические куски кода в удобные структуры. Но это каждый уже решает для себя сам.
2 комментария:
for (body = world.m_bodyList; body; body = body.m_next) {...}
Что-то туплю, как ьакой цикл на CoffeeScript написать?
Можно что-то типа:
body = world.m_bodyList
while body
# do staff
body = body.m_next
Отправить комментарий