Начальный шаблон для box2D
Автор: Евгений Рыжков Дата публикации:
Данный шаблон — это своего рода введение по работе с 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