HTML5 Game
Development
Evan Wallace & Justin Ardini
Brown Game Developers • CS DUG
What is HTML5?
What is HTML5?
● Umbrella term for new browser tech
● Makes media first-class citizens (no plugins)
○ Audio
○ Video
○ Realtime graphics
● Adds support for advanced web applications
○ Geolocation
○ File drag-and-drop
○ Offline cache
○ Lightweight networking
○ Multithreading
Games in HTML5
Why?
● Easy
○ Rapid development
○ Easy deployment
○ Open source culture and tools
● Widely supported
○ Any modern web browser
○ Mobile devices
○ Facebook / Google+ apps
○ etc.
● Not going away anytime soon
● JavaScript is fun!
API: 2D Canvas
● A space to draw on from JavaScript
<canvas id="c" width="400" height="300"></canvas>
var c =
document.getElementById('c').getContext('2d')
c.fillStyle = 'red'
c.fillRect(0, 0, 50, 50)
● The main reason for HTML5 games
○ Rich 2D drawing API (lines, curves, polygons,
images, text)
○ Games can directly manipulate pixels, not possible
through HTML+CSS
○ Hardware accelerated and widely supported
API: WebGL
● Hardware-accelerated 3D graphics in
JavaScript
<canvas id="c" width="400" height="300"></canvas>
var gl = document.getElementById('c').getContext(
'experimental-webgl')
gl.clearColor(1, 0, 0, 1)
gl.clear(gl.COLOR_BUFFER_BIT)
● Similar to OpenGL ES 2.0
○ Verbose, low-level API
○ You'll want a framework (e.g. three.js)
○ Need to know GLSL, OpenGL Shading Language
API: Web Sockets
● TCP sockets connecting browser and server
○ Fast communication channel
○ No HTTP headers
● Enables networked multiplayer games
○ Perfect for turn-based games
○ Unfortunately, currently no way of using UDP, which
is ideal for realtime games
● Needs special server-side support
API: Web Sockets
var socket = new WebSocket("http://localhost:8000")
socket.onopen = function() {
console.log('Socket opened')
}
socket.onmessage = function(msg) {
console.log('Received ' + msg.data)
}
socket.onclose = function() {
console.log('Socket closed')
}
socket.send('Sending a message')
socket.close()
API: Audio
● A single audio track
<audio id="a" src="example.wav"></audio>
document.getElementById('a').play()
● Usage in games
○ Usually one background music track
○ Usually need multiple copies of a sound effect
playing simultaneously
Time to make a game!
Anatomy of a Game
Logic JavaScript code
Graphics <canvas>
Input onmousedown, onkeydown
Sounds <audio>
Music <audio>
Multiplayer new WebSocket()
Game assets <img>
Event loop setInterval()
Getting Started: The Event Loop
● Display new frames at a fixed rate
○ Logically separating updating and drawing helps
○ Keyboard and mouse events will be handled using
event listeners
window.onload = function() {
setInterval(function() {
update()
draw()
}, 1000 / 60)
}
Creating the Screen
● We'll use a canvas for the screen
<canvas id="screen" width="400" height="300"></canvas>
○ Uses standard HTML coordinate system by default
(0, 0)
(400, 300)
Drawing a Frame
● First need to clear the screen
○ Canvas remembers everything drawn to it (from the
last frame)
○ Want to start from scratch
function draw() {
var c = document.getElementById('screen').getContext('2d')
c.clearRect(0, 0, c.canvas.width, c.canvas.height)
// draw frame here
}
Drawing an Image
● Canvas API integrates with the DOM
○ Can draw an <img> directly!
<img id="image" src="example.png" style="display: none">
var image = document.getElementById('image')
c.drawImage(image, 40, 10)
(0, 0)
(40, 10)
Sprite sheets
● All frames of an animation in a single image
○ Sprite sheets are widely available on the internet
○ Pass more arguments to c.drawImage() to only
draw part of an image
Moving the Player
● Player is moved using a velocity
○ Velocity set by keyboard
○ Add velocity to player position every frame
var keys = {}
document.onkeydown = function(e) { keys[e.which] = true }
document.onkeyup = function(e) { keys[e.which] = false }
function update() {
player.velocity.x = !!keys[39] - !!keys[37] // right - left
player.velocity.y = !!keys[40] - !!keys[38] // down - up
player.x += player.velocity.x
player.y += player.velocity.y
}
Representing the Level
● Need a representation of solid objects
○ Simplest thing that works: list of solid rectangles
○ Graphics may be represented separately (i.e. an
entire pre-drawn image)
Collision Detection and Response
● Don't want the player to move through solid
rectangles
○ Have to detect when players hit something
○ Fit another rectangle around the player (rectangles
are easy to work with)
Collision Detection and Response
● Overlap test
○ Do two rectangles overlap?
○ Compare the ranges along the x and y axes
function overlapTest(a, b) {
return a.x < b.x + b.w && a.x + a.w > b.x &&
a.y < b.y + b.h && a.y + a.h > b.y
}
a
Collision Detection and Response
● Can now detect a collision
○ Loop over all rectangles and test for overlaps with
new player position
○ If collision, don't move there
● Can do better
○ Player is moving from A to B
○ Currently just stay at A when B overlaps the level
Would
like to
A stop
B
here
Collision Detection and Response
● Sweep test
○ Sweep from A to B, move up to the collision
function move(p, vx, vy) {
for (var i = 0; i < rects.length; i++) {
var c = { x: p.x + vx, y: p.y, w: p.w, h: p.h }
if (overlapTest(c, rects[i])) {
if (vx < 0) vx = rects[i].x + rects[i].w - p.x
else if (vx > 0) vx = rects[i].x - p.x - p.w
}
}
p.x += vx
// same thing for p.y and vy...
}
Platformer Movement
● Player movement now restricted to empty
regions of the level
○ Now need to move like a platformer
○ Jumping and gravity
● Gravity
○ Add constant number to y velocity each frame
● Detecting floors and ceilings
○ If we moved less vertically than we tried to
○ Reset y velocity to 0
Sound Effects: Take One
● First attempt at simultaneous playback
new Audio('example.wav').play()
○ Has too much delay in Firefox
○ Better to have an existing audio element already
Sound Effects: Take Two
● Better method of simultaneous playback
○ Cache as many audio elements as you want playing
simultaneously
○ Each new sound event plays the next audio element
in circular fasion
// support up to 4 copies of 'x.wav' playing at once
var elems = [], index = 0
for (var i = 0; i < 4; i++) elems.push(new Audio('x.wav'))
function playSoundEvent() {
elems[index].play()
index = (index + 1) % elems.length
}
Cross-Browser Sound Effects
● Audio still doesn't work consistently across
all browsers, as of right now:
○ An element must be reloaded in Chrome or it will
only play once
○ An element must not be reloaded in Firefox or there
will be a delay
function playSoundEvent() {
if (window.chrome) elems[index].load()
elems[index].play()
index = (index + 1) % elems.length
}
Performance
● Scenario: You made an awesome HTML5
game but it runs too slowly. What do you do?
Performance Tips
● Use a profiler!
○ Actually, use several (one for each target browser)
○ Chrome web inspector is easiest to use
● Figure out why the bottlenecks exist
○ sin / cos / sqrt calls?
○ Too many canvas draw calls?
○ Too many function calls?
● Check for too many garbage collections
○ Allocate fewer objects
○ Pool and reuse objects
Questions?
Time for PIZZA!
Workshop time!
Materials:
http://madebyevan.com/gamedevclass/
References
● Make your own 8-bit sounds
http://www.bfxr.net/
● Canvas tutorial
http://www.netmagazine.com/tutorials/learning-basics-html5-canvas
● Canvas cheat sheet
http://simon.html5.org/dump/html5-canvas-cheat-sheet.html
● Mozilla Developer Network
https://developer.mozilla.org/en/HTML/HTML5