A play­ful ex­per­i­ment with se­ri­ous li­braries. Vir­gil Spruit shows you how to build a WebGL physics game run­ning on sock­ets

net magazine - - CONTENTS -

Vir­gil Spruit shows you how to build your own WebGL physics game

This project will be split up into dif­fer­ent parts. We will give a short in­tro­duc­tion to Heroku, show how to use Physijs with three.js, ex­plain how to han­dle socket events over Node.js and also how we go about han­dling the sent data.

1 Heroku

This project will be hosted on Heroku, which is a cloud plat­form to host your apps. It has a wide va­ri­ety of sup­ported lan­guages such as Ruby, Java, PHP and Python. We are go­ing to use Node.js.

Sign up for an ac­count and choose Node.js. For this project we can use the ba­sic server, which is free of charge. After regis­tra­tion you will come to your dash­board where you can cre­ate your app. This will cre­ate a sub­do­main at herokuapp.com. As a de­ploy­ment method, you can choose to ei­ther use the Heroku Com­mand Line In­ter­face (CLI) to de­ploy us­ing its git repos­i­tory, or have a con­nec­tion set up to GitHub or Drop­box. I’ve cho­sen to go with its CLI; this will re­quire an in­stall. But in re­turn you get a va­ri­ety of new help­ful tools, one of th­ese is live de­bug­ging through your ter­mi­nal.

For set­ting up your server I rec­om­mend fol­low­ing the steps as de­scribed here: https://de­v­cen­ter.heroku. com/ar­ti­cles/get­ting-started-with-nodejs.

To de­ploy you use de­fault git com­mands. Each one you use will trig­ger the build server and your app will be de­ployed to the Heroku server and then be view­able at your sub­do­main.

Once the code is de­ployed you can view your project at [your­pro­ject].herokuapp.com. To view the logs use the ‘heroku logs — tail’ com­mand in your ter­mi­nal. Some of the things be­ing shown is what is be­ing served to the client – it shows the socket con­nec­tions, and if you want to de­bug your code, you could also use the con­sole.log in or­der to out­put to the ter­mi­nal.

2 Build the physics scene

We will be us­ing the most pop­u­lar WebGL frame­work, three.js, to build a 3D scene con­tain­ing an ob­ject on which we’ll at­tach physics. The physics li­brary of choice is Physijs, a plug-in for three.js. As an ex­ten­sion to three.js, Physijs uses the same cod­ing con­ven­tion, mak­ing it eas­ier to use if you are al­ready fa­mil­iar with three.js. The first thing is the pool ta­ble. We are us­ing the Physijs Height­field­Mesh, be­cause this mesh will read the height from the PlaneGeom­e­try. So it will ba­si­cally wrap it­self around the three.js ob­ject. var tableGeom­e­try = new THREE. PlaneGeom­e­try(650, 500, 10, 10); var tableMa­te­rial = Physijs. cre­ateMa­te­rial( new THREE. MeshPhongMa­te­rial({ shini­ness: 1, color: 0xb00000, emis­sive: 0x111111, side: THREE. Dou­bleSide }), .8, // fric­tion .4 // resti­tu­tion ); ta­ble = new Physijs. Height­field­Mesh( tableGeom­e­try, tableMa­te­rial, 0); So Height­field­Mesh re­quires a geom­e­try but also a Physijs Ma­te­rial. We’re adding two new features to the three.js ma­te­rial. Those are the fric­tion and resti­tu­tion vari­ables. Fric­tion is the re­sis­tance the ob­ject makes, and resti­tu­tion refers to the ‘bounci­ness’. Th­ese two vari­ables will de­fine how real the physics will feel like in your scene. For the cre­ated pool balls we don’t want to make them too bouncy, so keep the num­ber low. Like three. js, Physijs also has a se­ries of ba­sic shapes to go around the orig­i­nal mesh. SphereMesh wrap­ping the SphereGeom­e­try will give the ball physics. When ini­tial­is­ing the scene, we call buildBall(8), which will trig­ger the fol­low­ing func­tion… var buildBall = func­tion(num­berBall) { var bal­lTex­ture = new THREE.Tex­ture(); var bal­lIn­dex = ball. length; Add the tex­ture:

Th­ese two vari­ables will de­fine how real the physics will feel like in your scene

bal­lTex­ture = THREE. ImageUtils. load­Tex­ture(‘ tex­tures/’ + num­berBall + ‘_Ball. jpg’, func­tion( im­age) { bal­lTex­ture. im­age = im­age; }); Cre­ate the physijs-en­abled ma­te­rial with some de­cent fric­tion and bounce prop­er­ties: var bal­lMa­te­rial = Physijs. cre­ateMa­te­rial( new THREE. MeshLam­bertMa­te­rial({ map: bal­lTex­ture, shini­ness: 10, color: 0xd­ddddd, emis­sive: 0x111111, side: THREE. Fron­tSide }), .6, // fric­tion .5 // resti­tu­tion );

Tex­ture map­ping:

bal­lMa­te­rial. map.wrapS = bal­lMa­te­rial. map.wrapT = THREE. Re­peatWrap­ping;

bal­lMa­te­rial. map. re­peat. set(1, 1); Cre­ate the physics-en­abled SphereMesh, and start it up in the air: ball[ bal­lIn­dex] = new Physijs. SphereMesh( new THREE. SphereGeom­e­try( 25, 25, 25), bal­lMa­te­rial, 100 ); // y off­set to the top of the can­vas ball[ bal­lIn­dex]. po­si­tion.y = 500; // shad­ows ball[ bal­lIn­dex]. re­ceiveShadow = true; ball[ bal­lIn­dex]. castShadow = true; // add the ball to your can­vas scene. add( ball[ bal­lIn­dex]); }; We are adding tex­ture from a .jpg file. Cre­ate the ma­te­rial and use that for the SphereMesh to cre­ate the ob­ject, which we will place ver­ti­cally to the top so it drops in to the screen.

3 Sock­ets con­nec­tion

For com­mu­ni­ca­tion be­tween the server and the client, we will be us­ing socket.io ( https://socket.io). This is one of the most re­li­able li­braries avail­able for Node.js. It’s built on top of the We­bSock­ets API.

Now physics is en­abled for the meshes we need user in­put to make the game in­ter­ac­tive. The in­put de­vice we’re us­ing is the mo­bile de­vice. The mo­bile browser is the con­troller that will pro­vide data from the ac­celerom­e­ter and gy­ro­scope ( www.htm­l5rocks.

com/en/tu­to­ri­als/de­vice/ori­en­ta­tion) to the desk­top where you will see the game.

First off, a con­nec­tion be­tween the mo­bile browser and the desk­top browser has to be made. Each time a browser con­nects with our Node.js app, we need to make a new con­nec­tion. A client side con­nec­tion is set up by us­ing the fol­low­ing: var socket = io. con­nect();

socket. emit(‘event name’, data);

socket. on(‘event name’, func­tion() {});

3.1 Set­ting up the desk­topgame

If we are on a desk­top we will send our sock­ets a de­vice emit telling our server the desk­top is the game us­ing the fol­low­ing line of code:

var socket = io. con­nect(); // when ini­tial wel­come mes­sage, re­ply with ‘game’ de­vice type socket. on(‘ wel­come’, func­tion(data) {

socket. emit(“de­vice”, { “type”: “game” }); });

The server will re­turn us a unique key/game code gen­er­ated by crypto ( https://nodejs.org/api/crypto.

html). This will be dis­played to the desk­top.

// gen­er­ate a code var gameCode = crypto. ran­domBytes( 3).toString(‘ hex’). sub­string( 0, 4).toLow­erCase(); // en­sure unique­ness while ( gameCode in sock­etCodes) {

gameCode = crypto. ran­domBytes( 3).toString(‘ hex’). sub­string( 0, 4).toLow­erCase(); } // store game code -> socket as­so­ci­a­tion sock­etCodes[ gameCode] = io. sock­ets. sock­ets[socket. id]; socket.gameCode = gameCode

Tell game client to ini­tialise and show the game code to the user…

socket. emit(“ini­tial­ize”, gameCode);

3.2 Con­nect con­troller to thegame

To con­nect the mo­bile de­vice to the game, we will use a form to sub­mit the game code from the desk­top screen. On the form sub­mit we will send the game code to the server for authen­ti­ca­tion.

socket. emit(“de­vice”, { “type”: “con­troller”, “gameCode”: gameCode });

The server will check if the game code is valid and will set up the con­nec­tion with the desk­top game.

if (de­vice.gameCode in sock­etCodes) { // save the game code for con­troller com­mands socket.gameCode = de­vice.gameCode // ini­tial­ize the con­troller socket. emit(“con­nected”, {}); // start the game sock­etCodes[de­vice.gameCode]. emit(“con­nected”, {}); }

Once the con­nec­tion is all set, we will then give the 8-ball a small push from the x and z with the fol­low­ing com­mand…

ball[0]. setLin­earVe­loc­ity(new THREE.Vec­tor3( 30, 0, 30));

4 Send­ing data

Now that the con­nec­tion is es­tab­lished we want to send the gyro and ac­celerom­e­ter vari­ables to the game. By us­ing the win­dow.on­de­vice­mo­tion and the

win­dow.on­de­vice­ori­en­ta­tion events, we have the data we need to em­u­late the same tilt move­ments of our phone to the pool ta­ble. I’ve cho­sen to use an in­ter­val of 100ms to emit those val­ues.

setIn­ter­val( func­tion() {

socket. emit(‘send gyro’, [ Math. round(rotY), Math. round(rotX), ay, ax]); }, in­ter­valTime);

On the client side we will re­solve the la­tency by tween­ing the in­com­ing val­ues from the server to the tilt of the pool ta­ble. For tween­ing we use TweenMax ( https://greensock.com/tweenmax).

// han­dle in­com­ing gyro data socket. on(‘new gyro’, func­tion(data) { var degY = data[1] < 0 ? Math. abs(data[1]) : - data[1]; TweenMax.to( ta­ble. ro­ta­tion, 0.3, { x: degToRad(degY - 90), y: degToRad(data[0]), ease: Lin­ear. easeNone, onUp­date: func­tion() {

ta­ble.__dirtyRo­ta­tion = true;

To con­nect the mo­bile de­vice to the game, we will sub­mit the game code from the desk­top

} }); });

5 Ex­tra events

To give it a bit more in­ter­ac­tiv­ity, I’ve added a cou­ple of ex­tra events for the user to play with. We’re go­ing to give the user the op­tion to add ex­tra balls next to the 8-ball by us­ing the num­bers on the key­board. An­other one is to bounce the ta­ble up­wards. For this you can hit the space­bar. But we’re also adding a tap event on the con­troller de­vice. This will send an event to the pool ta­ble, which will rise the ta­ble and send the balls up.


// cre­ate balls / slam ta­ble on space­bar doc­u­ment. ad­dEven­tLis­tener(‘ key­down’, func­tion(e) { if (e. keyCode == 49) { // key: 1

buildBall(1); } else if (e. keyCode == 50) { // key: 1

buildBall( 2); } else if (e. keyCode == 51) { // key: 1

buildBall( 3); } else if (e. keyCode == 32) { // key: space­bar


} });

The buildBall func­tion is the same func­tion we used to cre­ate the sphere 8-ball. We are just us­ing dif­fer­ent tex­tures that will wrap the sphere. For push­ing the ta­ble up, we give the ta­ble an up­ward mo­tion along the y axis with this code…

ta­ble. setLin­earVe­loc­ity(new THREE.Vec­tor3( 0, 500, 0));


When you have a con­cept for a game or any­thing else, it is en­tirely likely that there are li­braries out there that could make your life eas­ier. This is a demo that shows how this can work. We hope this will help spark some cre­ative ideas or help you with your cur­rent project. To see a live ex­am­ple of the game, see http://go8ball.herokuapp.com or go to https://github. com/vir­gils/demo-8ball

Stay real The key goal of our game is em­u­lat­ing the phys­i­cal move­ments to the screen

Bounce up Tap your screen or hit the space­bar to bounce the ta­ble up

Go stan­dard Stan­dard git com­mands will trig­ger a de­ploy­ment of your app

Free of­fer­ing Heroku is an easy to use and free to trial node.js web server

Vir­gil Spruit About the au­thor w: www. klash. nl t: @ vir­gilrocks job: Cre­ative De­vel­oper ar­eas of ex­per­tise: HTML, CSS, JavaScript

Top More balls equals more fun. Try hit­ting the space­bar or tap­ping the screen of your mo­bile

Above Add more balls and see how much your browser can han­dle

Newspapers in English

Newspapers from Australia

© PressReader. All rights reserved.