В Internet Explorer 11 добавлена поддержка некоторых интересных новых событий DOM: событий DeviceOrientation . Эти события предоставляют информацию о физической ориентации и движении текущего оборудования.
W3C опубликовал спецификацию для этих событий: http://www.w3.org/TR/orientation-event/
В этой статье я покажу вам, как использовать эти события в небольшой 3D-игре с мячом «Амига» .
Окончательный результат будет выглядеть это .
Хотите попробовать это? Просто зайдите туда (вы можете использовать ориентацию устройства или клавиши курсора).
События DeviceOrientation и Babylon.js
Прежде чем подробно рассмотреть спецификацию DeviceOrientation , вы можете посмотреть это видео, показывающее использование ориентации устройства в сцене babylon.js. И, как вы можете видеть, это скалы !
Как работают события DeviceOrientation
Существует два типа данных, предоставляемых событиями DeviceOrientation:
- Ориентация ( deviceorientation ) : это значение определяет ориентацию физического устройства относительно системы координат, центрированной на Земле. Это выражается в градусах. Три координаты предоставляются:
- альфа : вращение вокруг оси z
- бета : вращение вокруг оси х
- гамма : вращение вокруг оси y
Ось определяется с помощью правостороннего соглашения:
Чтобы понять эти значения, давайте начнем с устройства в ваших руках:
Альфа ориентация изменяется при перемещении устройства вокруг оси Z:
Бета ориентация изменяется при перемещении устройства вокруг оси х:
Наконец, гамма- ориентация изменяется при перемещении устройства вокруг оси y:
- Движение ( devicemotion ) : это значение определяет ускорение по каждой оси (x, y, z). Значения выражены в м / с² и могут включать (или не включать) влияние силы тяжести). Это событие также может обеспечить скорость вращения (в градусах / с) вокруг каждой оси.
Для получения более подробной информации, пожалуйста, ознакомьтесь с документацией MSDN .
Ориентация извлекается с помощью события « deviceorientation », запускаемого в объекте окна:
window.addEventListener("deviceorientation", moveBall); function moveBall(evt) { if (evt.alpha < 5 || evt.alpha > 355) { ball.position.z += 0.1; } }
Движение извлекается с использованием события « devicemotion », запускаемого в объекте окна:
window.addEventListener("devicemotion", detectShake); function detectShake(evt) { var accl = evt.acceleration; if (accl.x > 1.5 || accl.y > 1.5 || accl.z > 1.5) { // Tilt 🙂 onLose(); } }
Первое очевидное использование этих событий — управление игрой. Вы также можете использовать их для распознавания жестов или для определения ориентации пользователя для использования с картой соответственно.
Создание игры с мячом
Игра, которую мы создадим, представляет собой простую игру с мячом, в которой вы должны управлять мячом и заставлять его двигаться к определенным точкам, чтобы набирать очки:
Система частиц в верхнем правом углу определяет место, куда вы должны переместить шар. Как только мяч окажется рядом с хорошим местом, вы заработаете очко.
Каждый раз, когда вы зарабатываете очки, скорость мяча будет увеличиваться, и игровая площадка будет вращаться, чтобы увеличить сложность .
Итак, прежде всего вам нужно создать простой HTML-файл со ссылкой на babylon.js (невероятно!):
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Device orientation - ball game</title> <link href="index.css" rel="stylesheet" /> <script src="babylon.js"></script> </head> <body> <canvas id="renderCanvas"></canvas> <div id="score">Score: 0</div> <div id="speed">Speed: 1</div> <div id="gameOver" class="hidden"> <div id="gameOverText">Game Over</div> </div> <script src="index.js"></script> </body> </html>
Затем внутри index.js мы можем создать трехмерную среду, необходимую для нашей игры. Первое, что нужно сделать, это создать движок и сцену ;
var canvas = document.getElementById("renderCanvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; if (BABYLON.Engine.isSupported()) { var engine = new BABYLON.Engine(canvas, true); var scene = new BABYLON.Scene(engine); var light = new BABYLON.DirectionalLight("light", new BABYLON.Vector3(2, -10, 5), scene); var camera = new BABYLON.ArcRotateCamera("camera", 3 * Math.PI / 2.0, Math.PI / 4.0, 20.0, new BABYLON.Vector3(0, 0, 0), scene); scene.activeCamera = camera;
Вам также потребуется цикл рендеринга, чтобы убедиться, что кадры отрисованы на холсте
engine.runRenderLoop(function () { scene.render(); if (!started) { return; } });
На данный момент экран немного пуст:
Тогда мы можем создать звездное поле, чтобы получить крутой фон. Он будет создан как система частиц:
// Starfield var starfield = new BABYLON.ParticleSystem("particles", 4000, scene); starfield.particleTexture = new BABYLON.Texture("star.png", scene); starfield.minAngularSpeed = -4.5; starfield.maxAngularSpeed = 4.5; starfield.minSize = 0.5; starfield.maxSize = 1.0; starfield.minLifeTime = 0.5; starfield.maxLifeTime = 2.0; starfield.minEmitPower = 0.5; starfield.maxEmitPower = 1.0; starfield.emitRate = 600; starfield.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE; starfield.minEmitBox = new BABYLON.Vector3(-25, 0, -25); starfield.maxEmitBox = new BABYLON.Vector3(25, 0, 25); starfield.direction1 = new BABYLON.Vector3(0, 1, 0); starfield.direction2 = new BABYLON.Vector3(0, 1, 0); starfield.color1 = new BABYLON.Color4(0, 0, 0, 1); starfield.color2 = new BABYLON.Color4(1, 1, 1, 1); starfield.gravity = new BABYLON.Vector3(0, 5, 0); starfield.emitter = new BABYLON.Vector3(0, -2, 0); starfield.start();
Для получения дополнительной информации о системе частиц, вы можете перейти сюда .
Теперь это начинает хорошо выглядеть:
Затем мы должны создать шар (простую сферу), добавить материал и подготовить небольшую анимацию (используется, когда шар захватывает точку):
// Ball var ball = BABYLON.Mesh.CreateSphere("ball", 16, 1.0, scene, false); var ballMaterial = new BABYLON.StandardMaterial("ballMaterial", scene); ballMaterial.diffuseColor = new BABYLON.Color3(1, 0, 0); ballMaterial.diffuseTexture = new BABYLON.Texture("amiga.jpg", scene); ballMaterial.diffuseTexture.uScale = 3; ballMaterial.diffuseTexture.vScale = 4; ball.material = ballMaterial; ball.position = new BABYLON.Vector3(0, 0.5, 0); ball.renderingGroupId = 1; ball.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(0, 0, 0); var animationScale = new BABYLON.Animation("scale", "scaling", 30, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); animationScale.setKeys([{ frame: 0, value: new BABYLON.Vector3(1, 1, 1) }, { frame: 20, value: new BABYLON.Vector3(2.0, 2.0, 2.0) }, { frame: 40, value: new BABYLON.Vector3(1, 1, 1) }]); ball.animations.push(animationScale);
Обратите внимание на использование ball.renderingGroupId = 1, которое позволит мячу (и игровая площадка находиться на другом слое, чем звездное поле, чтобы избежать попадания звезд через игровую площадку).
Более подробную информацию о том, как создавать простые объекты с помощью babylon.js, вы можете найти здесь .
Более подробную информацию о материалах вы можете получить здесь .
Для получения дополнительной информации об анимации, вы можете перейти сюда .
Мяч является центром вселенной:
Детская площадка будет простой плоскостью, текстурированной с рисунком дерева:
// Playground var ground = BABYLON.Mesh.CreateGround("ground", 20, 20, 1, scene, false); var groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene); groundMaterial.specularColor = new BABYLON.Color3(0, 0, 0); groundMaterial.diffuseTexture = new BABYLON.Texture("wood.png", scene); groundMaterial.diffuseTexture.uScale = 2; groundMaterial.diffuseTexture.vScale = 2; ground.material = groundMaterial; ground.receiveShadows = true; ground.renderingGroupId = 1;
Игра почти готова:
Чтобы добавить более реалистичный эффект, давайте добавим несколько теней:
// Shadows var shadowCaster = new BABYLON.ShadowGenerator(1024, light); light.position = new BABYLON.Vector3(-4, 14, -12.5); shadowCaster.useVarianceShadowMap = true; shadowCaster.getShadowMap().renderList.push(ball);
Вы можете получить больше информации о тенях здесь .
И выглядит отлично:
Последнее, что нужно добавить, — это цель (то есть место, куда идти, чтобы получить одно очко). Мы также будем использовать систему частиц здесь:
// Target var target = new BABYLON.ParticleSystem("particles", 4000, scene); target.particleTexture = new BABYLON.Texture("star.png", scene); target.minAngularSpeed = -4.5; target.maxAngularSpeed = 4.5; target.minSize = 0.5; target.maxSize = 3.0; target.minLifeTime = 0.5; target.maxLifeTime = 2.0; target.minEmitPower = 0.5; target.maxEmitPower = 1.0; target.emitRate = 200; target.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE; target.minEmitBox = new BABYLON.Vector3(-1, 0, -1); target.maxEmitBox = new BABYLON.Vector3(1, 0, 1); target.direction1 = new BABYLON.Vector3(0, 1, 0); target.direction2 = new BABYLON.Vector3(0, 1, 0); target.color1 = new BABYLON.Color4(1, 1, 0, 1); target.color2 = new BABYLON.Color4(1, 1, 1, 1); target.gravity = new BABYLON.Vector3(0, 5, 0); target.emitter = new BABYLON.Vector3(8, 0, 8); target.renderingGroupId = 1; target.start();
Наша игра готова к игре:
Добавление событий DeviceOrientation в нашу игру
Использовать события DeviceOrientation довольно просто. Мяч будет контролироваться с помощью устройства вращения. Для этого вам понадобятся переменные для хранения значений текущего и предыдущего поворота:
var orientationGamma = 0; var orientationBeta = 0; var initialOrientationGamma = 0; var initialOrientationBeta = 0;
Используя эти переменные, вот код для обнаружения изменений вращения:
// Orientation window.addEventListener("deviceorientation", moveBall); function moveBall(evt) { if (!started) { return; } if (!initialOrientationGamma) { initialOrientationGamma = evt.gamma; initialOrientationBeta = evt.beta; } orientationGamma = evt.gamma; orientationBeta = evt.beta; } window.addEventListener("devicemotion", detectShake); function detectShake(evt) { var accl = evt.acceleration; if (accl.x > 1.5 || accl.y > 1.5 || accl.z > 1.5) { // Tilt 🙂 onLose(); } }
Вы можете заметить, что значения гаммы и бета используются здесь. Движение устройства используется для имитации «наклона», когда вы слишком быстро встряхиваете устройство.
Для простоты я не буду включать код для функций onLose (и onWin ), но вы можете найти их в исходном коде игры, доступном ниже.
Затем вы должны обновить renderLoop, чтобы использовать эти значения:
engine.runRenderLoop(function () { scene.render(); // Compute direction if (orientationGamma) { var z = (initialOrientationBeta - orientationBeta) * 0.05; var x = (initialOrientationGamma - orientationGamma) * -0.05; direction.addInPlace(new BABYLON.Vector3(0, 0, z * speed * scale)); direction.addInPlace(new BABYLON.Vector3(x * speed * scale, 0, 0)); } // Moving and rotating ball ball.position.addInPlace(direction); var rotationToApply = BABYLON.Quaternion.RotationYawPitchRoll(0, direction.z * 1.5, -direction.x * 1.5); ball.rotationQuaternion = rotationToApply.multiply(ball.rotationQuaternion); direction.scaleInPlace(0.95); // Collisions checkCollisions(); });
Гамма вращение контролирует направление к x и бета к z. Затем шар перемещается соответствующим образом и немного вращается в правильном направлении, чтобы имитировать вращение.
Функция checkCollisions просто проверяет, находится ли мяч внутри игровой площадки и не достигнута ли цель (чтобы затем вызвать функцию onWin ):
// Collisions var checkCollisions = function() { // Target met if (BABYLON.Vector3.Distance(ball.position, target.emitter) < 1.2) { onWin(); return; } var point = ball.position.clone(); point.y -= 0.5; if (!ground.intersectsPoint(point)) { onLose(); } };
И это все . Теперь у вас есть современная, красивая и управляемая игра!
Полная игра
Полная игра также поддерживает клавиши курсора. Вы можете найти код здесь . Не стесняйтесь использовать его в качестве основы для собственных приложений!
Идти дальше
Если вы хотите пойти дальше, вот несколько указателей:
- События ориентации устройства в MSDN: http://msdn.microsoft.com/en-us/library/ie/dn433240(v=vs.85).aspx
- Спецификация W3C: http://www.w3.org/TR/orientation-event/
- Babylon.js: www.babylonjs.com