43
HTML5 Gaming Erik Oros ([email protected] | @WaterlooErik) November 15, 2012

HTML5 Gaming - BlackBerry · HTML5 Gaming Erik Oros ([email protected] | @WaterlooErik) November 15, 2012 . BlackBerry Loves HTML5 2 . Canvas2D 3 . What is Canvas2D? A surface for programmatic

  • Upload
    others

  • View
    9

  • Download
    0

Embed Size (px)

Citation preview

HTML5 Gaming

Erik Oros ([email protected] | @WaterlooErik)

November 15, 2012

BlackBerry Loves HTML5

2

Canvas2D

3

What is Canvas2D?

A surface for programmatic rendering of shapes/images.

Unlike SVG, no scene graph.

<canvas id=“canvas2D” width=“640” height=“480”>

HTML5 canvas is not supported.

</canvas>

var canvas = document.querySelector(‘#canvas2d’);

var context = canvas.getContext(‘2d’);

4

Canvas 2D Functionality

Rects, Paths, Images, Text, Transforms, Shadows, Line Caps and Joins, Colors and Styles, Animations, Clipping

All images attributed to Mozilla Contributors from https://developer.mozilla.org/en-US/docs/Canvas_tutorial and used under the Creative Commons Attribution-Sharealike license. 5

Basic Example

function drawPath(context) {

context.beginPath();

context.moveTo(3, 0);

context.lineTo(10, 0);

context.quadraticCurveTo(30, 0, 20, 13);

context.quadraticCurveTo(0, 14, 0, 13);

context.closePath();

context.fillStyle = "#c0c0c0";

context.fill();

}

6

Basic Example

function init() {

var elem = document.getElementById('myCanvas');

var canvasContext = elem.getContext('2d');

canvasContext.fillRect(0, 0, 125, 95);

var transX = [ 0.15, 0, 1.15, 1, 0.85, 2, 1.85 ];

var transY = [ 0.0, 0.7, 0, 0.7, 1.4, 0.5, 1.2 ];

canvasContext.translate(20,20);

for(var i=0; i<7; i++) {

canvasContext.save();

canvasContext.translate(30*transX[i], 30*transY[i]);

drawPath(canvasContext);

canvasContext.restore();

}

} 7

Hardware Acceleration

BlackBerry PlayBook 2.0

Hardware acceleration through GPU.

Paths are tessellated and passed to

OpenGL ES 2.0.

BlackBerry PlayBook 2.1

Updated graphics drivers for

increased performance.

BlackBerry 10

Hardware and software improvements will continue the trend.

8

KineticJS

Interact with rendered objects.

http://www.kineticjs.com

FabricJS

Interactive object model on top of canvas.

http://fabricjs.com

Cocos2d-HTML5

http://www.cocos2d-x.org/

CakeJS

JavaScript scene graph library.

http://code.google.com/p/cakejs/

ImpactJS

http://impactjs.com

Box2D

Physic engine.

http://box2d.org

Canvas2D Frameworks

9

Cocos2d-HTML5 Example

Custom ControlsOverlay.js created.

Joysticks and buttons.

Sprite art by Clint Bellanger

http://www.OpenGameArt.org

Tile art by Daniel Cook

http://www.LostGarden.com

Work In Progress

Documentation.

Open source.

10

WebGL

What is WebGL?

OpenGL ES 2.0 in your web browser.

Khronos open standard.

Hardware accelerated graphics for the web.

It’s fully integrated.

It is not a plug-in.

Standards compliant browsers.

Chrome

Firefox

Safari

Opera

What about mobile?

BlackBerry PlayBook.

BlackBerry 10.

http://caniuse.com/webgl

TunnelTilt is WebGL

First WebGL demo on PlayBook 2.0

Available on BlackBerry App World

Open-sourced on www.github.com/blackberry

Key Features: Accelerometer and Collision Detection

Photojam for Facebook is WebGL

Instant Filters and Effects via WebGL.

Connects directly with Facebook.

Special thanks to James Gibbons.

14

WebGL Frameworks

IvanK Lib

2D with WebGL; simplicity and performance.

http://lib.ivank.net/

J3D by Bartek Drozdz (Open source, MIT)

Leverage Unity3D scenes in your WebGL applications.

https://github.com/drojdjou/J3D

Inka3D (Closed source)

Leverage Maya scenes in your WebGL applications.

http://www.inka3d.com

CubicVR.js by Charles Cliffe (Open source, MIT)

Full-fledged WebGL framework, JSON/Collada imports, physics.

https://github.com/cjcliffe/CubicVR.js

Three.js is WebGL

Created by Ricardo Cabello as a 3D JavaScript library.

One of the most popular WebGL frameworks in use.

Large community involvement.

Under active development.

Distributed under MIT license.

https://github.com/mrdoob/three.js

Images from: http://mrdoob.github.com/three.js/ 16

Pure WebGL vs. Three.js

Exercise: Drawing a square in 6 steps.

17

Pure WebGL Three.js

Create a Canvas. Import Three.js.

Get a WebGL context. Setup scene.

Setup a GLSL program. Setup camera.

Setup geometry. Add geometry with material.

Setup shaders.

Render. Render

18

Step 1 of 6

Pure WebGL (Lines: 1) Create canvas.

<canvas id=“myCanvas” width=“1024” height=“512”></canvas>

Three.js (Lines: 1) Import Three.js.

<script src=“js/Three.js”></script>

19

Step 2 of 6

Pure WebGL (Lines: 3) Get WebGL context.

var canvas = document.querySelector(“#myCanvas”); var gl = canvas.getContext(“experimental-webgl”);

Three.js (Lines: 2) Setup scene.

scene = new THREE.Scene();

20

Step 3 of 6

Pure WebGL (Lines: 8) Setup GLSL program.

var vertexShader = createShaderFromScriptElement(gl, “2d-vertex-shader”); var fragmentShader = createShaderFromScriptElement(gl, “2d-fragment-shader”); var program = createProgram(gl, [vertexShader, fragmentShader]); gl.useProgram(program); var positionLocation = gl.getAttribLocation(program, “a_position”);

Three.js (Lines: 5) Setup camera.

camera = new THREE.PerspectiveCamera(FOV, ASPECT_RATIO, NEAR_PLANE, FAR_PLANE); camera.position.z = 1000.0; scene.add(camera);

21

Step 4 of 6

Pure WebGL (Lines: 13) Buffer geometry.

var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(

[-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0] ), gl.STATIC_DRAW);

gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

Three.js (Lines: 9) Add geometry with material.

geometry = new THREE.CubeGeometry(1024, 600, 0); material = new THREE.MeshBasicMaterial({color: 0x00FF00, wireframe: false}); mesh = new THREE.Mesh(geometry, material); scene.add(mesh);

22

Step 5 of 6

Pure WebGL (Lines: 24) Setup shaders.

<script id=“2d-vertex-shader” type=“x-shader/x-vertex”> attribute vec2 a_position; void main() {

gl_Position = vec4(a_position, 0.0, 1.0); }

</script> <script id=“2d-fragment-shader” type=“x-shader/x-fragment”>

void main() { gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); // Green.

} </script>

23

Step 6 of 6

Pure WebGL (Lines: 25) Render.

gl.drawArrays(gl.TRIANGLES, 0, 6);

Three.js (Lines: 13) Render.

renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); renderer.render(scene, camera);

Result:

Peaks and Valleys

WebGL, Virtual Controls, Audio…

What Is Peaks and Valleys?

HTML5 gaming sample.

Combines a number of concepts:

Endless terrain based on heightmap.

Skybox texturing.

Ambient and directional lighting.

Pixel blending.

Joystick and button controls.

www.github.com/blackberry/WebGL-Samples

Original (Fixed 150 x 150)

Generate a square.

Raise all included vertices.

Repeat.

Average with neighbours.

Current (Dynamic 1024 x 1024)

Image as height map.

Web Workers progressively loading.

Heightmap from: http://en.wikipedia.org/wiki/Heightmap

Generating the Landscape

26

_this = this;

this.worker = new Worker('./js/GLTerrainWorker.js');

this.worker.addEventListener('message', function (e) {

var params = e.data;

if (params.cmd === 'update') {

gl.bindBuffer(gl.ARRAY_BUFFER, _this.vBuffer);

gl.bufferData(gl.ARRAY_BUFFER, params.vertices, gl.DYNAMIC_DRAW);

_this.vBuffer.itemSize = 3;

_this.vBuffer.numItems = params.vertices.length / _this.vBuffer.itemSize;

/* Repeat for normal and index buffers. */

}

this.working = false;

}, false);

this.worker.working = true;

this.worker.postMessage({

'cmd': 'init',

'width': assets.json.terrain.width,

'height': assets.json.terrain.height,

'tileSize': assets.json.terrain.tileSize,

'vertices': assets.json.terrain.vertices,

'normals': assets.json.terrain.normals,

'offset': 60.0

});

Web Workers: GLTerrain.js

27

GLTerrain.prototype.update = function (px, pz) {

/* Only request an update if we're not already working. */

if (this.worker.working === false) {

this.worker.working = true;

this.worker.postMessage({

'cmd': 'update',

'px': -px,

'pz': -pz

});

}

};

/* Initialize event listener for messages. */

self.addEventListener('message', function (e) {

var params = e.data;

if (params.cmd === 'update') {

self.update(params);

} else if (params.cmd === 'init') {

self.init(params);

}

}, false);

self.update = function (params) {

/* ~70 lines and ~14400 executions:

* Calculate new vertex, normal, and index arrays.

*/

setTimeout(function () {

self.postMessage({

'cmd': 'update',

'message': 'complete',

'vertices': new Float32Array(vertices),

'normals': new Float32Array(normals),

'indices': new Uint16Array(indices)

});

}, 3000);

};

Web Workers: GLTerrainWorker.js

28

Generating the Skybox

Two easy steps:

Paint the inside of a box.

Place box on head/camera.

The magic happens with:

gl.disable(gl.DEPTH_TEST);

Don’t forget to turn this back on.

TODO

360° Skybox With Cloud Movement 29

Lighting

float weighting = max(dot(aVertexNormal, vec3(0.0, -1.0, 1.0)), 0.0);

vWeighting = vec3(0.2, 0.2, 0.2) + vec3(0.6, 0.6, 0.6) * weighting;

Calculate the dot product between the vertex normal and the direction of the light source.

Set a minimum (ambient) light and add the directional component.

vLightWeighting gets passed to the fragment shader.

30

Blending Colours and Textures

Fragment shader blends colours and textures.

vec4 diffuseSand = vec4(0.8, 1.0, 0.0, 1.0);

vec4 diffuseGrass = texture2D(texture1, vec2(vTextureCoord.s, vTextureCoord.t));

vec4 diffuseRock = vec4(0.5, 0.5, 0.5, 1.0);

vec4 diffuseSnow = vec4(1.0, 1.0, 1.0, 1.0);

vec4 color = vec4(1.0, 1.0, 1.0, 1.0);

color = mix(diffuseSand, color, min(abs( 400.0 - vPosition.y) / 500.0, 1.0));

color = mix(diffuseGrass, color, min(abs( 800.0 - vPosition.y) / 200.0, 1.0));

color = mix(diffuseRock, color, min(abs(1000.0 - vPosition.y) / 300.0, 1.0));

color = mix(diffuseSnow, color, min(abs(1200.0 - vPosition.y) / 300.0, 1.0));

gl_FragColor = vec4(color.rgb * vLightWeighting, color.a);

31

Input System

Original

Expanded virtualjoystick.js by Jerome Etienne for multi-touch controls.

Current

CSS3 driven panels.

Repurposed ControlsOverlay.js from Cocos2D-HTML5 to WebGL.

https://github.com/oros/ControlsOverlay.js

33

Freewill.js

freewill = new Freewill({ 'container': document.querySelector('#easle') });

/* Add a button. */

button = freewill.addButton({

'image': './images/freewill/buttonred.png',

'pos': [ w - 106.0, h - 98.0 ],

'opacLow': 0.3

});

/* Add a Joystick to control camera rotation. */

rotation = freewill.addJoystick({

'imageBase': './images/freewill/dpad.png',

'imagePad': './images/freewill/pad.png',

'fixed': false,

'trigger': [w / 2.0, 0.0, w / 2.0, h - 108.0],

'opacLow': 0.0

}); 34

Traversing Peaks and Valleys

Minimize triangles via gl.TRIANGLE_STRIP.

35

TODO: HTML5 Audio

Current

HTML5 <audio> elements.

Loads JSON via AJAX.

Simultaneous playback.

TODO

Integrate into PeaksAndValleys.

Explore SoundJS.

36

var tracks = {};

function Audio() {

var xhr = new XMLHttpRequest();

xhr.open('GET', 'audio/audio.json', true);

xhr.responseType = 'text';

xhr.onload = function () {

if (this.status === 200) {

var json = eval(this.response);

for (var n = 0; n < json.length; n = n + 1) {

var item = json[n];

tracks[item.name] = document.createElement('audio');

tracks[item.name].setAttribute('src', 'audio/' + item.file);

tracks[item.name].setAttribute('preload', 'auto');

tracks[item.name].setAttribute('loop', 'true');

if (item.playOnLoad === true) {

tracks[item.name].setAttribute('autoplay', 'true');

}

tracks[json[n].name].load();

}

}

};

xhr.send();

}

Audio.prototype.playTrack = function (name) {

if (tracks[name] && tracks[name].paused === true) {

tracks[name].play();

}

};

Audio.prototype.stopTrack = function (name) {

if (tracks[name] && tracks[name].paused === false) {

tracks[name].pause();

}

};

TODO: BlackBerry Messenger

Register Application blackberry.event.addEventListener('onaccesschanged', function (accessible, status) {

if (status === 'allowed') {

this.registered = accessible;

/* We’re ready for BBM functionality! */

}

}, false);

blackberry.bbm.platform.register({

uuid: ‘http://www.famkruithof.net/uuid/uuidgen'

});

Invite To Download (2% generating 20%) (V)(;,,;)(V) if (this.registered === true) {

blackberry.bbm.platform.users.inviteToDownload();

} 37

TODO: Can Do!

Additonal Social Integration

Facebook, Twitter, etc.

Multiplayer

Node.js and Socket.io.

Rendering multiple players/models in one area.

3D Interactions

Ray tracing.

Cut Scenes, Model Animation, etc.

Popular components of many games.

38

TODO: Wish List

Web Audio API

Low latency audio.

True multi-channel audio.

Scoreloop

Currently available to native developers.

Simplifies social gaming (leader boards, achievements, etc.)

Monetization

Looking beyond sales revenue.

Subscription, digital goods, etc.

39

Learning Resources

40

BlackBerry Got Game Port-a-thon

November 16th and 17th

Tiered Rewards

$100 per eligible application (up to 20.)

Between 2 and 5: BlackBerry PlayBook

First 100 to submit 5+: BlackBerry Dev Alpha

First 10 to submit 10+: Paid trip to GDC 2013 in San Francisco

More Information / Virtual Registration

http://devblog.blackberry.com/2012/11/got-game-port-a-thon

42

THANK YOU

Erik Oros ([email protected] | @WaterlooErik)

November 15, 2012