Free Download PDF Books, HTML5 Games Creating Fun with HTML5 CSS3 and WebGL – PDF Books

HTML5 Games Creating Fun with HTML5 CSS3 and WebGL – PDF Books

HTML HTML5 ReadOnline

Summary of Contents

  • Page 1

  • Page 2

  • Page 3

    HTML5 GamesactionURI(http://www.allitebooks.org):www.freepdf-books.com

  • Page 4

    actionURI(http://www.allitebooks.org):www.freepdf-books.com

  • Page 5

    HTML5 GamesCREATING FUN WITH HTML5, CSS3, AND WEBGLJacob SeidelinactionURI(http://www.allitebooks.org):www.freepdf-books.com

  • Page 6

    This edition first published 2014© 2014 John Wiley and Sons, Ltd.Registered officeJohn Wiley & Sons Ltd, The Atrium, Southern Gate, Chichester, West Sussex, PO19 8SQ, United Kingdom For details of our global editorial offices, for customer services and for information about how to apply for ...

  • Page 7

    actionURI(http://www.allitebooks.org):www.freepdf-books.com

  • Page 8

    Publisher’s AcknowledgementsSome of the people who helped bring this book to market include the following:Editorial and ProductionVP Consumer and Technology Publishing Director: Michelle LeeteAssociate Director–Book Content Management: Martin TribeAssociate Publisher: Chris WebbAssociate Comm...

  • Page 9

    About the AuthorJACOB SEIDELIN is a freelance web developer with 15 years of experience working with back-end programming, graphics design, and front-end technology. When not working with clients he enjoys JavaScript and HTML5, web game development, and generally pushing the limit of what is poss...

  • Page 10

    AcknowledgmentsI’d like to acknowledge a few people who helped in the making of this book. I want to thank my editors Sydney Argenta and Melba Hopper and the rest of the Wiley team. A big thanks to Andrew Wooldridge, my technical editor, whose keen eye for technical details kept me on my toes. ...

  • Page 11

    Contents 19,Introduction 19,  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19,1 20,Who this book is for 20, 20, . . . . . . 20,. . . . . . . 20,. . . . . . . 20,. . . . . . . 20,. . . . . . . 20,. . . . . . . 20...

  • Page 12

    xHTML5 G A ME S 45,Loading the scripts 45, 45, . . . . . . 45,. . . . . . . 45,. . . . . . . 45,. . . . . . . 45,. . . . . . . 45,. . . . . . . 45,. . . . . . . 45,. . . . . . 45, . 45,27 49,Creating a DOM helper module 49, 49, . . . . . . 49,. . . . . . . 49,. . . . . . . 49,. . . ...

  • Page 13

    xiT ABL E O F C O NT E NT S 101,Part II Creating the 101,Basic Game. . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 103,CHAPTER 4 103,Building the Game 103,  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...

  • Page 14

    xiiHTML5 G A ME S 148,Drawing with canvas 148, 148, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148, .130 149,Drawing shapes and paths 149, 149, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....

  • Page 15

    xiiiT ABL E O F C O NT E NT S 253,CHAPTER 9 253,Animating Game Graphics 253,. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253,235 254,Making the Game React 254, 254, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ....

  • Page 16

    xivHTML5 G A ME S 327,CHAPTER 11 327,Creating 3D Graphics with WebGL 327,. . . . . . . . . . . . . . . . . . . . . . . . 327,309 328,3D for the Web 328, 328, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...

  • Page 17

    xvT ABL E O F C O NT E NT S 403,Making the Game State 403,Persistent 403, 403, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403, .385 403,Saving the game data 403, 403, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ...

  • Page 18

    xviHTML5 G A ME S

  • Page 19

    Introduction“ALL THIS IS done in HTML5, by the way!” exclaimed Steve Jobs, the mind and face of the Apple success story, as he walked the audience through the new HTML5-powered ad system at the iPhone OS 4.0 Keynote, receiving cheers, laughs, and applause in return. The recent developments in...

  • Page 20

    HTML5 G A ME S2direction of actual applications, allowing developers to build experiences more akin to desk-top applications than the traditional page-based web site. Naturally, these developments also apply to web games, and many of the recent advancements are a perfect fit for games and other i...

  • Page 21

    IN T R OD UCT I O N3During the course of the book, you go through the development of a complete web game from the initial white page to the final product, ready to play in both the browser as well as on your iPhone or Android device. You see how to utilize new elements such as canvas and audio to...

  • Page 22

  • Page 23

    Chapter 1 Gaming on the WebChapter 2 Taking the First StepsChapter 3 Going MobilePart IGetting Started with HTML5 Games

  • Page 24

  • Page 25

    Chapter 1Gaming on the WebIn This Chapter■ Finding out what HTML5 is and where it came from■ Seeing HTML5 within the context of games■ Looking at important new features■ Enabling feature detection and dealing with legacy browsersBEFORE I DIVE into code, I want to establish the context of ...

  • Page 26

    HTML5 G A ME S8Finally, I briefly introduce the puzzle game that I use throughout the rest of the book to take you through the creation of a complete HTML5 game.Tracing the History of HTML5HTML, the language of the web, has gone through numerous revisions since its invention in the early 1990s....

  • Page 27

    C HA P T E R 1 G A MING O N T HE W EB9nature of this element without a doubt helped it spread quickly when the first interactive animations and graphics effects started appearing. More advanced projects soon followed, giving the new standard a dose of good publicity and promising a future with a ...

  • Page 28

    HTML5 G A ME S10 ctx.fillStyle = "blue"; ctx.beginPath(); ctx.arc(50, 50, 25, 0, Math.PI * 2, true); ctx.arc(150, 50, 25, 0, Math.PI * 2, true); ctx.fill(); // draw a red triangle ctx.fillStyle = "red"; ctx.beginPath(); ctx.moveTo(100, 75); ctx.l...

  • Page 29

    C HA P T E R 1 G A MING O N T HE W EB11I revisit the canvas element in Chapter 6 and explore it in detail when I use it to create game graphics and special effects.AudioThe new audio element is just as welcome to a web game developers’ toolbox as the canvas element. Finally, you have native aud...

  • Page 30

    HTML5 G A ME S12TIPThe W3C is currently working on expanding HTML5 with the Web Audio API, which enables advanced audio synthesizing and processing. Because this API is still experimental, I won’t be using it for the game in this book, although I briefly examine the possibilities it presents in...

  • Page 31

    C HA P T E R 1 G A MING O N T HE W EB13Of course, using WebSockets requires that you also implement a server application that’s compatible with the WebSockets protocol and capable of responding to the messages you send to it. This doesn’t have to be a complex task, however, as I show you in C...

  • Page 32

    HTML5 G A ME S14WebGLWebGL is OpenGL for the web. It’s based on OpenGL ES 2.0. The most widely used graphics API is now available for web developers to create online 3D graphics content. Of course, this has major implications for the kind of web games that are now possible. As a testament to th...

  • Page 33

    C HA P T E R 1 G A MING O N T HE W EB15Creating Backward CompatibilityAs with most other new technologies, issues with backward compatibility inevitably show up when working with HTML5. HTML5 isn’t one big, monolithic thing: Browsers support fea-tures, not entire specifications. No browsers tod...

  • Page 34

    HTML5 G A ME S16Filling the gaps with polyfillsBeginning in the early 2000s, a popular trend has been to favor so-called progressive enhancement when adding new features to websites. This strategy calls for websites to target the lowest common denominator in terms of supported features. Any te...

  • Page 35

    C HA P T E R 1 G A MING O N T HE W EB17The game you’ll develop takes advantage of several features from the HTML5 specification and also uses related technologies such as web fonts and CSS3 for building the UI. Although the game may not be revolutionary, it allows me to cover many of the newest...

  • Page 36

  • Page 37

    Chapter 2Taking the First StepsIn This Chapter■ Setting out the rules and mechanics of the game■ Identifying various stages of the game■ Setting up the basic HTML■ Creating the first JavaScript modules■ Making a splash screen using web fontsWITH THE BACKGROUND and technological context ...

  • Page 38

    HTML5 G A ME S20Understanding the GameThe game I walk you through in this book is a match-three puzzle game, a game type made popular mainly by the Bejeweled game series by casual game developer PopCap Games. I have named the game Jewel Warrior; feel free to pick a better and more creative name ...

  • Page 39

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S21and raises the number of points needed to advance to the next level. This might keep players on their toes, but without modification, a skilled player can keep playing indefinitely. To make the game harder and harder as time goes by, the point gap be...

  • Page 40

    HTML5 G A ME S22Main menuAfter the player clicks through the splash screen, she is taken to the main menu. This is a simple menu with just a few items. Most importantly, the menu gives access to the actual game but also features buttons for displaying the high score, more info about the game, and...

  • Page 41

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S23Figure 2-3: The sketch of the game screen includes a grid and space for a toolbar.High scoreWhen the game ends, the application switches to a high score list showing the top scores along with the player names. If the player achieved a score that’s...

  • Page 42

    HTML5 G A ME S24Figure 2-4: This sketch shows a typical high score list.Creating the Application SkeletonYou don’t need special tools or applications to follow the development of the game. When you get to the WebSocket discussion in Chapter 13, you do need to install Node.js and set it up on ...

  • Page 43

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S25Okay, time to get started. Create an empty folder for the game project and create two sub-folders: scripts and styles. Later in the process, a few extra folders are added, but these two are enough for now.Setting up the HTMLThe foundation of the gam...

  • Page 44

    HTML5 G A ME S26Listing 2-2 Adding screen elements to the game container... <div id="game"> <div class="screen" id="splash-screen"></div> <div class="screen" id="main-menu"></div> <div class...

  • Page 45

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S27Listing 2-4 The initial content of the main style sheetbody { margin : 0; overflow : hidden;} #game { position : absolute; left : 0; top : 0; width : 320px; height : 480px; background-color : rgb(30,30,30);} #game .screen { ...

  • Page 46

    HTML5 G A ME S28the Microjs website where you’ll find several script loaders. One example is the Yepnope library, which is also incorporated into Modernizr. By using the feature detection of Modernizr and the conditional loading of Yepnope, it’s easy to load only the right scripts and fallbac...

  • Page 47

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S29All game modules are properties of the jewel namespace and are basically just objects with some public methods. If you’ve ever used the so-called Module Pattern in your own code, you’ll be familiar with this method. All functionality is defined i...

  • Page 48

    HTML5 G A ME S30 queueEntry.loaded = true; if (!executeRunning) { executeScriptQueue(); } }; image.src = src; } ...})();First, the load() function adds the script to the scriptQueue array. It stores not only the name of the file ...

  • Page 49

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S31 executeScriptQueue(); }; script.src = next.src; first.parentNode.insertBefore(script, first); } else { executeRunning = false; } } ...})();The executeScriptQueue() functi...

  • Page 50

    HTML5 G A ME S32 function hasClass(el, clsName) { var regex = new RegExp("(^|\\s)" + clsName + "(\\s|$)"); return regex.test(el.className); } function addClass(el, clsName) { if (!hasClass(el, clsName)) { el.className += " "...

  • Page 51

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S33Listing 2-10 Loading the jewel.dom module...<head> ... <script src="scripts/jewel.js"></script> <script> window.addEventListener("load", function() { jewel.load("scripts/dom....

  • Page 52

    HTML5 G A ME S34This is much less obtrusive than the alert() debugging that web developers had to resort to years ago. This book doesn’t make a big deal out of adding debugging mechanisms or error han-dling in the code, focusing instead on getting to know the new features and technologies avail...

  • Page 53

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S35Even if Jewel Warrior doesn’t use a very deep namespace hierarchy, having to type the full module path to get to a function can still be annoying. To save on typing, you can easily make shortcut references to modules, as shown in Listing 2-11, wher...

  • Page 54

    HTML5 G A ME S36Listing 2-13 Adding the splash screen markup... <div id="game"> <div class="screen" id="splash-screen"> <h1 class="logo">Jewel <br/>Warrior</h1> <span class="continue"...

  • Page 55

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S37Copy the font files from the Chapter 2 code archive and place them in a new folder called fonts in the project folder. The CSS font declarations go in a new CSS file, fontfaces.css, in the styles folder. Listing 2-14 shows the content of this style s...

  • Page 56

    HTML5 G A ME S38Listing 2-15 Adding a reference to the embedded font#game { ... font-family : Geo; color : rgb(200,200,100);}Remember to also put a link reference to fontfaces.css in the head element in index.html:<head> ... <link rel="stylesheet" href="styl...

  • Page 57

    C HA P T E R 2 T AK ING T HE FIR S T S T EP S39The logo is now set in Slackey, the text is colored green, and everything is placed in the center. The text-shadow declaration serves two purposes. A bright yellow outline is added using two thin shadows in opposite directions. The third shadow adds ...

  • Page 58

    HTML5 G A ME S40Figure 2-5: Here is the splash screen in its current state.SummaryIn this chapter, I laid out the concepts of the Jewel Warrior game. I discussed the rules of the game, the jewel swapping mechanics, and how the player scores points by matching sets of identical jewels. I then des...

  • Page 59

    Chapter 3Going MobileIn This Chapter■ Designing for mobile devices■ Supporting different screen resolutions■ Creating the main menu■ Making web applications for iOSTHIS CHAPTER COVERS some of the advantages and challenges you face when taking your web application to the mobile platform. I...

  • Page 60

    HTML5 G A ME S42Developing Mobile Web ApplicationsToday hundreds of millions of devices, smartphones, and tablets run on software such as Apple’s iOS and the Google-backed Android system. These devices can run most advanced applications and games built with HTML5.Games have been particularly su...

  • Page 61

    C HA P T E R 3 GOING M O BIL E43The challenges of mobile platformsDeveloping your application or game with web technology presents numerous challenges. Not being tied to a single distribution channel can be a drawback. Getting new apps from the App Store or from the Android Market is easy, and m...

  • Page 62

    HTML5 G A ME S44Figure 3-1: The virtual keyboard on the iPod touch and iPhone lets users input data.Mouse versus touchMobile devices also lack a mouse, of course, but at least the function of the touch screen is somewhat analogous to the computer mouse. Tapping the screen works the same as clic...

  • Page 63

    C HA P T E R 3 GOING M O BIL E45as a shortcut to context menus or other alternative actions. On touch screens, it’s difficult to differentiate between types of touches. We have only one type of finger. The workaround most often used is to differentiate between short and long taps, with a long p...

  • Page 64

    HTML5 G A ME S46This also goes for tablet displays. Some tablets have display resolutions similar to smart-phones, whereas others can compete with desktop monitors. Still, the device resolutions are similar. Table 3-2 shows a small selection of display resolutions on various tablets.Table 3-2 T...

  • Page 65

    C HA P T E R 3 GOING M O BIL E47This way, the computer can safely use kerning to adjust the space between letters to improve readability. It also allows the em unit to be used in other alphabets that have no letter M.NOTEYou can also use the em unit to define a few special characters. The width o...

  • Page 66

    HTML5 G A ME S48Listing 3-2 Using relative units in logo Styles.logo { font-size : 1.5em; line-height : 0.9em; text-shadow : 0.03em 0.03em 0.03em rgb(255,255,0), -0.03em -0.03em 0.03em rgb(255,255,0), 0.10em 0.15em 0.15em rgb(0,0,0); ...Note that,...

  • Page 67

    C HA P T E R 3 GOING M O BIL E49Table 3-3 Viewport meta tag parametersDirectiveDescriptionwidthA numeric value in pixels that specifies the width of the viewport that the device should use to display the page. The special value device-width sets the width to the device width.heightA numeric valu...

  • Page 68

    HTML5 G A ME S50Listing 3-5 Disabling user scaling<head> ... <meta name="viewport" content="width=device-width, user-scalable=no"> ...</head>If you load the game now on, for example, an iPad, the game area doesn’t fill the entire screen, ...

  • Page 69

    C HA P T E R 3 GOING M O BIL E51Listing 3-7 Adding menu CSS rules/* Main menu styles */#main-menu { padding-top : 1em;} ul.menu { text-align : center; padding : 0; margin : 0; list-style : none;}ul.menu li { margin : 0.8em 0;}ul.menu li button { font-family : Slackey, sans-se...

  • Page 70

    HTML5 G A ME S52Remember that values specified in em units are relative to the font-size of the element. Because the button elements have a font-size value of their own, all the other CSS values of the button elements are now relative to this font-size. Furthermore, this font-size is itself speci...

  • Page 71

    C HA P T E R 3 GOING M O BIL E53 } } return { run : run };})();The first time it’s called, the public run() method calls the setup() function. This function sets up an event handler on the screen element that switches screens when the user clicks or taps the screen. As d...

  • Page 72

    HTML5 G A ME S54Listing 3-10 Calling the run methodjewel = (function() { ... function showScreen(screenId) { var dom = jewel.dom, $ = dom.$, activeScreen = $("#game .screen.active")[0], screen = $("#" + screenId)[0]; if (!je...

  • Page 73

    C HA P T E R 3 GOING M O BIL E55 function run() { if (firstRun) { setup(); firstRun = false; } } return { run : run };})();The first time the main menu is displayed, the event handling is set up so that clicking the menu items takes the user...

  • Page 74

    HTML5 G A ME S56Figure 3-2: The main menu offers the user an array of game options.Using CSS media queriesNo matter how hard you try, sometimes you just can’t make a single set of CSS rules behave properly across all devices and resolutions. Sometimes, the best solution is to make separate sty...

  • Page 75

    C HA P T E R 3 GOING M O BIL E57You can also use media queries in the actual CSS:@media screen and (min-width : 480px) { body { font-size : 150%; }}This example scales the font-size to 150%, but only when the content is displayed on a screen and only if the width of the display is at...

  • Page 76

    HTML5 G A ME S58FeatureValuesDescriptionmonochromeNon-negative value, for example, 2Describes the number of bits per pixel used in a monochrome output device. The value is 0 for non-monochrome displays.resolutionPositive resolution, for example, 300dpiscanprogressive or interlaceOnly applies to t...

  • Page 77

    C HA P T E R 3 GOING M O BIL E59@media screen and (orientation: portrait) { #sidebar { display : none; }}@media screen and (orientation: landscape) { #sidebar { display : block; }}This example shows only the #sidebar element when the page is displayed in landscape mode.A...

  • Page 78

    HTML5 G A ME S60In the mobile.css style sheet, you first make the game fill the entire display. In main.css, you gave the game element a fixed size of 320x480 pixels. That works fine for placing the game on a web page and displaying it on a computer monitor. A game like Jewel Warrior doesn’t ne...

  • Page 79

    C HA P T E R 3 GOING M O BIL E61Listing 3-15 Adding landscape styles/* smartphones landscape */@media (orientation: landscape) { #splash-screen, #main-menu { font-size : 1.0em; padding-top : 0.75em; } ul.menu li { display : inline-block; margin : 0; } ...

  • Page 80

    HTML5 G A ME S62Figure 3-3: The main menu can display in landscape mode.Developing for iOS and Android DevicesApple sits heavily on the handheld device market: That’s no secret. Android devices are gain-ing market share, but the ubiquity of iPod, iPhone, and iPad devices that all run the same...

  • Page 81

    C HA P T E R 3 GOING M O BIL E63Listing 3-16 Enabling web application mode<head> ... <meta name="apple-mobile-web-app-capable" content="yes" /> ...</head>With apple-mobile-web-app-capable set to yes, iOS knows that when this page is bookmarked and su...

  • Page 82

    HTML5 G A ME S64Listing 3-17 Testing for the standalone propertyif (window.navigator.standalone) { alert("You are running the standalone app!");} else if (window.navigator.standalone === false) { alert("You are using app in mobile Safari!");} else { alert("You ar...

  • Page 83

    C HA P T E R 3 GOING M O BIL E65The new test determines whether the standalone mode is enabled. Because the question doesn’t make sense on non-iOS devices, you treat a nonexistent standalone property as though it’s running in standalone mode. Besides, what you’re really interested in is bei...

  • Page 84

    HTML5 G A ME S66Listing 3-21 Adding the install screen markup<div id="game"> ... <div class="screen" id="install-screen"> <h1 class="logo">Jewel <br/>Warrior</h1> <span> Click the <img sr...

  • Page 85

    C HA P T E R 3 GOING M O BIL E67Figure 3-4: The mobile Safari install screen shows when the game loads.On devices running iOS 6 or earlier, the icon is processed in a way that adds a shiny effect. By using apple-touch-icon-precomposed instead of apple-touch-icon, you can tell iOS to leave the ic...

  • Page 86

    HTML5 G A ME S68Listing 3-23 Using icons for multiple resolutions<head> ... <link rel="apple-touch-icon-precomposed" href="images/ios-icon.png"/> <link rel="apple-touch-icon-precomposed" sizes="72x72" href="...

  • Page 87

    C HA P T E R 3 GOING M O BIL E69You can also use one set of icons for the entire website by leaving out the link elements and placing the icon images in the root directory of the website. The iOS system then searches the root for a suitable icon using a list of predefined filenames in the format ...

  • Page 88

    HTML5 G A ME S70mode. This image must have the dimensions 748x1024, which means that the content needs to be rotated 90 degrees. I have created three startup images that display only the dimen-sions of the images so you can see when each one is loaded. You can find these images in the images fold...

  • Page 89

    C HA P T E R 3 GOING M O BIL E71The value of the content attribute must be one of default, black, and black- translucent. Unfortunately, this feature is currently broken in iOS 7, along with a number of other things as mentioned earlier. Instead of using the value you provide, iOS 7 uses the back...

  • Page 90

    HTML5 G A ME S72the best you can do is put a shortcut on the home screen that opens in the standard browser application. However, the Android browser gives you more space to work with than Safari does, and the only space that’s reserved is the top status bar. When a page loads in the Android br...

  • Page 91

    C HA P T E R 3 GOING M O BIL E73This feature has no place in a game. The user should be able to tap and press anything without interference from the native browser behavior. The following CSS property disables the callout:-webkit-touch-callout: none;Likewise, the ability to select text and images...

  • Page 92

    HTML5 G A ME S74when things don’t work out as expected. Although the mobile browsers aren’t as feature-rich as their desktop counterparts, they do have options that come in handy for debugging JavaScript.First, if you’re using Safari on a Mac OS X computer, you can connect your iPad or iPho...

  • Page 93

    C HA P T E R 3 GOING M O BIL E75Figure 3-7: Use the mobile Safari developer settings for debugging.When the console is enabled, you see an error bar just below the URL bar in Safari. The error bar reports the number of errors on the page. If any HTML, CSS, or JavaScript errors occur, you can cli...

  • Page 94

    HTML5 G A ME S76Figure 3-8: Once enabled, the debugger provides you with detailed error information in mobile Safari.Debugging on AndroidIn Android 4.0 and higher, the stock browser also comes with a built-in console. Simply type about:debug in the address bar to enable the console. You probab...

  • Page 95

    C HA P T E R 3 GOING M O BIL E77TIPUnlike some of their desktop counterparts, the JavaScript console functions in Android and iOS take only one argument. You can supply more than one argument to, for example, console.log(), but only the first one is used in the log message.Building Native Web App...

  • Page 96

    HTML5 G A ME S78to build your game for iOS because you need a machine running Mac OS X and the Xcode development suite actionURI(http://developer.apple.com/xcode):(http://developer.apple.com/xcode). To install your game on the actual devices and distribute it through the App Store, you also must ...

  • Page 97

    C HA P T E R 3 GOING M O BIL E79<body> <button id="snap">Take a picture!</button> <script> var button = document.getElementById("snap"); button.addEventListener("click", function() { navigator.camera.getPicture( ...

  • Page 98

    HTML5 G A ME S80 version = "1.0.0"> <name>Jewel Warrior</name> <description> A game of jewel swapping </description> <author href="http://nihilogic.dk" email="jseidelin@nihilogic.dk"> ...

  • Page 99

    C HA P T E R 3 GOING M O BIL E81Future Mobile PlatformsAt the moment, Android and iOS take the lion’s share of the mobile market, but new platforms are always emerging, and a few of them are very interesting for web development.Mozilla is hard at work on Firefox OS (actionURI(http://www.mozill...

  • Page 100

  • Page 101

    Chapter 4 Building the GameChapter 5 Delegating Tasks to Web WorkersChapter 6 Creating Graphics with CanvasChapter 7 Creating the Game DisplayChapter 8 Interacting with the GameChapter 9 Animating Game GraphicsPart IICreating the Basic Game

  • Page 102

  • Page 103

    Chapter 4Building the GameIn This Chapter■ Creating a module for the game board■ Encapsulating the game state■ Setting up the jewel board■ Implementing the game rules■ Reacting to jewel swapsIN THIS CHAPTER, I show you how to implement the rules and game mechanics that control the jewel...

  • Page 104

    HTML5 G A ME S86modules, mainly the game screen, can use to interact with the game state. Because the board serves as a backend to the game display, the code in this chapter doesn’t add visual elements to the game. This means that, in this chapter, you will have to call the functions manually i...

  • Page 105

    C HA P T E R 4 B UILD ING T HE G A ME87So far, the barebones board module has no functionality at all. In the following section, you move on to the first method and start fleshing out the module.Initializing the game stateThe board logic needs a few settings defined, such as the number of rows a...

  • Page 106

    HTML5 G A ME S88Listing 4-4 The Initializing functionjewel.board = (function() { var settings, jewels, cols, rows, baseScore, numJewelTypes; function initialize() { settings = jewel.settings; numJewelTypes = settings.numJewelTypes; ba...

  • Page 107

    C HA P T E R 4 B UILD ING T HE G A ME89The first thing you see in Listing 4-4 is a group of variable declarations. The first variable just imports the settings module because you need to access the settings in a bit. The second vari-able, jewels, is an array of arrays, essentially a two-dimension...

  • Page 108

    HTML5 G A ME S90function as an argument to the relevant method and have that method call the callback func-tion when it is done. You probably already know this pattern from JavaScript functions such as window.setTimeout() or the addEventListener() method on DOM elements. These functions both take...

  • Page 109

    C HA P T E R 4 B UILD ING T HE G A ME91 } } ...})();The jewel type is picked using the helper function randomJewel(), which simply returns an integer value between 0 and (numJewelTypes - 1). Listing 4-7 shows the random-Jewel() function.Listing 4-7 Creating a random jeweljewel.board ...

  • Page 110

    HTML5 G A ME S92 jewels[x] = []; for (y = 0; y < rows; y++) { type = randomJewel(); while ((type === getJewel(x-1, y) && type === getJewel(x-2, y)) || (type === getJewel(x, y-1) && ...

  • Page 111

    C HA P T E R 4 B UILD ING T HE G A ME93You now have enough code to set up the board and fill it with random jewels. If you type the following into the JavaScript console, you should see the jewels printed out as numeric valuesjewel.board.initialize()jewel.board.print()Implementing the RulesNow t...

  • Page 112

    HTML5 G A ME S94 // look up while (type === getJewel(x, y + up + 1)) { up++; } // look down while (type === getJewel(x, y - down - 1)) { down++; } return Math.max(left + 1 + right, up + 1 + down); } ...})();Note that che...

  • Page 113

    C HA P T E R 4 B UILD ING T HE G A ME95 chain = (checkChain(x2, y2) > 2 || checkChain(x1, y1) > 2); // swap back jewels[x1][y1] = type1; jewels[x2][y2] = type2; return chain; } return { canSwap : canSwap, ... }})()...

  • Page 114

    HTML5 G A ME S96other jewels fall down and more jewels enter the board from the top. This means that the board must be checked again, but this time the situation is not so simple. The only way to be sure all chains are detected is to be thorough and search the whole board. When you use the checkC...

  • Page 115

    C HA P T E R 4 B UILD ING T HE G A ME97 for (var x = 0; x < cols; x++) { gaps[x] = 0; for (var y = rows-1; y >= 0; y&#x2013;) { if (chains[x][y] > 2) { hadChains = true; gaps[x]++; re...

  • Page 116

    HTML5 G A ME S98Creating new jewelsThe check() function is not finished; it has a few loose ends. By moving existing jewels down, you fill the gaps below but leave new gaps at the top of the board. So, after processing all the jewels in a column, you need to create new jewels and have them come d...

  • Page 117

    C HA P T E R 4 B UILD ING T HE G A ME99Listing 4-16 Awarding points for chainsjewel.board = (function() { ... function check() { ... for (x = 0; x < cols; x++) { gaps[x] = 0; for (y = rows-1; y >= 0; y&#x2013;) { if (chains[x][y] ...

  • Page 118

    HTML5 G A ME S100Listing 4-17 Checking the board recursivelyjewel.board = (function() { ... function check(events) { ... events = events || []; if (hadChains) { events.push({ type : "remove", data : removed ...

  • Page 119

    C HA P T E R 4 B UILD ING T HE G A ME101Listing 4-18 Checking for available movesjewel.board = (function() { ... // returns true if at least one match can be made function hasMoves() { for (var x = 0; x < cols; x++) { for (var y = 0; y < rows; y++) { ...

  • Page 120

    HTML5 G A ME S102If a time comes when the player cannot swap any jewels and hasMoves() therefore returns false, the board must be automatically refilled. The refill is triggered in the check() func-tion. After the board is checked for chains, the jewels are removed, and new ones are brought in. A...

  • Page 121

    C HA P T E R 4 B UILD ING T HE G A ME103 for (x = 0; x < cols; x++) { copy[x] = jewels[x].slice(0); } return copy; } return { ... getBoard : getBoard };})();Simply calling fillBoard() doesn’t guarantee that the new board has available m...

  • Page 122

    HTML5 G A ME S104Swapping jewelsAll the functions that govern the state of the board are now in place. The only thing missing is a function that actually swaps jewels. This task is relatively straightforward. You already have the canSwap() function that tells whether the player is allowed to swap...

  • Page 123

    C HA P T E R 4 B UILD ING T HE G A ME105 function is called with either a list of events that happened after the swap or, in case of an invalid swap, with false. Listing 4-24 shows the functions that are now exposed via the board module.Listing 4-24 Returning the public methodsjewel.board = (func...

  • Page 124

    HTML5 G A ME S106allows access to the data only through a few access points, ensuring that all modifications happen in accordance with the rules of the game.This chapter also showed you how to prepare for future multiplayer functionality by shaping the module such that the game can use both the s...

  • Page 125

    Chapter 5Delegating Tasks to Web WorkersIn This Chapter■ Introducing Web Workers■ Describing major API functions■ Looking at examples■ Creating a worker-based board moduleIN THIS CHAPTER , I show you how to use Web Workers, a cool feature that came out of the Web Hypertext Application Te...

  • Page 126

    HTML5 G A ME S108that run independently from the main JavaScript thread, but in reality, the functions they call are pushed onto the same event loop that the main thread uses. One drawback is that you cannot have a function that blocks the execution and expect the browser to behave. For example, ...

  • Page 127

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S109No DOM accessAs you may have guessed, this separation of worker and parent thread also means that workers have no access to the DOM. The window and document objects simply don’t exist in the scope of the worker, and any attempt...

  • Page 128

    HTML5 G A ME S110Timeouts and intervalsThe timer functions that you know from the window object are all available in worker threads, which means that you’re free to use the following functions:■ setTimeout()■ clearTimeout()■ setInterval()■ clearInterval()If the worker is terminated, all...

  • Page 129

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S111You can create more than one worker thread. You can even create more workers that use the same script. Some tasks are well suited for parallelization, and with computers sporting more and more CPU cores, dividing intensive tasks b...

  • Page 130

    HTML5 G A ME S112To listen for messages from the worker, attach a handler to the message event:worker.addEventListener("message", function(event) { // message received from worker thread}, false);Similarly, in the worker thread, listen for the message event on the global object:addEv...

  • Page 131

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S113I don’t go into depth about shared workers here, and they aren’t used for the Jewel Warrior game. Let me just give you a short example to show how multiple pages can connect to and communi-cate with the same worker. Listing 5-...

  • Page 132

    HTML5 G A ME S114Shared workers don’t have a global message event as dedicated workers do. Instead, they must listen for connect events that fire whenever a new page creates a connection to the worker. Communication between the worker and connecting threads happens via port objects that emit me...

  • Page 133

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S115Creating the test pageBecause the loop must run to the end if the n is a prime, any sufficiently large prime number makes isPrime() hog the CPU for a while, effectively locking down the main UI thread for that page.To see that th...

  • Page 134

    HTML5 G A ME S116This simple test page features an input field with a button. When you click the check button, the value of the number field is passed to isPrime(), and the result is displayed in a message box. The default number I specified in the input field is a prime and should take a while ...

  • Page 135

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S117 }, false); worker.postMessage(n); }, false);When the check button is clicked, a new worker is created from the prime-worker.js script. The value of the number input field is converted to a number and posted to the worker u...

  • Page 136

    HTML5 G A ME S118though. Because the module was designed with multiplayer support in mind, it already has an asynchronous interface, which makes it easy to adapt to the asynchronous nature of worker messaging. It’s pure logic; it manipulates only its own internal data and doesn’t need DOM acc...

  • Page 137

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S119of the data for easy access. Listing 5-8 shows the message event handler in the board.worker.js script.Listing 5-8 The message handleraddEventListener("message", function(event) { var board = jewel.board, messa...

  • Page 138

    HTML5 G A ME S120function is called, the data parameter is sent to the main thread as a message, and it’s then up to the main thread to handle the callback message.Keeping the same interfaceNow you can put this new worker module to use. The game should be able to run with or without worker supp...

  • Page 139

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S121 messageCount, callbacks; function initialize(callback) { messageCount = 0; callbacks = []; worker = new Worker("scripts/board.worker.js"); } function post(command, data, cal...

  • Page 140

    HTML5 G A ME S122Handling responsesWhen the callback function is passed to post(), it’s entered into the callbacks array so it can be fetched whenever the worker posts a response back to the main thread. The board module listens for responses by attaching a message event handler in initialize()...

  • Page 141

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S123Listing 5-13 Exposing the public methodsjewel.board = (function() { ... return { initialize : initialize, swap : swap, getBoard : getBoard, print : print };})(); Loading the right moduleNow yo...

  • Page 142

    HTML5 G A ME S124workers is as simple as testing whether the Worker() constructor exists on the window object. Add the hasWebWorkers() function to jewel.js, as shown in Listing 5-15.Listing 5-15 Detecting support for Web Workersjewel = (function() { ... function hasWebWorkers() { re...

  • Page 143

    C HA P T E R 5 D E L E G A T ING T A SK S T O W EB W O R K E R S125Now simply preload board.worker.js when you load the board.worker-interface.js script. Listing 5-17 shows the worker script added to the loading sequence in index.html.Listing 5-17 Preloading the worker modulewindow.addEventListen...

  • Page 144

  • Page 145

    Chapter 6Creating Graphics with CanvasIn This Chapter■ Using canvas versus other methods■ Drawing with the canvas element■ Drawing paths and shapes■ Applying transformations to the canvas■ Modifying image dataTHIS CHAPTER SHOWS you how to create dynamic graphics with the canvas element....

  • Page 146

    HTML5 G A ME S128Ways to Display Graphics on the WebIn the past, all graphics on the web had to be represented by bitmap images in formats such as GIF or JPEG. More options for displaying graphics on the web are available today.Bitmap imagesBitmaps are images defined by a rectangular grid of pi...

  • Page 147

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S129The SVG format is not brand new; the development of the SVG specification began in 1999. However, only recently have all major browser vendors added native support for it. Although you’re able to modify the SVG content using DOM func...

  • Page 148

    HTML5 G A ME S130The canvas element really shines when you need fine-grained control over the output. With pixel-level data access, you can do things that aren’t possible with any other technology. One disadvantage of using canvas is that, even if many of its drawing functions are vector-based,...

  • Page 149

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S131An important concept to understand when using canvas is the context object. The canvas element doesn’t provide graphics functionality by itself. It merely defines a two-dimensional surface and exposes a few properties for setting the...

  • Page 150

    HTML5 G A ME S132Listing 6-1 Adding a rectangle pathctx.beginPath();ctx.moveTo(150, 200);ctx.lineTo(250, 200);ctx.lineTo(250, 230);ctx.lineTo(150, 230);ctx.closePath();A path is always made up of a number of subpaths. The first path function called in Listing 6-1 is ctx.moveTo(), which creates a ...

  • Page 151

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S133You can specify colors using any valid CSS color, meaning that hexadecimal format, color keywords, rgb(. . .), hsl(. . .), and so on are accepted. Aside from the color, you can also set the width of the stroke with the ctx.lineWidth pr...

  • Page 152

    HTML5 G A ME S134pixel on the left side and half a pixel on the right side. Now, that doesn’t work because there’s no such thing as half a pixel. The result is that a semitransparent 2-pixel-wide line is used instead. This result may or may not be what you want, but an easy fix is to add 0.5 ...

  • Page 153

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S135A similar shortcut exists for stroking rectangles:ctx.strokeStyle = "red";ctx.strokeRect(150, 200, 100, 30);A third variant of the rectangle function, ctx.clearRect(), takes the same four parame-ters, but instead of drawing, ...

  • Page 154

    HTML5 G A ME S136NOTEBoth startAngle and endAngle are measured in radians. The number of radians in a full circle is equal to 2π. If you’re more comfortable working with degrees, you can convert degrees to radians by multiplying by 180 divided by π.Listing 6-3 shows an example of how to draw...

  • Page 155

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S137 ctx.beginPath(); ctx.arc(200, 200, 160, 0, 2 * Math.PI, false); ctx.moveTo(200 + 180, 200); ctx.arc(200, 200, 180, 0, 2 * Math.PI, false); ctx.lineWidth = 2; ctx.strokeStyle = "black"; ctx.stroke();<...

  • Page 156

    HTML5 G A ME S138The first method, ctx.quadraticCurveTo(), adds a quadratic Bézier curve. In addition to the end point, this type of curve uses a single control point:ctx.quadraticCurveTo(cx, cy, x, y);This example adds a quadratic Bézier curve from the current position to (x, y), using the con...

  • Page 157

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S139Figure 6-3: In this quadratic Bézier curve, it’s as though the control point pulls toward the curve.The second curve method is called ctx.bezierCurveTo(). This method might as well have been named ctx.cubicCurveTo() because it crea...

  • Page 158

    HTML5 G A ME S140Figure 6-4 shows the resulting drawing. Again, I drew the control points for this figure. As you might imagine, the cubic curve gives you a lot more flexibility and can even create self-intersecting curves. This example is found in the file 04-cubicCurve.html.Figure 6-4: A cubi...

  • Page 159

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S141 ctx.beginPath(); ctx.moveTo(270,200); for (var i=0;i<=20;i++) { ctx.lineTo( 200 + Math.cos(i/10 * Math.PI) * 70 * (i%2 + 1), 200 + Math.sin(i/10 * Math.PI) * 70 * (i%2 +...

  • Page 160

    HTML5 G A ME S142If you want to reset the clipping path, you need to use the ctx.save() and ctx.restore() methods. These are covered later in this chapter. A resetClip() function has been added to the specification but is not yet implemented in any browser.Path objectsA recent addition to the 2D ...

  • Page 161

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S143point, the line is extended so the last point is positioned at the center of a square whose sides are equal to the line width. Figure 6-6 shows how the three different ctx.lineCap values alter the end of a stroke.Figure 6-6: Line cap...

  • Page 162

    HTML5 G A ME S144Extend the outer edges beyond the meeting point until the outer edges intersect. Fill the triangle defined by this miter point and the two corner points. Now, as you might imag-ine, path segments that meet at very acute angles could cause miter joints that extend far out from the...

  • Page 163

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S145Using gradientsFills and stroke styles need not be plain, solid colors. Canvas supports both linear and radial gradients. To use a gradient, you need to create a gradient object:var gradient = ctx.createLinearGradient( 50, 50, 250, ...

  • Page 164

    HTML5 G A ME S146Listing 6-8 continued ctx.fillStyle = linGrad; ctx.fillRect(0, 0, 400, 400); var radGrad = ctx.createRadialGradient( 200, 200, 25, 200, 200, 150 ); radGrad.addColorStop(0, "white"); radGrad.addColorStop(0.7, "yellow"); radGrad.add...

  • Page 165

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S147Using patternsThe last type of fill and stroke styles I discuss is patterns. You can use an existing image instead of a solid color or gradient. The image can be a regular image, a canvas element, or a video element. Start by creating ...

  • Page 166

    HTML5 G A ME S148Initially, the matrix is set to the identity matrix: 1 0 0 0 1 0 0 0 1If you’re comfortable with matrices, you can modify the transformation matrix directly using the ctx.transform() method:ctx.transform(a, b, c, d, e, f);This method multiplies the current matrix with ...

  • Page 167

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S149ctx.translate(50, 100);ctx.fillRect(120, 130, 200, 200);actually draws the rectangle with the upper-left corner in position (170, 230) on the canvas.ScalingYou can also scale the coordinate space using the ctx.scale() method. This meth...

  • Page 168

    HTML5 G A ME S150Using this method is essentially the same as applying the following transformation:ctx.transform( Math.cos(t), Math.sin(t), - Math.sin(t), Math.cos(t), 0, 0);One issue you should be aware of is that the rotation always happens around the origin. If you want to rota...

  • Page 169

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S151The ellipse() method is similar to the arc() method but takes a radius parameter for both the x- and y-axes as well as a rotation parameter. Before calling arc(), the coordinate system is translated to the center of the ellipse (x, y) ...

  • Page 170

    HTML5 G A ME S152the same logic to text on the canvas as you would to text in images. If it’s possible to get the same or a similar result using CSS, perhaps you should reconsider going for a canvas-based approach. For example, regular HTML and CSS are often better suited for elements such as h...

  • Page 171

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S153The left, center, and right values are trivial. The meaning of the start and end values depends on standard text direction of the current locale. For left-to-right locales, start is the same as left, and end is the same as right. For r...

  • Page 172

    HTML5 G A ME S154One final method exists on the context related to text. The ctx.measureText() method takes one parameter, a string, and returns a text metrics object. This object has one property, width, which is the width of text if it were to be drawn on the canvas using the current font value...

  • Page 173

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S155This example puts the shadow below and to the right of the content. Note that these are coordinate space units, so all transformations are also applied to these values. Finally, you can control the softness of the shadow with the ctx.s...

  • Page 174

    HTML5 G A ME S156Figure 6-10: Applying the shadow effect can create a three-dimensional image.Managing the state stackWith so many different properties and values that affect how content is rendered on the canvas, keeping track of old values can be hard if you need to revert to a previous state...

  • Page 175

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S157This example pushes the current state onto the stack, allowing you to safely modify any of the properties mentioned earlier. When you’re done messing around with the canvas state, you can go back to the way things were before by call...

  • Page 176

    HTML5 G A ME S158 // draw a star shape by adding horizontal lines // while rotating the coordinate space ctx.beginPath(); ctx.translate(0.5,0.5); for (i=0;i<60;i++) { ctx.rotate(1 / 60 * Math.PI * 2); ctx.lineTo(i % 2 ? 0.15 : 0.75, 0); ...

  • Page 177

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S159Note how the state is saved at the beginning and restored at the end. No matter what you do to the state in the rest of the function, the state is returned to its original form. Also note that the coordinate space is scaled using the f...

  • Page 178

    HTML5 G A ME S160Listing 6-13 The generalized path functionfunction makePath(ctx, points) { ctx.moveTo(points[0][0], points[0][1]); for (var i=1,len=points.length;i<len;i++) { ctx.lineTo(points[i][0], points[i][1]); }}The makePath() function just moves the position to the first...

  • Page 179

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S161 // restore scaling and clipping region ctx.restore(); // restore original state ctx.restore();}The drawLogo() function first translates the coordinates to place the origin in the center of the logo. This point is found by...

  • Page 180

    HTML5 G A ME S162Listing 6-15 continued // fill light grey part of "5" ctx.beginPath(); makePath(ctx, five2); makePath(ctx, five3); ctx.fillStyle = "#ebebeb"; ctx.fill(); // restore original state ctx.restore();}You can now put all these pieces together...

  • Page 181

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S163control how and where the function places the logo. You could even rotate it or draw a whole bunch of logos on the same canvas. Listing 6-17 shows an example of how to draw multiple instances of the logo.Listing 6-17 Drawing multiple l...

  • Page 182

    HTML5 G A ME S164CompositingYou’ve already seen how you can use paths to define clipping regions that mask whatever you draw on the canvas. That is not the only way you can control how content is added to the canvas.You can use the ctx.globalAlpha property, for example, to set a global alpha ch...

  • Page 183

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S165possible values for ctx.globalCompositeOperation. In the descriptions, A refers to the source content, and B refers to the destination.Table 6-1 Composite operationsValueDescriptionsource-atopRenders A on top of B but only where B is ...

  • Page 184

    HTML5 G A ME S166Figure 6-13: You use the transparency setting to create composite operations.In addition to these basic composite operations, you can also set ctx.globalComposite-Operation to one of the following blend modes:■ normal■ multiply■ screen■ overlay■ lighten■ color-dodge...

  • Page 185

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S167■ hue■ saturation■ color■ luminosityIf you’ve ever used Adobe Photoshop or a similar photo editing application, you probably already know some or all of these blend modes from the layer compositing feature in such application...

  • Page 186

    HTML5 G A ME S168The width and height properties specify the dimensions of the data contained in the data object. These values might not be the same as the dimensions of the region specified in the ctx.getImageData() call. Depending on the device and display, the actual number of pixels used behi...

  • Page 187

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S169 imageData.data[index] = r - r % block; imageData.data[index+1] = g - g % block; imageData.data[index+2] = b - b % block; imageData.data[index+3] = 255; }}ctx.putImageData(imageData, 0, 0);</script>...

  • Page 188

    HTML5 G A ME S170If you don’t alter the alpha value, the content you put back on the canvas with ctx.putIm-ageData() is transparent as well, which is probably not what you want.NOTEThe image data methods aren’t affected by any compositing, clipping, or transformation settings. Pixels are acce...

  • Page 189

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S171Understanding security restrictionsWhen it comes to image data and pixel-level access, the canvas element comes with a few security-related restrictions. Just as the XMLHttpRequest object can’t access documents on other servers, the ...

  • Page 190

    HTML5 G A ME S172Listing 6-19 continued image = new Image(); image.addEventListener("load", function() { ctx.drawImage(this, 0, 0); var cw = canvas.width, ch = canvas.height, imgData = ctx.getImageData(0,0,cw,ch), newData = ctx.getImageData...

  • Page 191

    C HA P T E R 6 CR E A T ING G R A P HI CS WI T H C A NV A S173First, an image element is created, and the canvas drawing function is attached to its load event. When the image is ready, it’s immediately drawn to the canvas so the image data can be accessed. In this example, you create two indep...

  • Page 192

    HTML5 G A ME S174SummaryIn this chapter, you got the grand tour of the canvas element. You saw pretty much all the features that the 2D drawing API has to offer, from drawing simple paths, shapes, and curves to creating advanced fills and strokes.You also saw how the image data methods let you ac...

  • Page 193

    Chapter 7Creating the Game DisplayIn This Chapter■ Adding a progress bar to the splash screen■ Creating the game display module■ Drawing the jewel board with canvasNOW THAT YOU’RE familiar with the canvas element, it’s time to put that knowledge to work. The game is sorely missing some ...

  • Page 194

    HTML5 G A ME S176Tracking Load ProgressAs the game evolves, more and more modules are added, so it’s a good idea to provide feedback to users while the resources are loading. Currently, nothing happens until all scripts are loaded and executed. Only then is the jewel.setup() function called and...

  • Page 195

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y177This function returns the current loading progress as a value between 0 and 1.Adding a progress barNow that the splash screen can access the progress value, you can also add a visual cue on the splash screen that lets the user know what’s ...

  • Page 196

    HTML5 G A ME S178} .../* Progress bar */.progress { margin : 0 auto; width : 6em; height : 0.5em; border-radius : 0.5em; overflow : hidden; border : 1px solid rgb(200,200,100);} .progress .indicator { background-color : rgb(200,200,100); height : 100%; width : 0%;}The C...

  • Page 197

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y179 $("#splash-screen .indicator")[0].style.width = p + "%"; if (p == 100) { setup(); } else { setTimeout(checkProgress, 30); } } function setup() { var dom = j...

  • Page 198

    HTML5 G A ME S180Building the Game ScreenFinally, you reach the actual game screen. Start by adding the game screen element to index.html, as shown in Listing 7-6.Listing 7-6 The game screen HTML<div id="game"> ... <div class="screen" id="game-screen&quo...

  • Page 199

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y181 }); } function setup() { // do nothing for now } function run() { if (firstRun) { setup(); firstRun = false; } startGame(); } return { run : run }; })()...

  • Page 200

    HTML5 G A ME S182 function setup() { var $ = jewel.dom.$, boardElement = $("#game-screen .game-board")[0]; cols = jewel.settings.cols; rows = jewel.settings.rows; canvas = document.createElement("canvas"); ctx = canvas.getCont...

  • Page 201

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y183 element. This information also lets you calculate jewelSize by dividing the width by the number of columns specified in the jewel.settings object. The jewel size and the num-ber of columns and rows are saved for later as they will be used ...

  • Page 202

    HTML5 G A ME S184You need to load the jewel sprite when the display module is initialized and make sure that the callback function isn’t called before the image has been loaded and is ready to be drawn on the canvas. If you call the drawImage() method on the canvas context with an image that ha...

  • Page 203

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y185Listing 7-12 Adding a background patternjewel.display = (function() { ... function createBackground() { var background = document.createElement("canvas"), bgctx = background.getContext("2d"); ...

  • Page 204

    HTML5 G A ME S186 left: 0; top: 0; width : 100%; height : 100%;} #game-screen .game-board .board { z-index : 10;} #game-screen .game-board .board-bg { z-index : 0;}Both the background canvas and board canvas are positioned using absolute, which places them on top of each other. ...

  • Page 205

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y187Filling the board with jewelsTime to draw some jewels! The display module needs a function that simply draws the entire board based on the board data. Listing 7-14 shows the new functions added to the display.canvas.js module.Listing 7-14...

  • Page 206

    HTML5 G A ME S188Triggering the initial redrawNow you just need to call the initialize() function, and when it finishes, call the first redraw(). Listing 7-15 shows the additions to the screen.game.js module.Listing 7-15 Triggering the initial redrawjewel.screens["game-screen"] = (func...

  • Page 207

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y189 <button class="pause">Pause</button> </footer> </div></div>...Figure 7-3: The game screen is loaded with jewels.The CSS rules from main.css shown in Listing 7-17 position the foo...

  • Page 208

    HTML5 G A ME S190 width : 100%;} .screen footer button { margin-left : 0.25em; margin-right : 0.25em; padding : 0 0.75em; font-family : Geo, sans-serif; font-size : 0.5em; color : rgba(200,200,100,0.5); background : rgb(10,20,0); border : 1px solid rgba(200,200,100,0.5)...

  • Page 209

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y191The code in Listing 7-18 introduces two new functions: pauseGame() and resumeGame(). You now add these functions along with a pause button in the footer.Pausing the gameThe pauseGame() and resumeGame() functions simply change the value of a...

  • Page 210

    HTML5 G A ME S192 <button class="pause">Pause</button> </footer> <div class="pause-overlay"> <div class="pause-text">Pause</div> </div> </div></div>The CSS rules in Li...

  • Page 211

    C HA P T E R 7 CR E A T ING T HE G A ME D I S P L A Y193Listing 7-22 Binding the pause event handlersjewel.screens["game-screen"] = (function() { ... function startGame() { ... paused = false; var dom = jewel.dom, overlay = dom.$("#game-screen ...

  • Page 212

    HTML5 G A ME S194Figure 7-4: The screen dims when the user pauses the game.SummaryThis chapter started with the game display, and the basic display routines for rendering the game board are now in place. You used the canvas element to put some jewels on the screen. In the beginning of the chapte...

  • Page 213

    Chapter 8Interacting with the GameIn This Chapter■ Capturing user input■ Working with touch events■ Binding inputs to actions■ Adding visual feedback to actionsIN THE PREVIOUS chapter, you implemented the first parts of the game display. So far, the display is just a static rendering of t...

  • Page 214

    HTML5 G A ME S196Capturing User InputI’m sure you’re more than familiar with basic keyboard and mouse events in desktop brows-ers, so here I focus on the more interesting topic of how these events behave on mobile devices with touch screens.Mouse events on touch devicesTouch-enabled devices ...

  • Page 215

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME197You don’t have much control over this keyboard. There’s no nice and easy way to disable it, and you can’t force it to pop up either. If you really need to be able to toggle the keyboard manually, you can place an input field out of view ...

  • Page 216

    HTML5 G A ME S198Listing 8-1 continued// toggle keyboard on clickdocument.getElementById("toggleButton").addEventListener( "click", toggleKeyboard, false);</script>In general, I advise against using the keyboard for anything other than text input. Not only is its func...

  • Page 217

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME199 coordinate properties used in regular mouse event objects—that is, clientX/Y, screenX/Y, and so on. The example in Listing 8-2 shows how to retrieve the coordinates of the touch event. You can find the example in the file 02-touch.html.List...

  • Page 218

    HTML5 G A ME S200Listing 8-3 Multitouch drag<div id="dragme1"></div><div id="dragme2"></div><script> var el1 = document.getElementById("dragme1"), el2 = document.getElementById("dragme2"); el1.addEventListe...

  • Page 219

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME201Another common feature in mobile applications is the two-finger, pinch-zoom gesture. When two fingers touch the screen and move either toward or away from each other, you can use the relative change in distance as a scaling factor. You can app...

  • Page 220

    HTML5 G A ME S202Listing 8-4 continued function endZoom() { this.removeEventListener("touchmove", zoom); this.removeEventListener("touchend", endZoom); } this.addEventListener("touchmove", zoom, false); this.addEvent...

  • Page 221

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME203Listing 8-5 Gesture-based zoom and rotate<div id="mydiv"></div><script> var el = document.getElementById("mydiv"); el.addEventListener("gesturestart", gestureStart, false); function ge...

  • Page 222

    HTML5 G A ME S204If you use Chrome, it’s even easier to simulate touch events. Open the DevTools settings by clicking the “gear” icon in the lower right corner. In the “Overrides” section you can enable emulation of touch events, among other things. The mouse pointer now acts like a tou...

  • Page 223

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME205 e.preventDefault(); }, false); canvas.addEventListener("mousemove", hitTest, false); function hitTest(e) { var rect = canvas.getBoundingClientRect(), x = e.clientX - rect.left, y = e.cli...

  • Page 224

    HTML5 G A ME S206The path property is a path object and is optional. If no path object is given, the current path is used. When the hit region is added, you can simply attach a listener to, for example, the click event, and if the user clicks inside a hit region, the relevant region ID will be av...

  • Page 225

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME207element is undefined. The gamepad objects in both types of lists are relatively simple and have the following properties:■ id■ index■ timestamp■ connected■ mapping■ axes■ buttonsThe id property is a string identifying the gamepad...

  • Page 226

    HTML5 G A ME S208Button IndexButton (Chrome)Button (Firefox)7Right triggerStart8BackLeft stick9StartRight stick10Left stick11Right stick12D-pad up13D-pad down14D-pad left15D-pad rightAs you can see, Firefox doesn’t map buttons for the triggers and the D-pad. These are treated as axes instead. T...

  • Page 227

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME209gamepad object is passed to the event handler in the gamepad property on the event object. Unfortunately, only Firefox currently supports these events.window.addEventListener("gamepadconnected", function(e) { alert("You conne...

  • Page 228

    HTML5 G A ME S210Listing 8-7 continued gamepadConnected(gamepad); } } else { gamepadConnected(gamepad); } updateGamepadState(gamepad); } }}This function can be called repeatedly with, for example, setInter...

  • Page 229

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME211timestamp property on the gamepad objects is implemented in all browsers, you can use it to determine whether you need to update the state at all. Until then, you need to update it every time. Listing 8-9 shows this function.Listing 8-9 Updat...

  • Page 230

    HTML5 G A ME S212Listing 8-10 The input modulejewel.input = (function() { var inputHandlers; function initialize() { inputHandlers = {}; } function bind(action, handler) { // bind a handler function to a game action } function trigger(action) { // trigger...

  • Page 231

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME213To create control bindings between input events and game actions, you give each input a keyword. For example, mouse clicks have the input keyword CLICK, a press of the Enter key has the keyword KEY_ENTER, and so on. The controls structure is s...

  • Page 232

    HTML5 G A ME S214functions associated with that action. For example, inputHandlers["selectJewel"] holds all the functions you need to call when the selectJewel action happens.The other empty function, trigger(), does the function calling. You will implement this function later in this c...

  • Page 233

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME215The DOM event object is passed on to a second function, handleClick(), along with the name of the game action. This behavior happens so that the same logic can be reused for touch events. The handleClick() function calculates the relative coor...

  • Page 234

    HTML5 G A ME S216Listing 8-14 Capturing touch inputjewel.input = (function() { ... function initialize() { var dom = jewel.dom, $ = dom.$, board = $("#game-screen .game-board")[0]; inputHandlers = {}; dom.bind(board, "mousedown"...

  • Page 235

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME217Listing 8-15 Adding key codesjewel.input = (function() { var keys = { 37 : "KEY_LEFT", 38 : "KEY_UP", 39 : "KEY_RIGHT", 40 : "KEY_DOWN", 13 : "KEY_ENTER", ...

  • Page 236

    HTML5 G A ME S218Gamepad inputYou can use the polling technique discussed earlier in this chapter to add gamepad support to the input module. First, you need to detect whether gamepads are supported by the browser; if they are, you start polling for changes. Listing 8-17 shows the changes to inpu...

  • Page 237

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME219The initialize() function simply uses the getGamepads() function for feature detec-tion. If getGamepads() returns anything, you can assume gamepad support and use setInterval() to start continuously calling pollGamepads(). You can simply copy ...

  • Page 238

    HTML5 G A ME S220Listing 8-19 continued controls = jewel.settings.controls, button = gpButtons[buttonIndex]; if (button && controls[button]) { trigger(controls[button]); } } function gamepadAxisChange(gamepad, axisIndex, axisValue) { ...

  • Page 239

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME221Listing 8-20 Initializing the cursorjewel.screens["game-screen"] = (function() { var firstRun = true, paused, cursor; function startGame() { var board = jewel.board, display = jewel.display; ...

  • Page 240

    HTML5 G A ME S222Selecting jewelsThe input module can trigger the following actions:■ selectJewel■ moveLeft■ moveRight■ moveUp■ moveDownThe selectJewel action selects a jewel on the board or, if possible, swaps two jewels in case another jewel is already selected. The move* actions move...

  • Page 241

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME223 setCursor(x, y, true); } } else { setCursor(x, y, true); } } ...})();If another jewel was already selected, you can use the distance between the two jewels to determine the appropriate ...

  • Page 242

    HTML5 G A ME S224Listing 8-23 continued break; case "remove" : display.removeJewels(boardEvent.data, next); break; case "refill" : display.refill(boardEvent.data, next); ...

  • Page 243

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME225Listing 8-24 Moving the cursorjewel.screens["game-screen"] = (function() { ... function moveCursor(x, y) { var settings = jewel.settings; if (cursor.selected) { x += cursor.x; y += cursor.y; ...

  • Page 244

    HTML5 G A ME S226Listing 8-25 continued function moveRight() { moveCursor(1, 0); } ...})();Binding inputs to game functionsWith both the game functions and input events defined, you can return to the input module in input.js and bind the two sets together in the inputHandlers obj...

  • Page 245

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME227 for (var i=0;i<handlers.length;i++) { handlers[i].apply(null, args); } } } ...})();If handlers are bound to the specified action—that is, if a property with that name is on the inputHand...

  • Page 246

    HTML5 G A ME S228You can now interact with the game, but clicking the jewels gives no visual feedback and try-ing to swap jewels will likely produce errors. It’s time to make the board display react to your input.Rendering the cursorThe input module is now properly linked to the game mechanics...

  • Page 247

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME229 renderCursor(); } return { initialize : initialize, redraw : redraw, setCursor : setCursor };})();The clearCursor() function clears the jewel at the cursor position and redraws the jewel. Listing 8-30 sho...

  • Page 248

    HTML5 G A ME S230Listing 8-31 continued function renderCursor() { if (!cursor) { return; } var x = cursor.x, y = cursor.y; clearCursor(); if (cursor.selected) { ctx.save(); ctx.globalCompositeOperation = "lig...

  • Page 249

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME231The cursor is now automatically updated and rendered when the user moves it or selects a jewel. Figure 8-1 shows what the cursor looks like.Figure 8-1: The currently selected jewel is now highlighted.Reacting to game actionsThe player can n...

  • Page 250

    HTML5 G A ME S232Listing 8-33 Temporary display functionsjewel.display = (function() { ... function moveJewels(movedJewels, callback) { var n = movedJewels.length, mover, i; for (i=0;i<n;i++) { mover = movedJewels[i]; clearJewel(mover.fromX,...

  • Page 251

    C HA P T E R 8 IN T E R A CT ING WI T H T HE G A ME233Try loading the game. You can now select jewels and swap them to form chains using mouse, touch, and keyboard input. You may find it difficult to follow the board reactions because the changes happen instantly, but you’ll deal with that prob...

  • Page 252

  • Page 253

    Chapter 9Animating Game GraphicsIn This Chapter■ Creating animation cycles■ Making animations for game actions■ Adding score and level UI elements■ Animating the game timerYOUR GAME IS now developed to the point that a player can select and swap jewels. It still needs a lot of polish, tho...

  • Page 254

    HTML5 G A ME S236Making the Game ReactSo far, you’ve dealt with only the player’s actions. In addition, the game must react to what the player does. Most importantly, the display needs to be updated so the player can make her next move. Although you’re able to make all the changes instantl...

  • Page 255

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS237This new API is supported in all current versions of the common desktop browsers as well as mobile Safari (beginning with iOS 6) and Android (beginning with Android 4.4). The most important function is the requestAnimationFrame() function, which...

  • Page 256

    HTML5 G A ME S238Listing 9-1 Polyfill for requestAnimationFrame()window.requestAnimationFrame = (function() { var startTime = Date.now(); return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(ca...

  • Page 257

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS239Listing 9-3 A simple animation with setTimeout()function animate() { var element = document.getElementById("anim"), time = Date.now(); // element is assumed to have position:absolute element.style.left = (50 + Math.cos...

  • Page 258

    HTML5 G A ME S240Listing 9-5 A simple animation with Mozilla eventsfunction animate(event) { var element = document.getElementById("anim"), time = event.timeStamp; element.style.left = (50 + Math.cos(time / 500) * 25) + "%"; element.style.top = (50 + Math.sin(...

  • Page 259

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS241Creating an animation cycle is as simple as that. The cycle() function doesn’t do anything interesting yet; it simply schedules another cycle. The initial call in setup() starts the cycle. Note that it also keeps track of the time of the previ...

  • Page 260

    HTML5 G A ME S242Note that Math.sin()creates the t1 and t2 factors. You can use sines and cosines for many things with animations. Here, the Math.sin() function provides an easy way to create values that vary over time, going smoothly from -1 to +1 and back, as shown in Figure 9-1. If you add 1...

  • Page 261

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS243The cursor now automatically updates in each cycle. Also, remember to remove the old renderCursor() call from the setCursor() and redraw() functions.Animating game actionsNext, you must handle five different game animations:■ Moving jewels■...

  • Page 262

    HTML5 G A ME S244Each animation is added to the list as a simple object structure describing the start time, the time it takes to finish, and the fncs property, which holds references to three functions: fncs.before(), fncs.render(), and fncs.done(). These functions are called at various times wh...

  • Page 263

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS245 function cycle() { var time = Date.now(); // hide cursor while animating if (animations.length === 0) { renderCursor(time); } renderAnimations(time, previousCycle); previousCycle = time; ...

  • Page 264

    HTML5 G A ME S246Now expand the swap() function in board.js so it generates these extra events. Listing 9-10 shows the new swap() function in board.js.Listing 9-10 Generating move events for invalid swapsjewel.board = (function() { ... function swap(x1, y1, x2, y2, callback) { var tm...

  • Page 265

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS247The swap() function now adds a move event to the initial events array so the jewels switch places. If the canSwap() test fails, a second event is added to move the jewels back.The moveJewels() function is passed an array of jewel objects describ...

  • Page 266

    HTML5 G A ME S248Listing 9-11 continued if (­n == 0) { cursor = oldCursor; callback(); } } }); }); } ...})();The main portion of the moveJewels() code iterates through all t...

  • Page 267

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS249Removing jewelsThe procedure for removing jewels is similar to the one in moveJewels(). The removeJewels() function is passed a list of objects that describe the jewels that need to disappear. Each object has these properties:■ type■ x■ y...

  • Page 268

    HTML5 G A ME S250As you can see, the drawJewel() call in render() now has new fourth and fifth arguments. These arguments are the scale and rotation that you want to apply to the jewel before drawing it. Listing 9-13 shows the changes to the drawJewel() function in display.canvas.js.Listing 9-...

  • Page 269

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS251TIPNow that you can add a scaling factor when drawing jewels, try adding a scale value of 1.1 or so in the renderCursor() function. The result is a more glowing appearance.Refilling the boardWhen the board module detects that no valid moves are...

  • Page 270

    HTML5 G A ME S252The rotation is done with a 3D CSS transformation. The CSS rotateX(), rotateY(), and rotateZ() transformations all rotate the element a number of degrees around their axes. The jewel.dom.transform() function is just a shortcut for the vendor-specific versions. Add the function to...

  • Page 271

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS253Figure 9-3: This animation flips the board.To test the refill animation without having to play until a refill is automatically triggered, you trigger the animation manually by entering the following into the JavaScript console:jewel.display.ref...

  • Page 272

    HTML5 G A ME S254Listing 9-15 Initializing the game info and starting the gamejewel.screens["game­screen"] = (function() { var gameState, ... function startGame() { var board = jewel.board, display = jewel.display; gameState = { level : ...

  • Page 273

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS255 <label class="score">Score: <span></span></label> </div> <div class="time"><div class="indicator"></div></div> ... </div&g...

  • Page 274

    HTML5 G A ME S256The new CSS rules aren’t particularly interesting. They simply arrange the elements below the game board and style the time bar to look a bit like the progress bar on the splash screen. Figure 9-4 shows the new elements.Figure 9-4: The new UI elements. The jewels appear above...

  • Page 275

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS257 #game­screen .game­info { width : auto; height : 2em; white­space : nowrap; } #game­screen .game­info label { font­size : 0.5em; } #game­screen .game­info .score { float : left; ...

  • Page 276

    HTML5 G A ME S258Figure 9-5: The game UI elements automatically adjust to landscape mode.You can now update these elements with the current values. First, they should be updated at the beginning of the game, so create an updateGameInfo() function that updates the score and level elements as show...

  • Page 277

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS259The updateGameInfo() call in startGame() resets the display to the initial values when a new game starts.Creating the game timerNow you can move on to the game timer. When the game starts, the timer must slowly count down, and when it reaches t...

  • Page 278

    HTML5 G A ME S260Listing 9-20 continued var delta = gameState.startTime + gameState.endTime ­ Date.now(), percent = (delta / gameState.endTime) * 100, progress = $("#game­screen .time .indicator")[0]; if (delta < 0) { ...

  • Page 279

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS261Pausing the gameThe pause button doesn’t actually temporarily stop the game yet. It needs to halt both the game timer and any animations that may be playing. If you simply choose not to update the animations and the timer while the game is p...

  • Page 280

    HTML5 G A ME S262Listing 9-21 continued function moveCursor(x, y) { if (paused) { return; } ... } ...})();To pause the animations, you add pause and resume functions to the display module. These functions don’t need to track the time because they can sim...

  • Page 281

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS263 function resume(pauseTime) { paused = false; for (var i=0;i<animations.length;i++) { animations[i].startTime += pauseTime; } } return { ... pause : pause, resume : resume }})(...

  • Page 282

    HTML5 G A ME S264Listing 9-23 continued case "refill" : display.refill(boardEvent.data, next); break; case "score" : // new score event addScore(boardEvent.data); next(); ...

  • Page 283

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS265Listing 9-25 Checking the number of pointsjewel.screens["game­screen"] = (function() { ... function addScore(points) { var settings = jewel.settings, nextLevelAt = Math.pow( settings.baseLevelSco...

  • Page 284

    HTML5 G A ME S266Listing 9-26 Advancing to the next leveljewel.screens["game­screen"] = (function() { ... function startGame() { ... updateGameInfo(); board.initialize(function() { display.initialize(function() { display.redraw(boar...

  • Page 285

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS267Listing 9-27 Adding a visual effect when the level changesjewel.display = (function() { ... function levelUp(callback) { addAnimation(1000, { before : function(pos) { var j = Math.floor(pos * rows * 2), ...

  • Page 286

    HTML5 G A ME S268Because pos goes from 0 to 1, j is an integer value that starts at 0 and ends at (2 * rows). The loop starts at y=0 and x=j. It then moves down the board, and at every row, it moves the x position one step to the left. The result is that the matching jewels form a diagonal row th...

  • Page 287

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS269 top : 50%; margin­top : ­0.5em; width : 100%; font­family : Slackey, sans­serif; color : rgb(150,150,75); text­shadow : 0.03em 0.03em 0.03em rgb(255,255,0), ­0.03em ­0.03em 0.03em rgb(255,255,0), ...

  • Page 288

    HTML5 G A ME S270Listing 9-30 continued/* zoom­fade animation class */.zoomfade { animation­name : zoomfade; animation­duration : 2s; ­webkit­animation­name : zoomfade; ­webkit­animation­duration : 2s; ­moz­animation­name : zoomfade; ­moz­animation­duration : 2s;}...

  • Page 289

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS271Listing 9-32 Announcing the next leveljewel.screens["game­screen"] = (function() { ... function advanceLevel() { gameInfo.level++; announce("Level " + gameState.level); ... } ...}Figure 9-6 ...

  • Page 290

    HTML5 G A ME S272While you’re at it, add an announcement when the game board is refilled. You can add the announce() call in playBoardEvents(), as shown in Listing 9-33.Listing 9-33 Announcing the refill eventjewel.screens["game­screen"] = (function() { ... function playBoardEv...

  • Page 291

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS273Listing 9-34 The game over animationjewel.display = (function() { ... function gameOver(callback) { addAnimation(1000, { render : function(pos) { canvas.style.left = 0.2 * pos * (Math.ran...

  • Page 292

    HTML5 G A ME S274Listing 9-35 Setting up the explosionjewel.display = (function() { ... function explode(callback) { var pieces = [], piece, x, y; for (x=0;x<cols;x++) { for (y=0;y<rows;y++) { piece = { t...

  • Page 293

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS275calls the explodePieces()function, which moves all the pieces and also applies a gravity effect to the pieces, forcing them to come down. The explodePieces() function needs both the pos and delta values to be able to move the pieces just the rig...

  • Page 294

    HTML5 G A ME S276The explodePieces() function does two things. First, it alters the position and velocity of all the jewel pieces. It then renders each of them on the now-blank canvas.The velocity is changed by adding a constant multiplied by the delta. This change in velocity simulates the effec...

  • Page 295

    C HA P T E R 9 A NIM A T ING G A ME G R A P HI CS277SummaryThe game experience of Jewel Warrior is enhanced immensely with the help of a few animated effects in the right places. In this chapter, you learned how to set up an animation cycle using the new animation timing API, and you used it to ...

  • Page 296

  • Page 297

    Chapter 10 Creating Audio for GamesChapter 11 Creating 3D Graphics with WebGLPart IIIAdding 3D and Sound

  • Page 298

  • Page 299

    Chapter 10Creating Audio for GamesIn This Chapter■ Introducing HTML5 audio■ Dealing with audio formats■ Using the Web Audio API■ Implementing an audio module■ Adding sound effects to the gameNOW THAT THE visual aspect of the game is taken care of, you can turn to adding audio. This chap...

  • Page 300

    HTML5 G A ME S282HTML5 AudioIn the early days of the web, there was no way to put sound on web pages, nor was there a need for it because the web was largely just a way to display documents. However, with the games and applications being produced today, it’s suddenly a feature that makes sense....

  • Page 301

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S283 // HTML5 audio is supported} else { // Load fallback code}If you need a good fallback solution, I recommend Scott Schiller’s excellent Sound Manager 2, available aactionURI(http://www.schillmania.com/projects/soundmanager2):t www.sch...

  • Page 302

    HTML5 G A ME S284As Table 10-1 shows, no format is universally supported. Firefox can play MP3 and AAC audio but relies on the operating system to support it, which means only on Windows Vista/7+ and Android for now. Internet Explorer supports WebM only with a plug-in. To get audio working relia...

  • Page 303

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S285if (canPlayMP3 == "probably") { ... // browser is confident that it can play MP3}if (canPlayMP3 == "probably" || canPlayMP3 == "maybe") { ... // there's a chance that it can play MP3}Note that, because the ...

  • Page 304

    HTML5 G A ME S286Using the audio ElementYou can create audio elements either by adding them to the HTML markup or by creating them with JavaScript. Adding an audio element to the HTML is as simple as using<audio src="mysound.mp3" />Just like the canvas element, the audio element ...

  • Page 305

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S287Figure 10-1: These audio elements can be rendered with native controls in Firefox (top), Chrome (middle), and Internet Explorer (bottom).As you can see, the overall appearance is the same, although the default dimensions vary a bit. If neces...

  • Page 306

    HTML5 G A ME S288The metadata value makes the browser load only enough data that it knows the duration of the audio file. If the preload attribute is set to auto or if the attribute is absent, the browser decides for itself what gives the best user experience. This includes potentially loading th...

  • Page 307

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S289If you specify both an src attribute on the audio element and add source child elements, the src attribute takes precedence. Only the audio source specified by the src attribute is considered; the source elements are disregarded, even if the...

  • Page 308

    HTML5 G A ME S290A common usage pattern is to make a sound loop back to the beginning and continue playing when it reaches the end. To make an audio clip loop, simply add the Boolean loop attribute to the audio element:<audio src="mysound.mp3" loop />You can also set the loop prop...

  • Page 309

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S291audio.volume = 0.75; // effective volume = 0.75;audio.muted = true; // effective volume = 0.0;...audio.muted = false; // effective volume = 0.75;Because mute is a Boolean, toggling between the two states is as easy as setting mute to its neg...

  • Page 310

    HTML5 G A ME S292Creating custom UI controlsSometimes, you may want to provide your own custom UI elements for controlling the audio playback. Perhaps the style of the native controls doesn’t fit with your application; perhaps you just want more control over their behavior. As you’ve probably...

  • Page 311

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S293$("button.stop")[0].addEventListener("click", function() { audio.pause(); audio.currentTime = 0;}, false); $("button.mute")[0].addEventListener("click", function() { audio.muted = !audio.muted;...

  • Page 312

    HTML5 G A ME S294One of the issues concerns volume control. As you’ve now learned, the audio element has its own volume value that you can use to control the volume of that specific audio clip. On iOS devices, audio elements always play at full volume, and you can’t change the volume value. T...

  • Page 313

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S295Using the Web Audio APIThe basic concept of the Web Audio API revolves around audio contexts and audio nodes. You can use many different types of audio nodes. Some have both inputs and outputs and transform the data in a specific way—for e...

  • Page 314

    HTML5 G A ME S296// create a GainNode that lowers the gain/volume to 0.8var gain = context.createGain();gain.gain.value = 0.8;Audio nodes connect to each other using the connect() function:source.connect(gain);When the audio has been routed through all the nodes you want, connect the output of th...

  • Page 315

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S297 <source src="steps.mp3" type="audio/mpeg" /> <source src="steps.ogg" type="audio/ogg; codecs='vorbis'" /></audio>The canvas is used to draw the sound positions relative to the l...

  • Page 316

    HTML5 G A ME S298Listing 10-7 Initializing and updating positionsvar soundPos1 = [Math.random() * 512, Math.random() * 512], soundPos2 = [Math.random() * 512, Math.random() * 512], listenPos = [256, 256]; function updatePositions() { context.listener.setPosition(listenPos[0], listenPos[1...

  • Page 317

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S299canvas.addEventListener("mousedown", function(e) { mouseIsDown = true; update(e); e.preventDefault();}, false); canvas.addEventListener("mouseup", function(e) { mouseIsDown = false;}, false); canvas.addEventLis...

  • Page 318

    HTML5 G A ME S300This function simply clears the canvas and draws the listener as a circle and each of the sounds as smaller, filled circles. Find the full example in the file 02-webaudio.html in the archive for this chapter.Building the Audio ModuleNow that you’ve seen how easy it is to use a...

  • Page 319

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S301 function formatTest() { var audio = new Audio(), types = [ ["ogg", "audio/ogg; codecs='vorbis'"], ["mp3", "audio/mpeg"] ]; for (var ...

  • Page 320

    HTML5 G A ME S302 sounds = {}; } function createAudio(name) { var el = new Audio("sounds/" + name + "." + extension); sounds[name] = sounds[name] || []; sounds[name].push(el); return el; } ...})();The createAudio() function has...

  • Page 321

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S303Listing 10-14 The play functionjewel.audio = (function() { var extension, sounds, activeSounds; function initialize() { extension = formatTest(); if (!extension) { return; } sounds =...

  • Page 322

    HTML5 G A ME S304 activeSounds[i].stop(); } activeSounds.length = 0; } return { initialize : initialize, play : play, stop : stop }; })();Cleaning upYou have one more thing left to do. When a sound starts, it’s added to the activeSounds ar...

  • Page 323

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S305Because you don’t keep track of where in the activeSounds array the audio element exists, the easiest approach is to do a blanket removal of any audio element that has ended. The elements are removed by using the splice() method, which modi...

  • Page 324

    HTML5 G A ME S306Playing sound effects is now as simple as adding audio.play() calls wherever you need them, as shown in Listing 10-18.Listing 10-18 Adding sound effectsjewel.screens["game-screen"] = (function() { ... function advanceLevel() { jewel.audio.play("levelup...

  • Page 325

    C HA P T E R 10 CR E A T ING A UD I O F O R G A ME S307Nevertheless, the level of support in modern desktop browsers has reached a level where you can confidently use HTML5 audio. The last part of this chapter showed you how to make an audio module and use it to add sound effects to Jewel Warrior...

  • Page 326

  • Page 327

    Chapter 11Creating 3D Graphics with WebGLYOU ARE ALREADY familiar with drawing 2D graphics with the canvas element. In this chapter, you move forward and use 3D graphics and the WebGL context. You find out enough about the WebGL API to render simple 3D scenes with lighting and textured objects.I...

  • Page 328

    HTML5 G A ME S3103D for the WebThe canvas element is designed so that the actual functionality is separate from the ele-ment. A so-called context provides all graphics functionality. In Chapter 6, you drew graphics on the canvas using a path-based API provided by the 2D context. WebGL extends th...

  • Page 329

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL311described by three points, where each point, also called a vertex, is a three-dimensional vec-tor. Put two triangles together to form a rectangle, put six squares together and you have a cube, and so on.WebGL stores this 3D geometry in...

  • Page 330

    HTML5 G A ME S312error has occurred. This function returns the value 0 if there are no errors or a WebGL error code indicating the type of error:var error = gl.getError();if (error != 0) { alert("An error occurred: " + error);}Putting code like this after every WebGL function call ca...

  • Page 331

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL313 return gl; } return { createContext : createContext };})();As you progress through this chapter, you add more and more functions to the module.NOTEI don’t list the complete code for the examples and the WebGL...

  • Page 332

    HTML5 G A ME S314As in JavaScript, you can also assign an initial value:data_type variable_name = init_value;GLSL introduces several data types that aren’t available in JavaScript. One data type that does behave the same in both JavaScript and GLSL is the Boolean type called bool:bool mybool = ...

  • Page 333

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL315This example combines the x and y components of the vec2 with a z value of 3.0 to create a new vec3 vector. You can use this capability for many things—for example, converting RGB color values to RGBA:vec3 myColor = vec3(1.0, 0.0, 0....

  • Page 334

    HTML5 G A ME S316If you use the multiplication operator on two vectors, the result is a component-wise multi-plication of the vectors:vec2 v0 = vec2(3.5, 4.0);vec2 v1 = vec2(2.0, 0.5);vec2 v2 = v0 * v1; // = vec2(3.5 * 2.0, 4.0 * 0.5) // = vec2(7.0, 2.0)The dot product can be ca...

  • Page 335

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL317SwizzlingA neat feature of GLSL vector types is swizzling. This feature enables you to extract multiple components of a vector and have them returned as a new vector. Suppose you have a three-dimensional vector and you want a two-dimen...

  • Page 336

    HTML5 G A ME S318MatricesMatrices also have their own types, mat2, mat3, and mat4, which let you work with 2x2, 3x3, and 4x4 matrices. Only square matrices are supported. Matrices are initialized much like vectors by passing the initial values to the constructor:mat2 myMat2 = mat2( 1.0, 2.0, ...

  • Page 337

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL319It’s also possible to multiply a matrix and a vector with matching dimensions, producing a new vector:vec2 v0 = vec2(2.5, 4.0);mat2 m = mat2( 3.5, 7.0, 2.0, 5.0);vec v1 = v0 * m; // = vec2( // m[0].x * v0....

  • Page 338

    HTML5 G A ME S320Vertex shadersThe vertex shader runs its code for each of the vertices in the buffer. Listing 11-2 shows a simple vertex shader.Listing 11-2 A basic vertex shaderattribute vec3 aVertex; void main(void) { gl_Position = vec4(aVertex, 1.0);}This simple shader declares an attribut...

  • Page 339

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL321You’re probably wondering about the first three lines in Listing 11-3. The OpenGL ES version of GLSL requires that fragment shaders specify the precision of float values. Three precisions are available: lowp, mediump, and highp. You...

  • Page 340

    HTML5 G A ME S322 " precision highp float;\r\n" + "#endif\r\n" + "void main(void) {\r\n" + " gl_FragColor = vec4(0.7, 1.0, 0.8, 1.0); \r\n" + "}\r\n";You can add \r\n at the end of each line to include line breaks in the sourc...

  • Page 341

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL323Listing 11-4 shows these calls combined to form the first function for the WebGL helper module.Listing 11-4 Creating shader objectsjewel.webgl = (function() { ... function createShaderObject(gl, shaderType, source) { var s...

  • Page 342

    HTML5 G A ME S324 throw gl.getProgramInfoLog(program);}Listing 11-5 shows these function calls combined to form the createProgramObject() function for the WebGL helper module.Listing 11-5 Creating program objectsjewel.webgl = (function() { ... function createProgramObject(gl, vs, fs) { ...

  • Page 343

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL325Uniform variablesIf you need to set values that are global to the entire group of vertices or pixels currently being rendered, you can use uniform variables. The value of a uniform variable is set with JavaScript and doesn’t change u...

  • Page 344

    HTML5 G A ME S326 1.6, 2.0, 9.2, 3.4]);The uniform[1234]i() and uniform[1234]fv() forms allow you to update integer values.Matrix values are set with the functions of the form uniformMatrix[234]fv():gl.uniformMatrix3fv(location, false, [ 4.3, 6.5, 1.2, 2.3, 7.4, 0.9, 5.5, 4.2, 3.0]...

  • Page 345

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL327In the example in Listing 11-7, the position of the vertex determines the color value assigned to the vColor variable. The variable is declared as varying, making it accessible in the frag-ment shader as shown in Listing 11-8.Listing 1...

  • Page 346

    HTML5 G A ME S328This method makes WebGL compare the distances between the objects and the point of view so that elements that are farther away don’t appear in front of closer objects. The gl.DEPTH_TEST argument passed to gl.enable() is a constant numeric value. WebGL has many of these constant...

  • Page 347

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL329The data is passed to gl.bufferData() as a Float32Array typed array object. This pro-cess is generic enough that you can add it to the webgl.js helper module. Listing 11-9 shows the gl.createFloatBuffer() function.Listing 11-9 Creating...

  • Page 348

    HTML5 G A ME S330var vbo = webgl.createFloatBuffer(gl, [ -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, 0.0]);You then need to declare how these vertices are used to create the triangles. You do this with an index buffer, which is a list of indices into the vertex list...

  • Page 349

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL331Using models, views, and projectionsSimply defining the model data isn’t enough to render it in any meaningful way. You also need to transform the vertices so that the object is rendered at the desired position in the world with the ...

  • Page 350

    HTML5 G A ME S332 ]; } ...})();The identity matrix is all zeroes with a main diagonal of ones and will be the starting point of the model-view matrix.var mvMatrix = createIdentityMat4();Again, if you’re not comfortable with matrices and vectors, I recommend paying a visit to linear...

  • Page 351

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL333Listing 11-13 Matrix rotationjewel.webgl = (function() { ... function rotateMat4(M, A, axis) { var x = axis[0], y = axis[1], z = axis[2], axisLength = Math.sqrt(x*x + y*y + z*z), sA = Math.sin(A), ...

  • Page 352

    HTML5 G A ME S334The rotateMat4() function adds a rotation transformation by setting up a rotation matrix using the specified angle, A, and axis, and then multiplying that matrix with the matrix M. The angle must be given in radians, not degrees.rotateMat4(mvMatrix, Math.PI / 4, [0, 1, 0]);You ca...

  • Page 353

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL335Listing 11-15 Projection matrix helper functionjewel.webgl = (function() { ... function createPerspectiveMat4(fov, aspect, near, far) { var f = 1.0 / Math.tan(fov * Math.PI / 360), nf = 1 / (near - far); ...

  • Page 354

    HTML5 G A ME S336Matrices in the vertex shaderTo use the two matrices in the vertex shader, you can add the uniform declarations for uModelView and uProjection:uniform mat4 uModelView;uniform mat4 uProjection;To transform the vertex position, multiply it by both matrices. Because they are 4x4 ma...

  • Page 355

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL337In this example, the model-view matrix is updated each frame to adjust the rotation. The rotation applied to the matrix is based on the current time, so the object will rotate at an even rate, regardless of how often the cycle runs. Af...

  • Page 356

    HTML5 G A ME S338Drawing the vertex dataNow you’re ready to draw some shapes. Before the vertex data is available to the vertex shader through the aVertex attribute, you must activate the vertex buffer. First, make sure the vertex buffer is bound to the gl.ARRAY_BUFFER target:gl.bindBuffer(gl....

  • Page 357

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL339Combine these calls, and you get a draw() function like the one shown in Listing 11-18.Listing 11-18 Drawing the objectfunction draw() { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.viewport(0, 0, canvas.width, canvas....

  • Page 358

    HTML5 G A ME S340Other rendering modesRendering modes other than gl.TRIANGLES are available. WebGL can also render points and lines, and it has modes that interpret the vertex data in different ways. The available rendering modes are■ TRIANGLES■ TRIANGLE_STRIP■ TRIANGLE_FAN■ POINTS■ LIN...

  • Page 359

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL341Loading Collada modelsSpecifying all the vertex and index values manually is feasible only for simple shapes, such as cubes, planes, or other basic shapes. It’s better to import complex objects that require many triangles from extern...

  • Page 360

    HTML5 G A ME S342 return { loadModel : loadModel, ... };})();When the file finishes loading, the XML document is available in the responseXML prop-erty of xhr. This document is passed on to a webgl.parseCollada()function, which must parse the XML document and create the neces...

  • Page 361

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL343enhance the rendering with textures and lighting effects. The example in the file 02- collada.html uses the Collada loading code to load and render a model of a sphere. The resulting image is shown in Figure 11-2.Figure 11-2: This sp...

  • Page 362

    HTML5 G A ME S344Adding lightYou can use many different methods to apply lighting to a 3D scene, ranging from relatively simple approximations to realistic but complex mathematical models. I stick to a simple solution called Phong lighting, which is a common approximation of light reflecting off ...

  • Page 363

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL345In the vertex shader, you access the vertex normals through an attribute variable, just as you access the vertices themselves:attribute vec3 aNormal;You also activate and enable the normal buffer in the same way you do the vertex buffe...

  • Page 364

    HTML5 G A ME S346 normalMatrix ); return normalMatrix; } return { setNormalMatrix : setNormalMatrix, ... };})();Per-vertex lightingWith the normal vector accessible in the vertex shader, you’re able to use it to calculate the amount of light that...

  • Page 365

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL347Listing 11-22 Calculating per-vertex diffuse lightattribute vec3 aVertex;attribute vec3 aNormal; uniform mat4 uModelView;uniform mat4 uProjection;uniform mat3 uNormalMatrix;uniform vec3 uLightPosition; varying float vDiffuse;varying ve...

  • Page 366

    HTML5 G A ME S348Figure 11-3: This sphere has per-vertex lighting.Adding per-pixel lightingAs you can see in Figure 11-3, it’s easy to make out the triangles in the band where the transi-tion from light to shadow occurs. One solution to this problem is to move the calculations to the fragment...

  • Page 367

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL349Listing 11-24 Vertex shader for per-pixel lightingattribute vec3 aVertex;attribute vec3 aNormal; uniform mat4 uModelView;uniform mat4 uProjection;uniform mat3 uNormalMatrix; varying vec4 vPosition;varying vec3 vNormal;varying vec3 vCol...

  • Page 368

    HTML5 G A ME S350Now that you’ve moved to the fragment shader, you can also add the specular component to get a shiny highlight.Specular lightTo calculate the intense specular light component, you need two new vectors: the view direc-tion and reflection direction. The view direction is a vector...

  • Page 369

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL351 vec3 color = vColor * (uAmbient + diffuse + specular); gl_FragColor = vec4(color, 1.0);}The result is shown in Figure  11-4. Moving the light calculations to the fragment shader gives a much smoother transition between the diff...

  • Page 370

    HTML5 G A ME S352The texture object needs to be bound to a target to let WebGL know how you want to use it. The target you want is gl.TEXTURE_2D:gl.bindTexture(gl.TEXTURE_2D, texture);The functions gl.texParameteri() and gl.texParameterf() enable you to set parameters that control how the texture...

  • Page 371

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL353Loading image dataYou’re now ready to load some pixels into the texture object. You do this with the texIm-age2D() function:gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);The second parameter specifies...

  • Page 372

    HTML5 G A ME S354Listing 11-27 Creating texture objectsjewel.webgl = (function() { ... function createTextureObject(gl, image) { var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, ...

  • Page 373

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL355Figure 11-5: You can apply this Earth texture map to a sphere.Using textures in shadersTextures are referenced in the fragment shader using a uniform variable with a special data type. The sampler2D type is a handle that points to th...

  • Page 374

    HTML5 G A ME S356You do the calculations in the fragment shader, but first you need a bit of information from the vertex shader. The texture coordinates on the sphere depend on the position of the given point. For calculating spherical coordinates, the surface normal is just as good, so the verte...

  • Page 375

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL357void main(void) { ... float theta = acos(vOrgNormal.y); float phi = atan(vOrgNormal.z, vOrgNormal.x); vec2 texCoord = vec2(-phi / 2.0, theta) / 3.14159; vec4 texColor = texture2D(uTexture, texCoord); vec3 color = te...

  • Page 376

    HTML5 G A ME S358This concludes the walkthrough of the WebGL API, and you now have a basic understanding of how you can use WebGL to create 3D graphics for your games and applications. The next section shows you how to use WebGL to add a new display module to Jewel Warrior.Creating the WebGL dis...

  • Page 377

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL359 initialize : initialize, redraw : redraw, setCursor : setCursor, moveJewels : moveJewels, removeJewels : removeJewels, refill : redraw, levelUp : levelUp, gameOver : gameOver ...

  • Page 378

    HTML5 G A ME S360Listing 11-32 Loading the WebGL display modulewindow.addEventListener("load", function() { jewel.load("scripts/dom.js"); if (jewel.isStandalone()) { ... if (jewel.hasWebGL()) { jewel.load("scripts/webgl.js"); ...

  • Page 379

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL361 return j.x == x && j.y == y; })[0]; } ...})();You can use the rnd property on the jewel object to add variation to the jewels so they don’t all look exactly alike—for example, by making the rotation...

  • Page 380

    HTML5 G A ME S362The redraw() function iterates over all positions on the board. If a jewel object exists in the given position, its type is changed; otherwise, a new jewel object is created. Listing 11-34 also shows the setCursor() function, which is almost identical to the one from the 2D canva...

  • Page 381

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL363Listing 11-36 Initializing the WebGL contextjewel.display = (function() { var program, geometry, aVertex, aNormal, uScale, uColor, ... function setupGL() { var webgl = jewel.webgl; gl.en...

  • Page 382

    HTML5 G A ME S364 } function setupTexture() {} function setupShaders() {} ...})();Note that a few of the uniform locations as well as the attribute locations are stored for later use. You store them so you don’t have to look them up in each render cycle. The locations don’t c...

  • Page 383

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL365Blending and transparencyIn the setupGL() function, notice that two new settings are enabled: gl.BLEND and gl.CULL_FACE. Both are used to give the jewels a semitransparent appearance.Enabling gl.BLEND lets you set rules for how the col...

  • Page 384

    HTML5 G A ME S366 } } previousCycle = now; requestAnimationFrame(cycle); } function pause() { paused = true; } function resume(pauseTime) { paused = false; for (var i=0;i<animations.length;i++) { animations[i].startT...

  • Page 385

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL367 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.ibo); jewels.forEach(drawJewel); } ...})();All the jewels use the same geometry, so you need to bind the buffers only once. You can then draw the model as many time...

  • Page 386

    HTML5 G A ME S368 gl.uniform1f(uScale, scale); gl.uniform3fv(uColor, colors[jwl.type]); gl.cullFace(gl.FRONT); gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0); gl.cullFace(gl.BACK); gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0); } ...

  • Page 387

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL369Figure 11-8: Noise texture for the jewels adds structure.The texture is created in the setupTexture() function shown in Listing 11-40.Listing 11-40 Setting up the jewel texturejewel.display = (function() { ... function setupShad...

  • Page 388

    HTML5 G A ME S370 gl.bindTexture(gl.TEXTURE_2D, texture); }, false); image.src = "images/jewelpattern.jpg"; } ...})();The solid color that is mixed with the jewel texture comes from the uniform variable set by the drawJewel() function:uniform vec3 uColor;T...

  • Page 389

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL371Figure 11-9: The WebGL renders the jewel board.Animating the jewelsThe last step is to implement the animations for the various game actions.Moving and swapping jewelsThe moveJewels() function, shown in Listing 11-41, is similar to i...

  • Page 390

    HTML5 G A ME S372 dx = mover.toX - mover.fromX, dy = mover.toY - mover.fromY, dist = Math.abs(dx) + Math.abs(dy); if (!jwl) { // new jewel entering from the top jwl = createJewel(mover.fromX, mover.fromY, ...

  • Page 391

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL373 var n = removedJewels.length; removedJewels.forEach(function(removed) { var jwl = getJewel(removed.x, removed.y), y = jwl.y, // original coordinates x = jwl.x; addAnima...

  • Page 392

    HTML5 G A ME S374Leveling up and ending the gameThree functions remain: refill(), gameOver(), and levelUp(). There are endless pos-sibilities for what the refill animation could look like. I leave that one up to you as an exercise. The current implementation simply redirects the call to the red...

  • Page 393

    C HA P T E R 11 CR E A T ING 3D G R A P HI CS WI T H W EBGL375 } ...})();That’s the last of the WebGL display module. You now have two different options for display-ing the game graphics.Using Third-Party WebGL EnginesWith WebGL getting more and more attention, middleware for this particu...

  • Page 394

    HTML5 G A ME S376This code is quite different from the elaborate code you’ve seen throughout this chapter. Three.js takes care of setting up buffer objects and shaders, leaving a much simpler interface for you to work with. Despite the simplified rendering flow, Three.js has been used in some v...

  • Page 395

    Chapter 12 Local Storage and CachingChapter 13 Going Online with WebSocketsPart IVLocal Storage and Multiplayer Games

  • Page 396

  • Page 397

    Chapter 12Local Storage and CachingIn This Chapter■ Introducing Web Storage■ Storing data in cookies versus in local storage■ Adding persistent data to the game■ Making a high score list■ Enabling offline play with application cachingHTTP COOKIES HAVE traditionally solved the problem of...

  • Page 398

    HTML5 G A ME S380server has no use for the data, the bandwidth used to transmit the cookies is wasted. Browsers impose hard limits on the number and size of cookies. To stay on the safe side, store no more than 50 cookies and 4K per domain.Using Web Storage solves both of these problems. First, ...

  • Page 399

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING381Even if you close the browser, reload the page, or call localStorage.getItem() from another page (on the same domain), the data is still there.Alternatively, you can access the data using square brackets notation. All the stored values are...

  • Page 400

    HTML5 G A ME S382Iterating over stored valuesThe length property of the storage object is equal to the number of key/value pairs that you have saved:var numValues = localStorage.length;The localStorage.key() method takes a single argument, an index between 0 and length-1, and returns the name o...

  • Page 401

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING383When you load the page, the text is loaded into the textarea element from the local Storage object. The keyup event handler updates the stored value whenever you type in the field. Because the data is continuously saved in localStorage, yo...

  • Page 402

    HTML5 G A ME S384Listing 12-3 Using the session storage<textarea id="input"></textarea> <script> var input = document.getElementById("input"); input.value = sessionStorage.getItem("mytext") || ""; input.addEventListener("keyup",...

  • Page 403

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING385 return; } } return { set : set, get : get }; })();Load the storage module with the other scripts in index.html as shown in Listing 12-5.Listing 12-5 Loading the storage modulewindow.addEventListen...

  • Page 404

    HTML5 G A ME S386Listing 12-6 Saving the gamejewel.screens["game-screen"] = (function() { ... function saveGameData() { jewel.storage.set("activeGameData", { level : gameState.level, score : gameState.score, time : Date.now() - ga...

  • Page 405

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING387 useActiveGame, startJewels; if (activeGame) { useActiveGame = window.confirm( "Do you want to continue your previous game?" ); if (useActiveGame) { ...

  • Page 406

    HTML5 G A ME S388Listing 12-8 Passing the initial jewels to the board modulejewel.board = (function() { ... function initialize(startJewels, callback) { settings = jewel.settings numJewelTypes = settings.numJewelTypes, baseScore = settings.baseScore, cols = sett...

  • Page 407

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING389Listing 12-10 Using the initial jewels in the worker...addEventListener("message", function(event) { var board = jewel.board, message = event.data; switch (message.command) { case "initialize" : ...

  • Page 408

    HTML5 G A ME S390Listing 12-11 Adding the high score markup<div id="game"> ... <div class="screen" id="high-scores"> <h2 class="logo">High score</h2> <ol class="score-list"> </ol> ...

  • Page 409

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING391#high-scores footer button.back { float: left;}When the list items are added later, they all contain two child span elements: one for the player name and one for the score. Once again, you can make the necessary adjustments for landscap...

  • Page 410

    HTML5 G A ME S392Listing 12-14 The high score screen modulejewel.screens["high-scores"] = (function() { var firstRun = true; function setup() { var $ = jewel.dom.$, backButton = $("#high-scores button[name=back]")[0]; jewel.dom.bind(backButton,...

  • Page 411

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING393Listing 12-15 Entering a new high score entryjewel.screens["high-scores"] = (function() { var numScores = 10, ... function getScores() { return jewel.storage.get("scores") || []; } function a...

  • Page 412

    HTML5 G A ME S394You use the getScores() function to fetch the high score list from the storage module. If no scores are stored yet, getScores() simply returns an empty array.The checkScores() function goes through the list of saved scores until it encounters a score that’s smaller than the pl...

  • Page 413

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING395 item.appendChild(nameEl); item.appendChild(scoreEl); list.appendChild(item); } } ...})();After populateList() retrieves the scores from the storage module, it makes sure that numScores entries...

  • Page 414

    HTML5 G A ME S396obvious advantage of decreasing network traffic on subsequent visits, but it also allows the application to function if no network connection exists at all.The relevant part of the HTML5 specification is available from the W3C aactionURI(http://www.w3.org/TR/2011/WD-html5-201105...

  • Page 415

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING397Currently, no official extension is required when naming your manifest file. Some sites use .manifest, whereas others use .appcache. However, I recommend that you use the latter because an unrelated Microsoft technology also uses the .mani...

  • Page 416

    HTML5 G A ME S398manifest specifies a page shown when online resources are unreachable. Consider the follow-ing example from the HTML5 specification:CACHE MANIFESTFALLBACK:/ /offline.htmlNETWORK:*This manifest makes the browser add pages and files to the application cache as the user vis-its the...

  • Page 417

    C HA P T E R 12 L O C A L S T O R A G E A ND C A C HING399Listing 12-18 Cache manifest with revision numberCACHE MANIFEST# Jewel Warrior cache manifest, rev 47 CACHE:images/jewels32.pngimages/jewels40.png...Triggering a cache update makes the browser check all the files listed in the manifest. Th...

  • Page 418

  • Page 419

    Chapter 13Going Online with WebSocketsIn This Chapter■ Using WebSockets for online communication■ Introduction to Node.js and server-side JavaScript■ Creating a simple chat applicationIN THIS CHAPTER, I introduce you to WebSockets and Node, two relatively new technolo-gies that make creatin...

  • Page 420

    HTML5 G A ME S402WebSockets were created to provide an alternative geared specifically toward persistent con-nections and low-latency communication. WebSockets keep the connection alive and use only two bytes of overhead for each message, a drastic reduction. Another cool thing about WebSockets i...

  • Page 421

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S403This creates a new WebSocket object and attempts to establish a connection tactionURI(http://www.myserver.com):o www.actionURI(http://www.myserver.com):myserver.comactionURI(http://www.myserver.com): on port 9999. The WebSocket constructor ...

  • Page 422

    HTML5 G A ME S404Closing the connectionWhen you want to close the connection, simply call the ws.close() method:ws.close();Calling the ws.close() method switches the ready state to CLOSING until the connection is completely shut down, after which the ready state is CLOSED. Call the ws.close() me...

  • Page 423

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S405Status codeDescription1008This status code can be used when no other status code fits or if there is a need to hide the real reason.1009The connection was closed because the endpoint received a message that is too big to process.1010The con...

  • Page 424

    HTML5 G A ME S406Sending messagesWhen the connection is open, you can send data to the server with the ws.send() method. This function takes a single argument that can be a UTF-8 string, an ArrayBuffer, or a binary Blob object:ws.send("Hello Server!"); // send a string to the serverIf s...

  • Page 425

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S407setInterval(function() { if (ws.bufferedAmount == 0) { var data = getUpdate(); ws.send(data); }}, 100);Even though the interval is set to 100 ms, the preceding example sends the update data only if the buffer is empty, t...

  • Page 426

    HTML5 G A ME S408Listing 13-1 Reading data from a file with nodevar fs = require("fs"); fs.readFile("./myfiles/mystuff.txt", function(err, data) { if (err) { // something bad happened } else { // process file data }});Most of the asynchronous built-in fu...

  • Page 427

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S409Open a console/terminal window and use the npm install command to install modules. For example, to install the WebSocket module that you use later in this chapter, enter the following command:npm install websocketSimilarly, you can use the ...

  • Page 428

    HTML5 G A ME S410Don’t be alarmed if npm complains that the native code compile failed, the module will work fine. Now you can get started with the first example. For something simple yet potentially useful, I show you how to create a basic HTTP server that always responds with the same message...

  • Page 429

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S411on. The response object is used to write the HTTP response to the client socket. The response object has three important methods: response.writeHead(), response.write(), and response.end().The response.writeHead() method writes the HTTP hea...

  • Page 430

    HTML5 G A ME S412Run the server by executing the command:node 01-httpserver.jsIf you are running the server on your local machine, you can now connect to the server by pointing your browser to http://127.0.0.1:9999/. When you connect to the server, you should see the text "It Works!" di...

  • Page 431

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S413Next, you need to make a link between the WebSocket server and HTTP server. The WebSocket server essentially attaches to the HTTP server and processes all requests it receives. To create a link between the servers, you mount a server config...

  • Page 432

    HTML5 G A ME S414console.log("Chat server listening on port 9999!"); server.listen(9999);When a new client connects to the server, a connect event is fired on the WebSocketServer object. This event carries a connection object that you must use to communicate with that client. Listing 13...

  • Page 433

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S415Listing 13-5 Broadcasting the messages to all clientsfunction broadcast(data) { clients.forEach(function(client) { client.sendUTF(data); });}This function simply iterates over all the connected clients and sends the message. No...

  • Page 434

    HTML5 G A ME S416The event handler receives a single argument, an object containing the message. String messages keep the data in the message.utf8Data property, whereas messages with binary content keep the data as a Node Buffer object available in the message.binaryData property.The messageHand...

  • Page 435

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S417 default : this.sendUTF("Unknown command: " + firstWord); } } else { broadcast(this.nickname + " says: " + data); }}You can find the complete Node server script in the file 0...

  • Page 436

    HTML5 G A ME S418Listing 13-10 Styling the chat client#input, #response { border : 1px solid black; padding : 2px; display : block; width : 600px;} #response { height : 300px;}The JavaScript file 03-websocketclient.js contains all the code needed to set up the chat client. When the...

  • Page 437

    C HA P T E R 13 GOING O NL INE WI T H W EBS O CK E T S419The setupInput() function attaches a function to the keydown event on the input field. Whenever the user presses Enter, which has the key code 13, the text in the field is sent to the server and the field is cleared. Listing 13-12 shows the...

  • Page 438

    HTML5 G A ME S420SummaryIn this chapter, you learned about the server-side JavaScript environment Node and the WebSocket API that enables you to create better network-enabled web applications than do traditional HTTP-based solutions.This chapter showed you how to use WebSockets to create connecti...

  • Page 439

    IndexNUMERICS3D CSS transformation, 251–2523D graphics, creating with WebGLabout, 309–310display, 358–375rendering, 327–343shaders, 313–327textures and lighting, 343–358Aabort event, 291accessingAndroid log, 77gamepads data, 206–208image data, 167–173activating splash screen, 35ac...

  • Page 440

    HTML5 G A ME S422Apache Software Foundation, 78Apple (website), 74application cache, 395–399application icons, 66–69applications, webbuilding native, 77–80debugging, 33–34, 73–77placing on home screen, 62–71apply() method, 227arc() function, 135–137, 150–151Arcade Fire, 376arcs, d...

  • Page 441

    IND EX423broadcasting messages to clients, 414–415browsers, 71–73buildingaudio module, 300–306game, 16–17game screen, 180–194high score data screen, 389–392input module, 211–233native web applications, 77–80storage modules, 384–385“Bulletproof @font-face Syntax” (Irish), 37b...

  • Page 442

    HTML5 G A ME S424Comet, 12commands, intercepting, 416–417communicating, with WebSockets, 405–407complex data types, encoding, 381compositing, 164–167connected property, 207connectHandler() function, 414connectionshandling, 414to servers, 402–405conn.remoteAddress property, 414console.log(...

  • Page 443

    IND EX425ctx.translate() method, 148–149cubic curves, drawing, 139–140cursoradding to display module, 228–229animations, 241–243initializing, 221moving, 224–226rendering, 228–231setting properties, 221updating, 230cursor object, 220cycle() function, 240–241, 263, 336–337, 365–36...

  • Page 444

    HTML5 G A ME S426EEclipse Classic (website), 77Edge (Adobe), 14Elastic Compute Cloud (EC2) Service (website), 409ellipse() method, 150–151ellipses, drawing, 150–151em unit, 46–47embedded font, 38, 152empty HTML document, 25enabling Safari debugger, 74–77encoding complex data types, 381en...

  • Page 445

    IND EX427before(), 244, 245bind(), 53, 213, 226board.initialize(), 119board.swap(), 223callback(), 122cancelRequestAnimationFrame(), 238canJewelMove(), 101canSwap(), 94, 95, 101, 104, 247check(), 96–100checkChain(), 93–95, 96checkScores(), 394clearCursor(), 229clearInterval(), 110, 238clearJe...

  • Page 446

    HTML5 G A ME S428functions (continued)removeClass(), 32removeJewels(), 231, 249–250, 251, 372–373render(), 245, 250, 273–274, 371–372renderAnimations(), 263renderCursor(), 241–243, 242–243, 251, 263requestAnimationFrame(), 237–238, 260, 336require(), 408resumeGame(), 191, 192–193r...

  • Page 447

    IND EX429gamepadsaccessing data, 206–208detecting changes to state, 209–211events, 208–209input, 218–220Generalized Path Function, 160Geo Regular font (Ben Weiner), 36gestures, 202–203getAudioElement() function, 302getBoard() function, 105, 120, 122–123getBoundingClientRect() method, ...

  • Page 448

    HTML5 G A ME S430IETF (Internet Engineering Task Force), 402image dataaccessing, 167–173creating pixel-based effects, 171–173exporting, 170loading, 353–355retrieving pixel values, 167–168security restrictions, 171updating pixel values, 168–170imagesadding, 151–156bitmap, 128imgData ob...

  • Page 449

    IND EX431removing, 249–250, 372–373, 374rendering, 364–371selecting, 222–224sending to worker, 388swapping, 104–105, 371–372using in worker, 388–389jewel.setup() function, 176Joyent, 410JSON (JavaScript Object Notation), 13Kkey codes, adding, 216–217keyboard input, 43–44, 196–...

  • Page 450

    HTML5 G A ME S432meta tag parameters, 48–49methodsaddColorStop(), 145–146addHitRegion(), 205–206apply(), 227audio.canPlayType(), 284audio.play(), 306audio.stop(), 303–304blur(), 197–198canPlayType(), 282, 284–285, 288canvas.toDataURL(), 170, 171–172client.sendBinary(), 415createServ...

  • Page 451

    IND EX433mobile style sheets, 59–62mobile web applications, developing, 42–43model file, 341–342models, 331–336model-view matrix, 331–334Modernizr library, 15modes, rendering, 340modulesadding, 391–392audio, 300–306board, 86–105, 118Canvas Display Module, 181–183display, 262–2...

  • Page 452

    HTML5 G A ME S434paths, 131–142patterns, 147pause() method, 291pauseGame() function, 191, 192–193pausinganimations in display module, 262–263game, 190–194, 261–263percent (%) units, 46–47per-pixel lighting, 348–351perspective projection, 334per-vertex lighting, 346–348Phantom Limb...

  • Page 453

    IND EX435index, 207mapping, 207timestamp, 207, 211public methodsexposing, 122–123returning, 105Qquadratic curves, drawing, 138–139querySelectorAll() function, 34RrandomJewel() function, 91reacting to game actions, 231–233receiving messages, 111–112, 407rectangle path, 131–132rectangles,...

  • Page 454

    HTML5 G A ME S436screen modulesadding, 52–56installing, 65–66screens, switching, 34scripts, loading, 27–31SDK (Software Development Kits), 42searching board for chains, 95–96security restrictions, 171selecting jewels, 222–224selectJewel() function, 222sendingchanges to display, 223–22...

  • Page 455

    IND EX437source-atop, 165source-in, 165source-out, 165source-over, 165specifying source files, 288–289specular light, 344, 350–351splash screen. See also screenabout, 21activating, 35adding markup, 36creating, 35–40HTML with progress bar, 177loading, 65making, 65–66module, 53–54styles, ...

  • Page 456

    HTML5 G A ME S438touch eventsabout, 198–199gestures, 202–203multitouch, 199–202simulating, 203–204touch input, 215–216tracking loading progress, 176–179transformations, 147–151transforming vertex position, 336transitioning high score data to screen, 391translating, 148–149transpar...

  • Page 457

    IND EX439W3C Touch Events specification (website), 198wav, 283Web Application mode, 63web applicationsbuilding native, 77–80debugging, 33–34, 73–77placing on home screen, 62–71Web Audio API, 12, 295–300web fonts, 36–37web graphicsbitmap images, 128canvas element, 129SVG graphics, 128...

  • Page 458

    HTML5 G A ME S440WHATWG (Web Hypertext Application Technology Working Group), 8, 107, 108width attribute, 49, 57window object, 110WOFF (Web Open Font Format), 36–37Worker Board Module, 117–120Worker() constructor, 110, 124‘worker threads.’ See Web Workerswrite() function, 419ws.close() me...

Free HTML Books, HTML Book Pdf, HTML Pdf Books, HTML Pdf Books Download, HTML Pdf Books Free Download, Free HTML5 Books, HTML5 Book Pdf, HTML5 Pdf Books, HTML5 Pdf Books Download, HTML5 Pdf Books Free Download, Free ReadOnline Books, ReadOnline Book Pdf, ReadOnline Pdf Books, ReadOnline Pdf Books Download, ReadOnline Pdf Books Free Download,