Статьи

HTML5: объединение физического движка (box2dWeb) с DeviceOrientation

Когда вышли первые смартфоны, все они имели традиционные лабиринтные приложения. Приложение, в котором вам нужно было перемещать мяч по определенному пути, наклоняя и перемещая телефон. Существует также спецификация HTML5, которая позволяет вам делать это прямо из браузера. Это позволило бы нам создавать все классные игры, которые запускаются прямо из браузера. В этой статье я покажу вам мои первые эксперименты с этим API в сочетании с физическим движком на основе JavaScript. Цель состоит в том, чтобы создать простое приложение HTML5, в котором вы можете перемещать несколько шариков, используя датчики движения на вашем устройстве. То, к чему мы стремимся, это:

Физика с использованием box2dweb

Вы можете проверить это здесь: « Box2dWeb and deviceorientation demo ».

Прежде чем я начну с объяснения, краткая заметка о совместимости устройств. Моей первоначальной идеей было написать это для моего планшета, чтобы немного поиграть с различными сенсорами, HTML5 apis и т. Д., Которые доступны. Проблема, однако, в том, что на данный момент библиотека box2dweb.js слишком тяжелая для разработки мобильных приложений. Я уже пробовал другие библиотеки физики javascript, но все они приводят к частоте кадров от 2 до 3 кадров в секунду. В настоящее время я изучаю разгрузку физического движка на серверный сервер (так же, как в примере с обнаружением лица ). Поэтому я протестировал и изменил этот пример для работы с датчиками из моего MacBook Pro.

Доступ к датчикам устройства

Доступ к датчикам устройства очень прост. В спецификации определяет , что вы должны зарегистрироваться для конкретного события, и вы получите обратный вызов в определенном интервале , как это:

    window.addEventListener("deviceorientation", function(event) {
          // process event.alpha, event.beta and event.gamma
      }, true);
</javscript>
 
The event you receive contains the following information:
 
<javascript>
     {alpha: 90,        // represents position on the z-axis
       beta: 0,          // represents position on the x-axis
       gamma: 0};    // represents position on the y-axis

Для моего macbook это приводит к следующему набору событий:

absolute: null
alpha: null
beta: 2.2814938370474303
bubbles: false
cancelBubble: false
cancelable: false
clipboardData: undefined
currentTarget: DOMWindow
defaultPrevented: false
eventPhase: 0
gamma: 1.3697507397371704
returnValue: true
srcElement: DOMWindow
target: DOMWindow
timeStamp: 1336114836578
type: "deviceorientation"

Как видите, помимо множества других сведений, мы получаем альфа, бета и гамму. Для моего MacBook я никогда не получаю альфа-значение. Для этой демонстрации я хочу перевернуть все шары от изображения влево, когда я наклоняю свой ноутбук влево, и они должны вращаться вправо, когда я наклоняю свой ноутбук вправо. То же самое касается и того, когда я наклоняю свой ноутбук назад, шары должны катиться вверх, а когда я наклоняю ноутбук вниз, шары должны катиться вниз.

Я использую следующий слушатель для этого:

// initialize the device orientation and set the callback
function initOrientation() {
    if (window.DeviceOrientationEvent) {
        console.log("DeviceOrientation is supported");
        window.addEventListener('deviceorientation', function (eventData) {
 
            var LR = eventData.gamma; // used as x gravity
            var FB = eventData.beta;  // used as y gravity
 
            var newXGravity = Math.round(LR / 2);
            var newYGravity = Math.round(FB / 2);
 
            if (newXGravity != world.m_gravity.x || newYGravity != world.m_gravity.y ) {
 
                // set new gravity
                world.m_gravity.x = newXGravity
                world.m_gravity.y = newYGravity
 
                // wakeup all the bodies when the gravity changes
                for (var body = world.m_bodyList; body; body = body.m_next) {
                    body.SetAwake(true);
                }
            }
        }, false);
    } else {
        alert("Not supported");
    }
}

В этом листинге я начинаю слушать событие и извлекаю новый X и новую гравитацию Y, основываясь на наклоне ноутбука. Когда наклон изменился, я установил новую гравитацию в физическом мире и разбудил все спящие тела (подробнее об этом см. Ниже). И это все, что вам нужно сделать.

Настройте физический движок

Далее давайте посмотрим на физический движок. Я использую box2dweb , которая является реализацией javascript движка javascript box2d . Я не буду вдаваться в подробности, но комментарии в коде должны объяснить, что происходит.

function initWorld() {
    var b2Vec2 = Box2D.Common.Math.b2Vec2
        , b2AABB = Box2D.Collision.b2AABB
        , 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
        , b2MouseJointDef = Box2D.Dynamics.Joints.b2MouseJointDef;
 
    // setup the world
    world = new b2World(
        new b2Vec2(0, 10)    //gravity
        , true               //allow sleep
    );
 
    // define the borders
    var fixDef = new b2FixtureDef;
    fixDef.density = 0.1;
    fixDef.friction = 0.3;
    fixDef.restitution = 0.2;
 
    var bodyDef = new b2BodyDef;
    //create enclosure
    bodyDef.type = b2Body.b2_staticBody;
    fixDef.shape = new b2PolygonShape;
    fixDef.shape.SetAsBox(width / 10, 2);
 
    // draw lower bound
    bodyDef.position.Set(0, height / scale);
    world.CreateBody(bodyDef).CreateFixture(fixDef);
 
    // draw upper bound
    bodyDef.position.Set(0, 0);
    world.CreateBody(bodyDef).CreateFixture(fixDef);
 
    // draw left bound
    fixDef.shape.SetAsBox(2, height);
    bodyDef.position.Set(0, 0);
    world.CreateBody(bodyDef).CreateFixture(fixDef);
 
    // draw right bound
    bodyDef.position.Set(width / scale, 0);
    world.CreateBody(bodyDef).CreateFixture(fixDef);
 
    //create 100 objects
    bodyDef.type = b2Body.b2_dynamicBody;
    for (var i = 0; i < 100; ++i) {
        fixDef.shape = new b2CircleShape(1);
        bodyDef.position.x = (Math.random() * width) / scale;
        bodyDef.position.y = (Math.random() * height) / scale;
        world.CreateBody(bodyDef).CreateFixture(fixDef);
    }
 
    //setup debug draw
    var debugDraw = new b2DebugDraw();
    debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
    debugDraw.SetDrawScale(10.0);
    debugDraw.SetFillAlpha(1);
    debugDraw.SetLineThickness(1.0);
    debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
    world.SetDebugDraw(debugDraw);
 
    // start drawing
    window.setInterval(update, 1000 / 100);
}
 
function update() {
    world.Step(1 / 60, 8, 3);
    world.DrawDebugData();
    world.ClearForces();
}

Завершение

Доступ к API ориентации устройства на самом деле довольно прост. Полезное использование информации — это совсем другая история. Это на самом деле очень плохо, хотя для мобильных устройств еще не создан мощный физический движок JavaScript. С другой стороны, с ростом скорости смартфонов и планшетов время может решить эту проблему.