Introduction:This article walks you through how to create an arcade style virtual reality game using JavaScript and Mozilla's A-Frame library. The game works on Rift, Vive, and Cardboard, as well as any most mobile and PC devices.Play the Game!Step 1: Create your HTMLA-Frame Virtual Reality is built over the internet as web pages. For that reason the first step in the process is to create a basic HTML page.<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Breakout VR Tutorial</title>
<meta name="description" content="Breakout VR Tutorial">
</head>
<body>
</body>
</html>Step 2: Add the A-Frame LibrariesA-Frame is a JavaScript library called "aframe.js". This should be added through a <script> tag inside the <head> section of the HTML.We will also use a library called "aframe-text-component", which allows to add text to our VR scene.!-- Basic A-Frame library -->
<script src="https://aframe.io/releases/0.2.0/aframe.min.js"></script>
<!-- Needed to add Text -->
<script src="https://rawgit.com/ngokevin/aframe-text-component/master/dist/aframe-text-component.min.js"></script>Step 3: Set up Static Game ElementsMost of the elements in our game will be dynamic and change as part of the game. However some elements will not move or have very little interaction. We will add those inside the <body> tag of the HTML using special tags specific to the A-Frame library.The a-scene element has to be in the body of the HTML. All of the other A-Frame elements will be placed inside of it.<a-scene>
</a-scene> Mixins are a way of defining attributes for a group of objects without declaring the attributes on each of those objects.
<!-- Mixins. -->
<a-assets>
<a-mixin id="red" material="color: red"></a-mixin>
<a-mixin id="green" material="color: green"></a-mixin>
<a-mixin id="blue" material="color: blue; opacity: 0.5"></a-mixin>
<a-mixin id="url-red" material="color: #d63959"></a-mixin>
<a-mixin id="cube" geometry="primitive: box"></a-mixin>
</a-assets>To help the player see the game area we are going to place flat planes behind and below the game area.
<!-- set game background planes. -->
<a-plane rotation="-90 0 0" width="4" height="4" color="#a0a0a0"></a-plane>
<a-plane position="0 2 -2" rotation="0 0 0" width="4" height="4" color="#bfabce"></a-plane>We could set the scene background to a flat color. I think that it looks more interesting with a 360 degree image, so I added in an example image from Mozilla.
<!-- sky color. -->
<a-sky src="city.jpg"></a-sky>We need to specify where the camera is at. To do this we add an A-Frame camera tag. The game functionality is based on the player moving their view, so I also added a cursor with lets the player see where their view is centered.Note that wasd-controls is set to disabled. This prevents the player from moving the camera away from the game board.
<!-- Set camera starting position. -->
<a-entity position="0 0 3.8">
<a-camera look-controls id="myCamera" wasd-controls="enabled: false">
<a-cursor id="cursor" material="color: gray; opacity: 0.5">
</a-cursor>
</a-camera>
</a-entity>Adding lighting is not strictly required, but I added a couple of lights into the scene to make the game elements easier to see.
<!-- Set light position. -->
<a-light
type="directional"
color="#FFF"
intensity="0.1"
position="-1 1 2">
</a-light>
<a-light
type="ambient"
color="#FFF">
</a-light>Step 4. Add a Window.OnLoad WrapperWe want the HTML to load before running the JavaScript. This is necessary to prevent errors in loading the game elements. The JavaScript is inserted as a <script> tag in the <head> section of the page.<script>
//wait until the page loads to perform the following
window.onload = function ()
{
}
</script>Step 5: Add Dynamic elements through JavaScriptMany elements of the game are dynamic and require heavy interaction. It's possible to declare these in the HTML and then interact with them through JavaScript, but I found it easier to declare them directly through the JavaScript.This is entered inside the window.onload function we declared earlier.Since this is a virtual reality game, every game element will have X, Y, and Z coordinates which define where they are at in cartesian space.The game ball is the ball that will bounce around inside the game area. We are going to create through as an A-Frame sphere.//Create the game ball
var gameBall = document.createElement('a-sphere');
var gameBallX = 0;
var gameBallY = 1.25;
var gameBallZ = -1;
var gameBallVelocityX = 0.05;
var gameBallVelocityY = 0.1;
var gameBallRadius = 0.15;
gameBall.setAttribute('color', '#EF2D5E');
gameBall.setAttribute('radius', gameBallRadius);
console.log(gameBallX + ' ' + gameBallY + ' ' + gameBallZ);
gameBall.setAttribute('position', gameBallX + ' ' + gameBallY + ' ' + gameBallZ);
scene.appendChild(gameBall);The paddle is a bar that will move left and right in the game area. We are going to create it as a box.
//create the paddle
var gamePaddle = document.createElement('a-box');
var gamePaddleX = 0;
var gamePaddleY = 0.3;
var gamePaddleVelocityX = 0;
var gamePaddleZ = -1;
var gamePaddleWidth = 1;
var gamePaddleHeight = 0.2;
var gamePaddleDepth = 0.2;
var gamePaddleColor = '#42f4aa';
gamePaddle.setAttribute('width', gamePaddleWidth);
gamePaddle.setAttribute('height', gamePaddleHeight);
gamePaddle.setAttribute('depth', gamePaddleDepth);
gamePaddle.setAttribute('color', gamePaddleColor);
scene.appendChild(gamePaddle);
gamePaddle.setAttribute('position', gamePaddleX + ' ' + gamePaddleY + ' ' + gamePaddleZ);The blocks are boxes that will disappear when the game ball hits them. We will create these as A-Frame boxes.
//create the game blocks
//arrays to hold the blocks and their positions
var gameBlocks = []; //objects
var gameBlocksX = []; //block x positions
var gameBlocksY = []; //block y positions
var gameBlocksZ = []; //block z positions
var gameBlocksActive = []; //whether the block is active
var blockWidth = 0.8;
var blockHeight = 0.2;
var blockDepth = 0.2;
var blockColor = '#4CC3D9';
//declare the blocks and their attributes
for (i = 0; i < 12; i++)
{
gameBlocks[i] = document.createElement('a-box');
gameBlocks[i].setAttribute('width', blockWidth);
gameBlocks[i].setAttribute('height', blockHeight);
gameBlocks[i].setAttribute('depth', blockDepth);
gameBlocks[i].setAttribute('color', blockColor);
gameBlocksActive[i] = "1";
}
//set the position of the blocks
//Top row
gameBlocksX[0] = -1.5;
gameBlocksY[0] = 3.5;
gameBlocksZ[0] = -1;
gameBlocksX[1] = -0.5;
gameBlocksY[1] = 3.5;
gameBlocksZ[1] = -1;
gameBlocksX[2] = 0.5
gameBlocksY[2] = 3.5;
gameBlocksZ[2] = -1;
gameBlocksX[3] = 1.5;
gameBlocksY[3] = 3.5;
gameBlocksZ[3] = -1;
//Middle row
gameBlocksX[4] = -1.5;
gameBlocksY[4] = 3;
gameBlocksZ[4] = -1;
gameBlocksX[5] = -0.5;
gameBlocksY[5] = 3;
gameBlocksZ[5] = -1;
gameBlocksX[6] = 0.5
gameBlocksY[6] = 3;
gameBlocksZ[6] = -1;
gameBlocksX[7] = 1.5;
gameBlocksY[7] = 3;
gameBlocksZ[7] = -1;
//Bottom row
gameBlocksX[8] = -1.5;
gameBlocksY[8] = 2.5;
gameBlocksZ[8] = -1;
gameBlocksX[9] = -0.5;
gameBlocksY[9] = 2.5;
gameBlocksZ[9] = -1;
gameBlocksX[10] = 0.5
gameBlocksY[10] = 2.5;
gameBlocksZ[10] = -1;
gameBlocksX[11] = 1.5;
gameBlocksY[11] = 2.5;
gameBlocksZ[11] = -1;
//add the blocks to the scene
for (i = 0; i < 12; i++)
{
scene.appendChild(gameBlocks[i]);
gameBlocks[i].setAttribute('position', gameBlocksX[i] + ' ' + gameBlocksY[i] + ' ' + gameBlocksZ[i]);
}Step 6. Add Game VariablesIn order for our game to work, we have to keep track of certain types of information. These will be declared as JavaScript variables near the top of our <script> section.
//declare variables
var gameIsOn = 0; //whether the game is active, controls certain functionality
var intervalLength = 25; //determines the speed of the game
var topBorder = 3.5; //border of game area
var bottomBorder = 0.25; //border of game area
var rightBorder = 1.8; //border of game area
var leftBorder = -1.8; //border of game area
var scene = document.querySelector('a-scene'); //assign a name to the A-Frame sceneStep 7. Create Functions to Reset the Game ElementsWe will want to reset the game elements when the game starts. Let's add these functions into the JavaScript to reset the blocks and the location of the ball.
//function to reset the blocks
function resetBlocks()
{
for (i = 0; i < 12; i++)
{
gameBlocksActive[i] = "1";
gameBlocks[i].setAttribute('opacity', '1');
}
}
//function to reset the ball position
function resetBall()
{
gameBallX = 0;
gameBallY = 1.25;
gameBallZ = -1;
gameBallVelocityX = 0.05;
gameBallVelocityY = 0.1;
gameBall.setAttribute('position', gameBallX + ' ' + gameBallY + ' ' + gameBallZ);
}
//function to check if all blocks are broken, return true if so
function checkBlocks()
{
var returnValue = 1;
for (i = 0; i < 12; i++)
{
if(gameBlocksActive[i] == "1")
returnValue = 0;
}
return returnValue;
} Step 8. Adding TextHow fun would a game be if we didn't know what was happening. We are going to add some text into the game environment, so that the game can communicate with the player.The score will keep track of how many blocks the player breaks.
//Display the score
var scoreValue = 0;
var scoreText = document.createElement('a-entity');
scoreText.setAttribute('mixin', 'blue');
scene.appendChild(scoreText);
scoreText.setAttribute('text', 'text: Score: ' + scoreValue);
scoreText.setAttribute('position', '-3.5 3.8 -0.8');
scoreText.setAttribute('size', '0.75');The player will have a finite number of lives. Everytime the ball touches the bottom of the screen instead of the paddle, we will deduct a life.
//Display the player's lives
var livesValue = 3;
var livesText = document.createElement('a-entity');
livesText.setAttribute('mixin', 'blue');
scene.appendChild(livesText);
livesText.setAttribute('text', 'text: Lives: ' + livesValue);
livesText.setAttribute('position', '1.4 3.8 -0.8')