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