Slide 1

Slide 1 text

Build a Game in JavaScript Starring Your Cat Omada Health February 16, 2016 1 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > [email protected] @mattmckenna

Slide 2

Slide 2 text

Why Build a Game in JS? • Haven't you always wanted to make a game? • You probably already know JS, so you can get started right away. • JS apps are relatively easy to deploy. • JS apps "work" on all devices. • It's fun! 2 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Croissant!

Slide 3

Slide 3 text

Croissant -- this is you! Croissant the Pizza Cat • Here's a screenshot of a game built in JS, starring Croissant: 3 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Pizzas -- touch these for points! Cat beds -- jump to avoid these!

Slide 4

Slide 4 text

Croissant the Pizza Cat • Let's play real quick! • http://runner.mtmckenna.com/ • https://github.com/mtmckenna/croissant-runner/ 4 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 5

Slide 5 text

The Next 30 Minutes • Getting started with a toolchain. • Create a game loop to draw on the . • Animate an image on the . • What about audio? • Handle user input. • Deploy your game! 5 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 6

Slide 6 text

Getting Started with a Toolchain • We need a toolchain in order to... • ... combine and transpile our code (e.g. ES6 to ES5). • ... bundle our JS modules into one file. • ... create a minified version to deploy. • ... live reload your web browser on code changes. 6 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 7

Slide 7 text

Let's Use Webpack 7 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > $ webpack-dev-server --inline http://localhost:8080/ webpack result is served from / content is served from /Users/ mckenna/workspace/croissant-runner Hash: 523d4bb3ed182dcd831f Version: webpack 1.12.6 Time: 2575ms $ npm start ... or create a shortcut! https://webpack.github.io/docs/tutorials/getting-started/

Slide 8

Slide 8 text

What is Webpack? • Transforms/processes files like Gulp/Grunt • Bundles JS modules together into one file like Browserify • Turns your static assets (JS, CSS, images) into requirable modules e.g. "require('pizza.png');" • https://github.com/petehunt/webpack-howto 8 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 9

Slide 9 text

The Game Loop • The game loop 1) calculates the position of sprites (Croissant, pizzas, etc.) and 2) draws them to the screen. 9 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > setInterval(function() { update(); draw(); }, 1000.0/60.0); We'll do a better game loop in 4 slides.

Slide 10

Slide 10 text

update() • Update the position of the sprites (e.g. Croissant, the pizzas, cat beds, etc.). • Check if anything is touching anything (e.g. if Croissant has touched a pizza/cat bed) and then do something (e.g. increase the score/end the game). 10 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > update() { updateSpritePositions(); handleCollisions(); }

Slide 11

Slide 11 text

draw() • Clear the 's context (more on in like 5 seconds). • Draw the randomly generated sprites (cat beds, pizzas, flowers, etc.). • Draw Croissant. 11 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > draw() { context.clearRect(0, 0, 320, 240); drawGround(); spriteEmitter.draw(); drawScore(); croissant.draw(); }

Slide 12

Slide 12 text

Draw on the • is an HTML element on which you can programmatically draw and animate whatever you want free of the DOM. • https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/ Tutorial 12 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > var canvas = document.createElement('canvas'); document.body.appendChild(canvas); var context = canvas.getContext('2d'); context.fillStyle = '#4f8f00'; context.font = '15px Monaco'; context.fillText('Hi Score: 19', 10, 25);

Slide 13

Slide 13 text

A Better Game Loop in app.js 13 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > var canvas = document.createElement('canvas'); var game = new Game(canvas); var animReq; document.body.appendChild(canvas); function gameLoop() { animReq = window.requestAnimationFrame(gameLoop); game.update(); game.draw(); } gameLoop(); This is what the next slide is about! Our game logic lives in here!

Slide 14

Slide 14 text

requestAnimationFrame • Supported in modern browsers. • Calls the gameLoop function when the browser is ready to repaint the screen. • The browser will attempt to call gameLoop 60 times a second (i.e. 60 FPS). No promises though. • requestAnimationFrame is better than setInterval. 14 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 15

Slide 15 text

setInterval 15 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 0 seconds 1 second 0.5 seconds gameLoop runs gameLoop runs, but the browser isn't ready to redraw

Slide 16

Slide 16 text

requestAnimationFrame 16 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > 0 seconds 1 second 0.5 seconds gameLoop runs gameLoop runs, but the browser isn't ready to redraw

Slide 17

Slide 17 text

Sprites • Nowadays, a sprite is generally a single bitmap graphic, usually with multiple frames of animation. • Animation is done by flipping through the images' frames like a flipbook or filmstrip. 17 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Frame 0 Frame 1 0px, 0px 30px, 0px 60px, 0px 60px, 32px Both frames are in one image: croissant.png

Slide 18

Slide 18 text

Go, Croissant! 18 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 19

Slide 19 text

Go, Croissant! 19 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 20

Slide 20 text

Go, Croissant! 20 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 21

Slide 21 text

Go, Croissant! 21 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 22

Slide 22 text

A Sprite ES6 Class 22 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > export default class { constructor(type, context, startingPosition, size, velocity) { ... } cacheImage(type) { ... } createImage(type) { ... } get image() { ... } get currentFrame() { ... } intersects(anotherSprite) { ... } updatePosition() { ... } draw() { ... } } The draw method animates the sprite and places it on the . Next slide!

Slide 23

Slide 23 text

Sprite's Draw Method 23 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > draw() { this.context.drawImage(this.image, this.currentFrame * this.size.width, 0, this.size.width, this.size.height, this.pos.x, this.pos.y, this.size.width, this.size.height); }This is the part that flips between the two frames in croissant.png

Slide 24

Slide 24 text

Audio • Audio in Javascript is ughghghhhhhh. • You have a couple options: The HTML5 tag and the Web Audio API. • The tag is simple to use, but nerfed on mobile. • So use Web Audio API. • https://developer.mozilla.org/en-US/docs/Web/API/ Web_Audio_API 24 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 25

Slide 25 text

A SoundEffect ES6 Class 25 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > export default class { constructor(type, context, loop = false) { ... } loadAudio(path) { ... } decodeAudio(data) { ... } play() { ... } stop() { ... } } Web Audio API rigamarole How we'll actually play our audio

Slide 26

Slide 26 text

Handling Input • "keydown" will work for keyboards and "touchstart" will work on mobile. • We have to use "bind" to make sure "this" isn't the window object. 26 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > addInputListeners() { window.addEventListener('keydown', this.jump.bind(this)); window.addEventListener('touchstart', this.jump.bind(this)); ... }

Slide 27

Slide 27 text

Build Production HTML/JS with Webpack 27 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > $ webpack -p

Slide 28

Slide 28 text

Deploying Your Game • Deploying JS-only apps is a (relative) breeze: no app store approval required and no app server to monitor. • Hosting options include Amazon S3, another CDN, your own web server, Surge.sh, Netlify. 28 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 29

Slide 29 text

Netlify Drag and Drop So Easy 29 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Click! Drag the dist folder! Click! Your game! Here!

Slide 30

Slide 30 text

Takeaways • Configure a toolchain before starting. • Use and requestAnimationFrame for your game loop. • Use the Web Audio API for audio. • Deploy on a static web host. 30 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 31

Slide 31 text

Finishing Your Game • Our game isn't done! • We need tests! • We need menus! • We need to persist high scores! • We need a deploy/rollback strategy! • We need mobile and desktop apps! 31 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 32

Slide 32 text

We Need... 32 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > Next week: Build a Game in Ember Starring Your Cat!

Slide 33

Slide 33 text

Links • https://developer.mozilla.org/en-US/docs/Games • http://ludumdare.com/compo/tools/ 33 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 34

Slide 34 text

Graphics/Audio Tools • Dots (iOS) • Pixen (OS X) • Pixelmator (OS X) • bfxr (web) • Audacity (OS X / Windows) 34 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 35

Slide 35 text

Croissant Stickers 35 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >

Slide 36

Slide 36 text

Thank You! 36 > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >