Интеграция физического движка 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
Отправить комментарий