Professional HTML5 Mobile Game Development


PROFESSIONAL HTML5 Mobile Game Development Pascal Rettig D o wnload from Wow! eBook Professional HTML5 Mobile Game Development Published by John Wiley & Sons, Inc. 10475 Crosspoint Boulevard Indianapolis, IN 46256 www.wiley.com Copyright © 2012 by Pascal Rettig Published by John Wiley & Sons, Inc., Indianapolis, Indiana Published simultaneously in Canada ISBN: 978-1-118-30132-6 ISBN: 978-1-118-30133-3 (ebk) ISBN: 978-1-118-42144-4 (ebk) ISBN: 978-1-118-43394-2 (ebk) Manufactured in the United States of America 10 9 8 7 6 5 4 3 2 1 No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should be addressed to the Permissions Department, John Wiley & Sons, Inc., 111 River Street, Hoboken, NJ 07030, (201) 748-6011, fax (201) 748- 6008, or online at http://www.wiley.com/go/permissions. Limit of Liability/Disclaimer of Warranty: The publisher and the author make no representations or warranties with respect to the accuracy or completeness of the contents of this work and specifically disclaim all warranties, including without limitation warranties of fitness for a particular purpose. No warranty may be created or extended by sales or pro- motional materials. The advice and strategies contained herein may not be suitable for every situation. This work is sold with the understanding that the publisher is not engaged in rendering legal, accounting, or other professional services. If professional assistance is required, the services of a competent professional person should be sought. Neither the pub- lisher nor the author shall be liable for damages arising herefrom. The fact that an organization or Web site is referred to in this work as a citation and/or a potential source of further information does not mean that the author or the publisher endorses the information the organization or Web site may provide or recommendations it may make. Further, readers should be aware that Internet Web sites listed in this work may have changed or disappeared between when this work was written and when it is read. For general information on our other products and services please contact our Customer Care Department within the United States at (877) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002. Wiley publishes in a variety of print and electronic formats and by print-on-demand. Some material included with standard print versions of this book may not be included in e-books or in print-on-demand. If this book refers to media such as a CD or DVD that is not included in the version you purchased, you may download this material at http://booksupport .wiley.com. For more information about Wiley products, visit www.wiley.com. Library of Congress Control Number: 2012942105 Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are trade- marks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries, and may not be used without written permission. All other trademarks are the property of their respective owners. John Wiley & Sons, Inc., is not associated with any product or vendor mentioned in this book. This book is dedicated to my wife, business partner, best friend, and all-around support system, Martha. Thank You. EXECUTIVE EDITOR Carol Long PROJECT EDITOR Jennifer Lynn TECHNICAL EDITOR Chris Ullman PRODUCTION EDITOR Christine Mugnolo COPY EDITOR San Dee Phillips EDITORIAL MANAGER Mary Beth Wakefield FREELANCER EDITORIAL MANAGER Rosemarie Graham ASSOCIATE DIRECTOR OF MARKETING David Mayhew MARKETING MANAGER Ashley Zurcher BUSINESS MANAGER Amy Knies PRODUCTION MANAGER Tim Tate VICE PRESIDENT AND EXECUTIVE GROUP PUBLISHER Richard Swadley VICE PRESIDENT AND EXECUTIVE PUBLISHER Neil Edde ASSOCIATE PUBLISHER Jim Minatel PROJECT COORDINATOR, COVER Katie Crocker COMPOSITOR Jeff Lytle, Happenstance Type-O-Rama PROOFREADER Nancy Carrasco INDEXER Johnna VanHoose Dinse COVER DESIGNER Ryan Sneed COVER IMAGE © Daniel Schweinert / iStockPhoto CREDITS ABOUT THE AUTHOR PASCAL RETTIG  is a lifelong programmer who got his start program- ming by writing BASIC games on the Apple II at the ripe age of 7. Pascal has a Bachelor of Science and a Master of Engineering in computer sci- ence and electrical engineering from the Massachusetts Institute of Technology ’02 and has been hacking and building stuff on the web since 1995. Pascal built the HTML5 game-based language learning system GamesForLanguage.com in 2011 and is currently a partner at the interac- tive web agency Cykod. He organizes one of the country’s oldest monthly HTML5 Game Development meetups in Boston each month and runs the HTML5 Game Development news site html5gamedevelopment.org. ABOUT THE TECHNICAL EDITOR CHRIS ULLMAN  is a senior software developer at MIG, specializing in .NET, and a technical editor/author, who has spent many years stewing in web- related technologies, like a teabag left too long in the pot. Coming from a computer science background, he gravitated toward MS solutions during the summer of ASP (1997). He cut his teeth on Wrox Press ASP guides, and since then he has edited or contributed to more than 30 books, most notably as lead author for Wrox’s bestselling Beginning ASP/ASP.NET 1.x/2 series. These days he lives out on the moors of Cornwall and spends his non-computing time running, writing music, and attempting with his wife, Kate, to curb the enthusiasm of three very boisterous children. ACKNOWLEDGMENTS I’D LIKE TO THANK MY WIFE,  Martha, who not only had to put up with me spending every moment of free time I had writing this book (while working on two startups) but also was gracious enough to design all the custom game art used in this book, ensuring that readers aren’t stuck with the dreaded curse of programmer art. I’d also like to thank my family for supporting me in this endeavor and continuing to accept me as a family member despite my best efforts to lock myself away for the duration. I’d like to particularly thank my editors, Carol Long, Jennifer Lynn, and San Dee Phillips, for help- ing a newbie author through the process of turning some pages of code into a cohesive book; and technical reviewer Chris Ullman, who did his best to ensure this book made it to print as error-free as possible. Lastly, I’d like to thank the Boston HTML5 Game Development community. Boston has an incred- ible technology community, and being around such motivated, smart people keeps me learning, energized, and constantly hacking away at new projects. CONTENTS INTRODUCTION xxiii Part I: DIVING IN CHAPTER 1: FLYING BEFORE YOU WALK 3 Introduction 3 Building a Complete Game in 500 Lines 4 Understanding the Game 4 Structuring the Game 4 The Final Game 5 Adding the Boilerplate HTML and CSS 5 Getting Started with Canvas 6 Accessing the Context 6 Drawing on Canvas 7 Drawing Images 8 Creating Your Game’s Structure 9 Building Object-Oriented JavaScript 10 Taking Advantage of Duck Typing 10 Creating the Three Principle Objects 11 Loading the SpriteSheet 11 Creating the Game Object 13 Implementing the Game Object 13 Refactoring the Game Code 15 Adding a Scrolling Background 16 Putting in a Title Screen 19 Drawing Text on Canvas 19 Adding a Protagonist 21 Creating the PlayerShip Object 22 Handling User Input 22 Summary 23 x CONTENTS CHAPTER 2: MAKING IT A GAME 25 Introduction 25 Creating the GameBoard Object 25 Understanding the GameBoard 26 Adding and Removing Objects 26 Iterating over the List of Objects 27 Defining the Board Methods 28 Handling Collisions 29 Adding GameBoard into the Game 30 Firing Missiles 30 Adding a Bullet Sprite 31 Connecting Missiles to the Player 32 Adding Enemies 33 Calculating Enemy Movement 33 Constructing the Enemy Object 34 Stepping and Drawing the Enemy Object 35 Adding Enemies on the Board 36 Refactoring the Sprite Classes 37 Creating a Generic Sprite Class 37 Refactoring PlayerShip 38 Refactoring PlayerMissile 39 Refactoring Enemy 39 Handling Collisions 40 Adding Object Types 40 Colliding Missiles with Enemies 41 Colliding Enemies with the Player 42 Making It Go Boom 43 Representing Levels 44 Setting Up the Enemies 44 Setting Up Level Data 45 Loading and Finishing a Level 46 Implementing the Level Object 47 Summary 49 CHAPTER 3: FINISHING UP AND GOING MOBILE 51 Introduction 51 Adding Touch Controls 51 Drawing Controls 52 Responding to Touch Events 54 Testing on Mobile 56 xi CONTENTS Maximizing the Game 57 Setting the Viewport 57 Resizing the Canvas 57 Adding to the iOS Home Screen 60 Adding a Score 60 Making It a Fair Fight 61 Summary 64 Part II: MOBILE HTML5 CHAPTER 4: HTML5 FOR MOBILE 67 Introduction 67 Capturing a Brief History of HTML5 68 Understanding How HTML5 Grew Up “Different” 68 Looking Toward HTML6? HTML7? Nope, Just HTML5 68 Going to the Spec 69 Differentiating the HTML5 Family and HTML5 69 Using HTML5 The Right Way 70 Having Your Cake and Eating It, Too 70 Sniffing Browsers 70 Determining Capabilities, Not Browsers 72 Enhancing Progressively 73 Polyfilling in the Gaps 74 Considering HTML5 from a Game Perspective 74 Canvas 74 CSS3/DOM 75 SVG 76 Considering HTML5 from a Mobile Perspective 76 Understanding the New APIs 77 What’s Coming: WebAPI 77 Surveying the Mobile Browser Landscape 77 WebKit: The Market Dominator 78 Opera: Still Plugging Along 78 Firefox: Mozilla’s Mobile Offering 79 WP7 Internet Explorer 9 79 Tablets 79 Summary 79 xii CONTENTS CHAPTER 5: LEARNING SOME HELPFUL LIBRARIES 81 Introduction 81 Learning JavaScript Libraries 82 Starting with jQuery 82 Adding jQuery to Your Page 82 Understanding the $ 83 Manipulating the DOM 84 Creating Callbacks 85 Binding Events 87 Making Ajax Calls 90 Calling Remote Servers 90 Using Deferreds 91 Using Underscore.js 92 Accessing Underscore 92 Working with Collections 92 Using Utility Functions 93 Chaining Underscore Method Calls 94 Summary 94 CHAPTER 6: BEING A GOOD MOBILE CITIZEN 95 Introduction 95 Responding to Device Capabilities 96 Maximizing Real Estate 96 Resizing Canvas to Fit 97 Dealing with Browser Resizing, Scrolling, and Zooming 98 Handling Resizing 98 Preventing Scrolling and Zooming 99 Setting the Viewport 100 Removing the Address Bar 101 Configuring Your App for the iOS Home Screen 103 Making Your Game Web App Capable 103 Adding a Startup Image 103 Configuring Home Icons 104 Taking Mobile Performance into Consideration 105 Adapting to Limited Bandwidth and Storage 106 Optimizing for Mobile 106 Good for Mobile Is Good for All 106 Minifying Your JavaScript 107 Setting Correct Headers 108 Serving from a CDN 108 xiii CONTENTS Going Offline Completely with Application Cache 109 Creating Your Manifest File 109 Checking If the Browser Is Online 111 Listening for More Advanced Behavior 111 A Final Word of Warning 111 Summary 112 Part III: JAVASCRIPT GAME DEV BASICS CHAPTER 7: LEARNING ABOUT YOUR HTML5 GAME DEVELOPMENT ENVIRONMENT 115 Introduction 115 Picking an Editor 116 Exploring the Chrome Developer Tools 116 Activating Developer Tools 116 Inspecting Elements 116 Viewing Page Resources 118 Tracking Network Traffic 119 Debugging JavaScript 121 Examining the Console Tab 121 Exercising the Script Tab 123 Profiling and Optimizing Your Code 125 Running Profiles 126 Actually Optimizing Your Game 128 Mobile Debugging 129 Summary 131 CHAPTER 8: RUNNING JAVASCRIPT ON THE COMMAND LINE 133 Introduction 133 Learning About Node.js 134 Installing Node 134 Installing Node on Windows 135 Installing Node on OS X 135 Installing Node on Linux 135 Tracking the Latest Version of Node 136 Installing and Using Node Modules 136 Installing Modules 136 Hinting Your Code 136 Uglifying Your Code 137 xiv CONTENTS Creating Your Own Script 137 Creating a package.json File 138 Using Server-Side Canvas 139 Creating a Reusable Script 140 Writing a Sprite-Map Generator 141 Using Futures 141 Working from the Top Down 142 Loading Images 144 Calculating the Size of the Canvas 146 Drawing Images on the Server-Side Canvas 146 Updating and Running the Script 148 Summary 148 CHAPTER 9: BOOTSTRAPPING THE QUINTUS ENGINE: PART I 149 Introduction 149 Creating a Framework for a Reusable HTML5 Engine 150 Designing the Basic Engine API 150 Starting the Engine Code 151 Adding the Game Loop 153 Building a Better Game Loop Timer 153 Adding the Optimized Game Loop to Quintus 154 Testing the Game Loop 155 Adding Inheritance 157 Using Inheritance in Game Engines 157 Adding Classical Inheritance to JavaScript 158 Exercising the Class Functionality 161 Supporting Events 162 Designing the Event API 162 Writing the Evented Class 162 Filling in the Evented Methods 163 Supporting Components 165 Designing the Component API 166 Implementing the Component System 167 Summary 169 CHAPTER 10: BOOTSTRAPPING THE QUINTUS ENGINE: PART II 171 Introduction 171 Accessing a Game Container Element 171 Capturing User Input 174 Creating an Input Subsystem 174 Bootstrapping the Input Module 175 xv CONTENTS Handling Keyboard Events 176 Adding Keypad Controls 178 Adding Joypad Controls 181 Drawing the Onscreen Input 184 Finishing and Testing the Input 186 Loading Assets 188 Defining Asset Types 189 Loading Specific Assets 189 Finishing the Loader 191 Adding Preload Support 194 Summary 195 CHAPTER 11: BOOTSTRAPPING THE QUINTUS ENGINE: PART III 197 Introduction 197 Defining SpriteSheets 198 Creating a SpriteSheet Class 198 Tracking and Loading Sheets 199 Testing the SpriteSheet class 200 Adding Sprites 201 Writing the Sprite Class 201 Referencing Sprites, Properties, and Assets 203 Exercising the Sprite Object 203 Setting the Stage with Scenes 207 Creating the Quintus.Scenes Module 207 Writing the Stage Class 208 Rounding Out the Scene Functionality 212 Finishing Blockbreak 214 Summary 217 Pa RT IV: BUILDING GAMES WITH CSS3 AND SVG CHAPTER 12: BUILDING GAMES WITH CSS3 221 Introduction 221 Deciding on a Scene Graph 221 Your Target Audience 222 Your Interaction Method 222 Your Performance Requirements 222 Implementing DOM Support 223 Considering DOM Specifics 223 Bootstrapping the Quintus DOM Module 223 D o wnload from Wow! eBook xvi CONTENTS Creating a Consistent Translation Method 224 Creating a Consistent Transition Method 227 Implementing a DOM Sprite 227 Creating a DOM Stage Class 230 Replacing the Canvas Equivalents 231 Testing the DOM Functionality 232 Summary 233 CHAPTER 13: CRAFTING A CSS3 RPG 235 Introduction 235 Creating a Scrolling Tile Map 235 Understanding the Performance Problem 236 Implementing the DOM Tile Map Class 236 Building the RPG 240 Creating the HTML File 240 Setting Up the Game 241 Adding a Tile Map 242 Creating Some Useful Components 245 Adding in the Player 248 Adding Fog, Enemies, and Loot 249 Extending the Tile Map with Sprites 253 Adding a Health Bar and HUD 255 Summary 260 CHAPTER 14: BUILDING GAMES WITH SVG AND PHYSICS 261 Introduction 261 Understanding SVG Basics 262 Getting SVG on Your Page 262 Getting to Know the Basic SVG Elements 263 Transforming SVG Elements 267 Applying Strokes and Fills 267 Beyond the Basics 270 Working with SVG from JavaScript 271 Creating SVG Elements 271 Setting and Getting SVG Attributes 272 Adding SVG Support to Quintus 272 Creating an SVG Module 273 Adding SVG Sprites 274 Creating an SVG Stage 276 Testing the SVG Class 278 xvii CONTENTS Adding Physics with Box2D 280 Understanding Physics Engines 281 Implementing the World Component 281 Implementing the Physics Component 284 Adding Physics to the Example 287 Creating a Cannon Shooter 288 Planning the Game 289 Building the Necessary Sprites 290 Gathering User Input and Finishing the Game 292 Summary 294 Part V: HTML5 CANVAS CHAPTER 15: LEARNING CANVAS, THE HERO OF HTML5 297 Introduction 297 Getting Started with the Canvas Tag 298 Understanding CSS and Pixel Dimensions 298 Grabbing the Rendering Context 301 Creating an Image from Canvas 301 Drawing on Canvas 302 Setting the Fill and Stroke Styles 303 Setting the Stroke Details 305 Adjusting the Opacity 306 Drawing Rectangles 306 Drawing Images 306 Drawing Paths 307 Rendering Text on Canvas 308 Using the Canvas Transformation Matrix 310 Understanding the Basic Transformations 310 Saving, Restoring, and Resetting the Transformation Matrix 311 Drawing Snowflakes 311 Applying Canvas Effects 313 Adding Shadows 314 Using Composition Effects 314 Summary 316 CHAPTER 16: GETTING ANIMATED 317 Introduction 317 Building Animation Maps 318 Deciding on an Animation API 318 Writing the Animation Module 320 Testing the Animation 323 xviii CONTENTS Adding a Canvas Viewport 325 Going Parallax 328 Summary 330 CHAPTER 17: PLAYING WITH PIXELS 331 Introduction 331 Reviewing 2-D Physics 332 Understanding Force, Mass, and Acceleration 332 Modeling a Projectile 333 Switching to an Iterative Solution 334 Extracting a Reusable Class 335 Implementing Lander 336 Bootstrapping the Game 336 Building the Ship 337 Getting Pixel Perfect 339 Playing with ImageData 340 Making It Go Boom 343 Summary 347 CHAPTER 18: CREATING A 2-D PLATFORMER 349 Introduction 349 Creating a Tile Layer 350 Writing the TileLayer Class 350 Exercising the TileLayer Code 352 Optimizing the Drawing 353 Handling Platformer Collisions 355 Adding the 2-D Component 356 Calculating Platformer Collisions 358 Stitching It Together with the PlatformStage 359 Building the Game 361 Boostrapping the Game 361 Creating the Enemy 363 Adding Bullets 364 Creating the Player 365 Summary 369 CHAPTER 19: BUILDING A CANVAS EDITOR 371 Introduction 371 Serving the Game with Node.js 371 Creating the package.json File 372 Setting Up Node to Serve Static Assets 372 xix CONTENTS Creating the Editor 373 Modifying the Platform Game 374 Creating the Editor Module 376 Adding Touch and Mouse Events 379 Selecting Tiles 381 Adding Level-Saving Support 383 Summary 384 Part VI: MULTIPLAYER GAMING CHAPTER 20: BUILDING FOR ONLINE AND SOCIAL 387 Introduction 387 Understanding HTTP-Based Multiplayer Games 388 Planning a Simple Social Game 388 Integrating with Facebook 389 Generating the Facebook Application 389 Creating the Node.js Server 390 Adding the Login View 393 Testing the Facebook Authentication 395 Connecting to a Database 396 Installing MongoDB on Windows 396 Installing MongoDB on OS X 396 Installing MongoDB on Linux 397 Connecting to MongoDB from the Command Line 397 Integrating MongoDB into the Game 398 Finishing Blob Clicker 401 Pushing to a Hosting Service 403 Summary 405 CHAPTER 21: GOING REAL TIME 407 Introduction 407 Understanding WebSockets 407 Using Native WebSockets in the Browser 408 Using Socket.io: WebSockets with Fallbacks 411 Creating the Scribble Server 411 Adding the Scribble Client 413 Building a Multiplayer Pong Game Using Socket.io 415 Dealing with Latency 415 Combating Cheating 416 Deploying Real-Time Apps 416 xx CONTENTS Creating an Auto-Matching Server 417 Building the Pong Front End 419 Summary 425 CHAPTER 22: BUILDING NONTRADITIONAL GAMES 427 Introduction 427 Creating a Twitter Application 427 Connecting a Node App to Twitter 429 Sending Your First Tweet 429 Listening to the User Stream 430 Generating Random Words 431 Creating Twitter Hangman 432 Summary 437 Part VII: MOBILE ENHANCEMENTS CHAPTER 23: LOCATING VIA GEOLOCATION 441 Introduction 441 Getting Started with Geolocation 441 Getting a One-Time Position 442 Plotting a Location on a Map 444 Watching the Position Change over Time 445 Drawing an Interactive Map 446 Calculating the Position between Two Points 448 Summary 448 CHAPTER 24: QUERYING DEVICE ORIENTATION AND ACCELERATION 449 Introduction 449 Looking at a Device Orientation 450 Getting Started with Device Orientation Events 450 Detecting and Using the Event 451 Understanding the Event Data 451 Trying Out Device Orientation 451 Creating a Ball Playground 452 Adding Orientation Control 454 Dealing with Browser Rotation 455 Summary 456 xxi CONTENTS CHAPTER 25: PLAYING SOUNDS, THE MOBILE ACHILLES HEEL 457 Introduction 457 Working with the Audio Tag 457 Using the Audio Tag for Basic Playback 458 Dealing with Different Supported Formats 458 Understanding the Limitations of Mobile Audio 459 Building a Simple Desktop Sound Engine 459 Using Audio Tags for Game Audio 460 Adding a Simple Sound System 460 Adding Sound Effects to Block Break 461 Building a Sound System for Mobile 463 Using Sound Sprites 463 Generating the Sprite File 466 Adding Sound Sprites to the Game 467 Looking to the Future of HTML5 Sound 467 Summary 467 Part VIII: GAME ENGINES AND APP STORES CHAPTER 26: USING AN HTML5 GAME ENGINE 471 Introduction 471 Looking at the History of HTML5 Engines 471 Using a Commercial Engine 472 Impact.js 473 Spaceport.io 474 IDE Engines 474 Using an Open-Source Engine 475 Crafty.js 475 LimeJS 476 EaselJS 478 Summary 481 CHAPTER 27: TARGETING APP STORES 483 Introduction 483 Packaging Your App for the Google Chrome Web Store 484 Creating a Hosted App 484 Creating a Packaged App 486 Publishing Your App 486 xxii CONTENTS Using CocoonJS to Accelerate Your App 487 Getting a Game Ready to Load into CocoonJS 487 Testing CocoonJS on Android 489 Building Your App in the Cloud 489 Building Apps with the AppMobi XDK and DirectCanvas 490 Understanding DirectCanvas 490 Installing the XDK 490 Creating the App 491 Modifying Alien Invasion to Use DirectCanvas 491 Testing Your App on a Device 496 Summary 496 CHAPTER 28: SEEKING OUT WHAT’S NEXT 497 Introduction 497 Going 3-D with WebGL 497 Getting Better Access to Sound with the Web Audio API 498 Making Your Game Bigger with the Full-Screen API 499 Locking Your Device Screen with the Screen Orientation API 499 Adding Real-Time Communications with WebRTC 499 Tracking Other Upcoming Native Features 500 Summary 500 APPENDIX: RESOURCES 501 INDEX 503 INTRODUCTION THE GAMING WORLD AND THE WEB  have been on a collision course with each other since social games began bringing gaming to the masses and helped make what was once a subculture a main- stream, mass-market phenomenon. Throw mobile into the mix and suddenly you have a massive phenomenon that is going to become more important as more devices get into people’s hands. For example, one story making its way around the web as of this writing is that game developer Rovio, creator of the Angry Birds franchise, is estimated to be worth approximately 8 billion dol- lars, almost the same as venerable phone maker Nokia. These days people spend more time on their phones and tablets than ever before, and games (in addition to social networks) account for a sig- nificant portion of that time. Smartphones and tablets are significantly displacing dedicated mobile gaming devices from Nintendo and Sony. With HTML5, game developers now have technology that has the capability to reach more people than ever imaginable from a single codebase. HTML5 mobile game development is currently a new technology that people aren’t sure what to make of yet, much like smartphone games were in 2008 when the Apple App Store launched. However, there are some serious heavyweights pushing for the success of HTML5 gaming. Facebook, which launched its App Center in May 2012, has made HTML5-based Web Apps first-class citizens on mobile and is looking for ways to monetize on mobile and get out from underneath the thumb of the 30% fee Apple takes for in-app purchases in its app store. Carriers such as AT&T similarly view web apps as a way to recapture revenue lost to Google and Apple. All is not rosy in the HTML5 game development picture, however. Different devices have different capabilities, levels of performance, and screen resolutions, and navigating the dangerous waters of mobile HTML5 game development requires some careful sailing. That’s where this book comes in. Its goal is to provide a pragmatic roadmap to build mobile games in HTML5, covering both the possibilities and limitations of the medium. If HTML5 game development on the desktop is still in its infancy, mobile HTML5 game development is still embryonic. The possibilities to do great things are within reach, but the first smash success in the medium is still to be seen. Getting into a technology at an early stage can provide significant benefits. One of the wonder- ful things in working in new technologies is that the noise level is minimal, and less is required to generate a splash than in other established mediums. HTML5 games, especially mobile ones, have budgets that are tiny fractions of the millions of dollars that standard PC and console games have, and yet they have the opportunity to create a smash hit in an instant due to the viral nature of the web. Mobile HTML5 games have even more potential for explosive growth because they can be shared instantly with a link rather than requiring the recipients to download an app that might not be available for their device from an app store. This book is a journey through the world of possibilities that the exciting realm of HTML5 mobile game development presents and I hope you’ll jump aboard. xxiv INTRODUCTION WHO THIS BOOK IS FOR This book is for anyone who wants to build interactive games in a browser using standards-based, plug-in-free technology. It has a focus on mobile game development because this is where HTML5 has an advantage versus competing web technologies such as Flash, but the games you build will be playable on desktop browsers as well. Developing games for mobile HTML5 requires cross-disciplinary skills over a range of different mediums. To do it right you must have a basic grasp of the JavaScript language because you’ll be pushing JavaScript to its limits to build games in the browser. This book does not try to teach you JavaScript from the ground up, but instead relies on a basic understanding of the language to cover ground quickly. If you don’t use JavaScript on a daily basis, you may find some spots of code hard to follow. All is not lost however—if you want to get up to speed on JavaScript quickly, Douglas Crockford’s semi- nal work on JavaScript called JavaScript: The Good Parts” (O’Reilly, 2008) is only 180 pages and can familiarize you with the language and can be used as a reference when techniques you might not be familiar with are mentioned in this book. If you are a desktop game developer more familiar with C++ than JavaScript, you can follow along with the text, but again because JavaScript (despite its C-like syntax) has more in common with Lisp than C++, you may want to review the Crockford book as well. JavaScript's weak typing, mutable method bindings, and closure support may cause some confusion. ActionScript developers coming from building games in Flash should feel right at home. The only major stumbling block is that HTML5 Game development is more disjointed than Flash. Make sure you pay close attention to Chapter 7, “Learning About Your HTML5 Game Development Environment,” because that chapter shows you how to inspect and debug JavaScript, so you don’t feel lost when something goes wrong in your game. Browsers have powerful script-debuggers built in, so you shouldn’t miss the Flash IDE too much. WHAT THIS BOOK COVERS This book covers creating games using HTML5 that run on HTML5-capable smartphones such as iOS devices and Android. Windows phone 7.5, which supports Canvas, is also targeted in some instances, but because its Canvas performance is restrictive and doesn’t support the standards-based multitouch events, support for the Windows phone is limited in some cases. You can get the most out of this book if you target mobile Safari on iOS 5.0 and up and Chrome for Android on Android 4.0 and up because these devices both have fast JavaScript engines and hardware-accelerated Canvas support. Many of the games run on older versions of Android, but performance will be limited. xxv INTRODUCTION HOW THIS BOOK IS STRUCTURED This book is comprised of seven sections, each with a special purpose to teach you about mobile HTML5 game development. Part I, “Diving In,” teaches you over the course of three chapters how to build a mobile HTML5 game from scratch that runs on any device that supports canvas. It shows the nitty-gritty of what's required to get a game up and running quickly without pulling in any external libraries. Part II, “Mobile HTML5,” takes a step back and covers in detail the state of HTML5 on mobile devices along with a couple of libraries—jQuery and Underscore.js—that you use to build games in the rest of the book. Part III, “JavaScript Game Dev Basics,” first walks you through how to inspect and debug your game and how to run JavaScript from the command line using Node.js. It then goes through the process to build a reusable HTML5 game engine from the ground up, showing how you can struc- ture and organize your code into coherent modules. Part IV, “Building Games with CSS3 and SVG,” takes a detour from canvas to show you how to use two other technologies—CSS3 and Scalable Vector Graphics (SVG)—to build games on mobile devices. Chapter 14, “Building Games with SVG and Physics,” also introduces the popular JavaScript Physics engine Box2D. Part V, “HTML5 Canvas,” first covers the canvas tag in detail and then proceeds to build a touch- friendly 2-D platformer and a level editor for that platformer to build levels. Part VI, “Multiplayer Gaming,” shows how you can create games that can provide a meaningful interaction among players, asynchronously and in real-time using WebSockets. Part VII, “Mobile Enhancements,” examines how to use some of the additional HTML5-family of APIs to enhance your game, covering geolocation and device orientation as well as covering the state of HTML5 sound on mobile devices. Part VIII, “Game Engines and App Stores,” surveys the landscape of game engines available for HTML5—both commercial and open-source—and helps you decide which engine is appropriate. It also covers emerging technologies that enable you to publish hardware-accelerated HTML5 games into the native mobile App stores. WHAT YOU NEED TO USE THIS BOOK The samples in this book run on modern desktop browsers in Windows, OS X, or Linux. The term modern desktop browsers refers to Internet Explorer versions 9 and up, and up-to-date versions of Safari, Firefox, or Chrome. xxvi INTRODUCTION If you want to run the samples on a mobile device, for best results you need an iOS device running iOS 5.0 or greater or an Android device running Android 4.0 or newer. Many of the examples work on Android 2.2 and above, but performance may be limited. If you run on a Mac, you can run a number of the examples via the iOS simulator that can be installed with XCode. Android simulators are unfortunately too slow currently to be a good test bed for running HTML5 games. CONVENTIONS To help you get the most from the text and keep track of what's happening, we’ve used a number of conventions throughout the book. WARNING  B oxes like this one hold important, not-to-be-forgotten information that is directly relevant to the surrounding text. NOTE  N otes, Tips, hints, and tricks are offest and placed in italics like this. SIDEBAR Asides to the current discussion are offset like this. As for styles in the text: ➤➤ We highlight new terms and important words when we introduce them. ➤➤ We show keyboard strokes like this: Ctrl+A. ➤➤ We show filenames, URLs, and code within the text like so: persistence.properties. ➤➤ We present code in two different ways: We use a monofont type with no highlighting for most code examples. We use boldface to emphasize code that is particularly important in the present context. SOURCE CODE As you work through the examples in this book, you may choose either to type in all the code man- ually or to use the source code files that accompany the book. All the source code used in this book is available for download at www.wrox.com. At the site, simply locate the book’s title (either by using D o wnload from Wow! eBook xxvii INTRODUCTION the Search box or by using one of the title lists) and click the Download Code link on the book’s detail page to obtain all the source code for the book. NOTE  Because many books have similar titles, you may find it easiest to search by the ISBN; this book’s ISBN is 978-1-118-30132-6. After you download the code, decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at www.wrox.com/dynamic/books/download.aspx to see the code available for this book and all other Wrox books. ERRATA We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be grateful for your feedback. By sending in errata you may save another reader hours of frustration and at the same time you can help us provide even higher quality information. To find the errata page for this book, go to www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page, you can view all errata that has been submitted for this book and posted by Wrox editors. A complete book list, including links to each book’s errata, is also available at www.wrox.com/misc-pages/ booklist.shtml. NOTE  A complete book list including links to errata is also available at www.wrox.com/misc-pages/booklist.shtml. If you don’t spot “your” error on the Book Errata page, click on the Errata Form link and complete the form to send us the error you have found. We’ll check the information and, if appropriate, post a mes- sage to the book’s errata page and fix the problem in subsequent editions of the book. P2P.WROX.COM For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e‑mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums. xxviii INTRODUCTION At p2p.wrox.com you can find a number of different forums to help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps: 1. Go to p2p.wrox.com and click the Register link. 2. Read the terms of use and click Agree. 3. Complete the required information to join, as well as any optional information you want to provide, and click Submit. 4. You will receive an e‑mail with information describing how to verify your account and com- plete the joining process. NOTE  You can read messages in the forums without joining P2P, but to post your own messages, you must join. After you join, you can post new messages and respond to messages other users post. You can read messages at any time on the web. If you would like to have new messages from a particular forum e‑mailed to you, click the Subscribe to This Forum icon by the forum name in the forum listing. For more information about how to use the Wrox P2P, read the P2P FAQs for answers to questions about how the forum software works as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page. PART I Diving In ⊲⊲ CHAPTER 1:  Flying Before You Walk ⊲⊲ CHAPTER 2:  Making It a Game ⊲⊲ CHAPTER 3:  Finishing Up and Going Mobile Flying Before You Walk WHAT’S IN THIS CHAPTER? ➤➤ Creating the HTML5 for a game ➤➤ Loading images and drawing on canvas ➤➤ Setting up your game’s structure ➤➤ Creating an animated background ➤➤ Listening for user input WROX.COM CODE DOWNLOADS FOR THIS CHAPTER The wrox.com code downloads for this chapter are found at www.wrox.com/remtitle .cgi?isbn=9781118301326 on the Download Code tab. The code is in the chapter 01 download and individually named according to the names throughout the chapter. INTRODUCTION Games have long been a medium that pushes technology to its limits. This book continues that proud tradition by taking the core technologies of the web—HTML, CSS, and JavaScript—and pushing them to the edges of their capabilities and performance. HTML5 as a game medium has come a long way capability-wise in a short amount of time, and many people believe in-browser gaming will be one of the primary distribution mechanisms for games in the coming years. Even though it’s not an environment originally designed for creating games, HTML5 is actually a nice, high-level environment for doing just that. So, in lieu of trying to abstract away all the boilerplate by building an engine immediately, you can get right to the good stuff: a one-off game built from the ground up on HTML5—a top-down 2-D space shooter called Alien Invasion. 1 4  ❘  CHAPTER 1  Flying Before You Walk BUILDING A COMPLETE GAME IN 500 LINES To drive home the point of how easy it is to build games in HTML5, the final game you build in the first three chapters contains fewer than 500 lines of code, all without using any libraries. Understanding the Game Alien Invasion is a top-down 2-D shooter game built in the spirit of the game 1942 (but in space) or a simplified version of Galaga. The player controls a ship, shown at the bottom of the screen, flying the ship vertically through an endless space field while defending Earth against an incoming hoard of aliens. When played on a mobile device, control is via left and right arrows shown on the bottom left of the screen, and a Fire button on the right. When played on the desktop, the user can use the keyboard’s arrow keys to fly and the spacebar to fire. To compensate for all the different screen sizes of mobile devices, the game resizes the play area to always play at the size of the device. On the desktop it plays in a rectangular area in the middle of the browser page. Structuring the Game Nearly every game of this type consists of a few of the same pieces: some asset loading, a title screen, sprites, user input, collision detection, and a game loop to tie it all together. The game uses as few formal structures as possible. Instead of building explicit classes, you take advantage of JavaScript’s dynamic typing (more on this in the section “Building Object-Oriented JavaScript”). Languages such as C, C++, and Java are called “strongly typed” because you need to be very explicit about the type of parameters that you pass around to method. This means you need to explicitly define base classes and interfaces when you want to pass different types of objects to the same method. JavaScript is weakly (or dynamically) typed because the language doesn’t enforce the types of parameters. This means you define your objects more loosely, adding methods to each object as needed, without building a bunch of base classes or interfaces. Image asset handling is dead simple. You load a single image, called a sprite sheet, that contains all your game’s sprite images in a single PNG and execute a callback after that image loads. The game also has a single method for drawing a sprite onto your canvas. The title screen renders a sprite for the main title and shows the same animated starfield from the main game moving in the background. The game loop is also simple. You have an object that you can treat as the current scene, and you can tell that scene to update itself and then to draw itself. This is a simple abstraction that works for both title and end game screens as well as the main part of the game. User input can use a few event listeners for keyboard input and a few “zones” on your canvas to detect touch input. You can use the HTML standard method addEventListener to support both of these. Lastly, for collision detection, you punt the hard stuff and just loop over the bounding boxes of each of the objects to detect a collision. This is a slow and naive way to implement collision detection, Adding the Boilerplate HTML and CSS   ❘  5 but it’s simple to implement and works reasonably well as long as the number of sprites you check against is small. The Final Game To get a sense of where the game is headed, check out Figure 1-1, and visit http://cykod.github.com/AlienInvasion/ on both a desktop browser and whatever mobile device you have handy. The game should run on any smartphone that supports HTML5 canvas; however, canvas performance on Android versions before Ice Cream Sandwich is poor. Now, it’s time to get started. ADDING THE BOILERPLATE HTML AND CSS The main boilerplate for an HTML5 file is minimal. You get a valid HTML file with a element inside of a container centered on the page, as shown in Listing 1-1. LISTING 1-1:  Boilerplate game HTML Alien Invasion
The only external files so far are the base.css file, an external style sheet, and a nonexistent game.js file that will contain the JavaScript code for the game. Drop the HTML from Listing 1-1 into a new directory, and call it index.html. In base.css you need two separate sections. The first is a CSS reset. CSS resets make sure all ele- ments look the same in all browsers and any per-element styling and padding is removed. To do this, the reset sets the size of all elements to 100% (16 pixels for fonts) and removes all padding, borders, and margins. The reset used is the well-known Eric Meyer reset: http://meyerweb.com/eric/ tools/css/reset/. FIGURE 1-1:  The final game. 6  ❘  CHAPTER 1  Flying Before You Walk You can simply copy the CSS code verbatim to the top of base.css. Next, you need to add two additional styles to the CSS file, as shown in Listing 1-2. LISTING 1-2:  Base canvas and container styles /* Center the container */ #container { padding-top:50px; margin:0 auto; width:480px; } /* Give canvas a background */ canvas { background-color: black; } The first container style gives the container a little padding at the top of the page and centers its con- tent in the middle of the page. The second style gives the canvas element a black background. GETTING STARTED WITH CANVAS You hopefully noticed a canvas tag in the middle of the HTML on the page (as shown in Listing 1-2): This is where all the action for the game takes place—so much exciting stuff you can do in such an unassuming tag. The tag has an id for easy reference along with a width and height. Unlike most HTML elements, you generally never want to add a CSS width and height onto canvas elements. Those styles visu- ally resize your canvas but do not affect the pixel dimensions of the canvas, which is controlled by the width and height on the element. Most of the time you should leave these alone. Accessing the Context Before you can do any drawing onto canvas, you need to fetch the context from the canvas element. The context is the object that you actually make API calls against (not the canvas element itself.) For 2-D canvas games, you can pull out the 2-D context, as shown in Listing 1-3. LISTING 1-3:  Accessing the rendering context var canvas = document.getElementById('game'); var ctx = canvas.getContext && canvas.getContext('2d'); if(!ctx) { // No 2d context available, let the user know alert('Please upgrade your browser'); Getting Started with Canvas  ❘  7 } else { startGame(); } function startGame() { // Let's get to work } First, grab the element from the document. These initial chapters use built-in browser methods for all DOM (Document Object Model) interaction; later you are introduced to how to do the same things more concisely using jQuery. Next, call getContext on the canvas element. A double-ampersand (&&) short circuit operator pro- tects you from calling a nonexistent method. This is used in the next if statement in case the visit- ing browser doesn’t support the canvas element. You always want to “fail loudly” in this case, so the players correctly blame their browser instead of your code. “Failing loudly” means that instead of “failing silently” with a white screen and an error hiding on the JavaScript console, the game explicitly pops up with a message that tells the user that something went wrong. There is a 3-D WebGL-powered rendering context available on desktop browsers (excluding Internet Explorer), but it is called glcanval and is available only on mobile Nokia devices at the time of this writing. WebGL is another standard, separate from HTML5, that allows you to use hardware-accelerated 3-D graphics in the browser. Add the code from Listing 1-3 to a file named game.js. You now can start playing with the canvas element. Drawing on Canvas This initial tutorial doesn’t use any of the vector-based drawing routines, but for the sake of getting something up on the screen quickly, you can draw a rectangle on the page. Modify the startGame() method of your game.js file to read as follows: function startGame() { ctx.fillStyle = "#FFFF00"; ctx.fillRect(50,100,380,400); } To draw a filled rectangle, you use the fillRect method on the ctx object, but first you need to set a fill style. You can pass in standard CSS color representations as strings to fillStyle, including hexadecimal colors, RGB triples, or RGBA quads. To layer a semitransparent rectangle on top of the existing one, add the following: function startGame() { ctx.fillStyle = "#FFFF00"; ctx.fillRect(50,100,380,400); // Second, semi-transparent blue rectangle ctx.fillStyle = "rgba(0,0,128,0.5);"; ctx.fillRect(0,50,380,400); } If you add the preceding code and reload your index.html file, you see a nice, big blue rectangle smack dab in the middle of your black canvas. 8  ❘  CHAPTER 1  Flying Before You Walk Drawing Images Alien Invasion is an old-school, top-down 2-D shooter game with retro-looking bitmap graphics. Luckily canvas provides an easy method called drawImage that comes in a couple of flavors, depend- ing upon whether you want to draw an entire image or just a portion of an image. The only complication is that, to draw those graphics, the game needs to load the image first. This isn’t a huge deal because browsers are handy at loading images; however, they load them asynchro- nously, so you need to wait for a callback to let you know that the image is ready to go. Make sure you have copied the sprites.png file over from the book assets for Chapter 1 into an images/ directory underneath your current game, and then add the code from Listing 1-4 to the bottom of your startGame function. LISTING 1-4:  Drawing images with canvas (canvas/game.js) function startGame() { ctx.fillStyle = "#FFFF00"; ctx.fillRect(50,100,380,400); // Second, semi-transparent blue rectangle ctx.fillStyle = "rgba(0,0,128,0.8);"; ctx.fillRect(25,50,380,400); var img = new Image(); img.onload = function() { ctx.drawImage(img,100,100); } img.src = 'images/sprites.png'; } If you reload the page, you should now see the sprite sheet lay- ered on top of your rectangles. See canvas/game.js in the chap- ter code for the complete code. You can see the code first waits for the onload callback before trying to draw the image onto the context and then sets the src after setting up the callback. The order is important because Internet Explorer does not trigger the onload callback if the image is cached if you reverse the order of the two lines. You can see the results—admittedly not pretty—in Figure 1-2. This first example uses the simplest drawImage method—one that takes an image and an x and y coordinate and then draws the entire image on the canvas. Modify the drawImage line to read as follows: var img = new Image(); img.onload = function() { ctx.drawImage(img,100,100,200,200); } img.src = 'images/sprites.png'; FIGURE 1-2:  The spritesheet and drawn rectangles. Creating Your Game’s Structure  ❘  9 The image has now shrunk down to the size of the extra parameters that you passed in which are the destination width and height. This is a second form of drawImage that enables you to scale images up or down to any dimensions. The last form of drawImage, however, is the one that you'll use the most often with bitmapped games. It is also the most complicated and takes a total of nine parameters: drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) This form enables you to specify a source rectangle in the image using parameters sx, sy, sWidth, and sHeight and a destination rectangle on the canvas using parameters dx, dy, dWidth, and dHeight. As you’ve probably figured out, to pull out an individual frame from one of the sprites in the sprite sheet, this is the format you want to use. Now give it a shot by changing the call to drawImage to: var img = new Image(); img.onload = function() { ctx.drawImage(img,18,0,18,25,100,100,18,25); } img.src = 'images/sprites.png'; If you reload the page, you see there’s now a single instance of the player ship on the canvas. So far so good. In the next section, you start to build out the structure for an actual game. IMMEDIATE VERSUS RETAINED MODE Canvas is a tool for creating games in what’s commonly referred to as Immediate mode. When you use canvas, all you are doing is drawing pixels onto the page. Canvas doesn’t know anything about your spaceships or missiles that fly around. All it cares about are pixels, and most canvas games clear the canvas completely between frames and redraw everything at an updated position. Contrast this with using the DOM to create a game. Using the DOM would be equivalent to creating a game in Retained mode, as the browser keeps track of the “scene graph” for you. This scene graph keeps track of the position and hierarchy of objects. Instead of starting from scratch in each frame, you need to adjust only the elements that have changed and the browser takes care of rendering everything correctly. Which is better? Well, it depends on your game. See the discussion in Chapter 12, “Building Games in CSS3,” to learn when to use which method. CREATING YOUR GAME’S STRUCTURE The code built so far has been a good way to exercise the canvas capabilities you’ll be using, but it will need to be reorganized to turn it into a useful structure for a game. Now take a step back to look at some of the patterns you want to use putting together the game. 10  ❘  CHAPTER 1  Flying Before You Walk Building Object-Oriented JavaScript JavaScript is an object-oriented (OO) language. As such, most elements in JavaScript are objects including strings, arrays, functions and, well, objects are objects in the OO sense. But this doesn’t mean that JavaScript has all the trappings of object-oriented programming (OOP) that you might expect. First, it doesn't have a classical inheritance model. Second, it doesn't have a standard constructor mechanism, relying instead on either constructor functions or object literals. Instead of classical inheritance, JavaScript implements prototypical inheritance, meaning you can create an object that represents the prototype, or blueprint, for a set of descendant objects that all share the same base functionality CLASSICAL VERSUS PROTOTYPICAL INHERITANCE Most popular object-oriented languages used today, including Java and C++, rely on classical inheritance, which means object behavior is defined by creat- ing explicit classes and instantiating objects from those classes. JavaScript has a much more fluid method of defining classes based on the idea of prototypes, which means you create an actual object that behaves the way you want and then create child objects off of that. Because methods are just regular JavaScript objects, many times developers also simply copy attributes from other objects to fake Java-style interfaces or multiple inheritance. This flexibility shouldn’t necessarily be viewed as a problem; rather, it means that developers have a lot of flexibility for how to create objects and can pick the best method for the specific use case. Alien Invasion uses constructor functions combined with prototypical inheritance where it makes sense. Using object prototypes can make object creation up to 50 times faster and provides memory savings, but it is also more restricting because you can’t use closures to access and protect data. Closures are a feature of JavaScript that allows you to keep variables in a method around for later use even when a method has finished execution. Chapter 9, “Bootstrapping the Quintus Engine: Part I,” discusses object-creation patterns in more detail, but for now just realize that the use of different methods is intentional. Taking Advantage of Duck Typing There’s a famous saying that if it walks like a duck and talks like a duck, then it must be a duck. When programming in strongly-typed languages, there’s no doubt whether it’s a duck—it must be an instance of the “Duck” class, or if you program in Java, implement the iDuck interface. In JavaScript, a dynamically-typed language, parameters, and references are not type-checked, meaning you can pass any type of object as a parameter to any function, and that function happily treats that object like the type of whatever object it was expecting until something blows up. This flexibility can be both a good and a bad thing. It’s a bad thing when you end up with cryptic error messages or errors during run time. It’s a good thing when you use that flexibility to keep a Loading the SpriteSheet  ❘  11 shallow inheritance tree but can still share code. The idea of using objects based on their external interface rather than their type is called duck typing. Alien Invasion uses this idea in a couple of places: game screens and sprites. The game treats anything that responds to method calls of step() and draw() as valid game screen objects or valid sprites. Using duck typing for game screens enables Alien Invasion to treat title screens and in-game screens as the same type of object, making it easy to switch between levels and title screens. Similarly, using duck typing for sprites means that the game can be flexible with what can be added to a game board, including the player, enemies, projectiles, and HUD elements. HUD, which is short for Heads Up Display, is the term commonly used for elements that sit on top of the game, such as number of lives left and the player’s score. Creating the Three Principle Objects The game needs three principle, mostly persistent objects: a Game object tying everything together; a SpriteSheet object for loading and drawing sprites; and a GameBoard object for displaying, updat- ing, and handling the collision of sprite elements. The game also needs a gaggle of different sprites such as the player, enemies, missiles, and HUD objects, such as the score and number of remaining lives, but those are introduced individually later. LOADING THE SPRITESHEET You have already seen most of the code necessary to load a sprite sheet and display sprites on the page. All that remains is to extract the functionality into a package. One enhancement puts in a map of sprite names to their locations to make it easier to draw the sprites on the screen. A second enhance- ment encapsulates the onload callback functionality to hide the details from any calling classes. Listing 1-5 shows the entire class. LISTING 1-5:  The SpriteSheet class var SpriteSheet = new function() { this.map = { }; this.load = function(spriteData,callback) { this.map = spriteData; this.image = new Image(); this.image.onload = callback; this.image.src = 'images/sprites.png'; }; this.draw = function(ctx,sprite,x,y,frame) { var s = this.map[sprite]; if(!frame) frame = 0; ctx.drawImage(this.image, s.sx + frame * s.w, s.sy, s.w, s.h, x, y, s.w, s.h); }; } 12  ❘  CHAPTER 1  Flying Before You Walk Although the class is short and has only two methods, it does have a number of things to note. First, because there can be only one SpriteSheet object, the object is created with new function() { ... } This puts the constructor function and the new operator on the same line, ensuring that only one instance of this class is ever created. Next, two parameters pass into the constructor. The first parameter, spriteData, passes in sprite data linking the rectangles of sprites to names. The second parameter, callback, passes as a call- back to the image onload method. The second method, draw, is the main workhorse of the class because it does the actual drawing of sprites onto a context. It takes as parameters the context, the string specifying the name of a sprite from the spriteData map, an x and y location to draw the sprite, and an optional frame for sprites with multiple frames. The draw method uses those parameters to look up the spriteData in the map to get the source location of the sprite as well as the width and height. (For this simple SpriteSheet class, every frame of the sprite is expected to be the same size and on the same line.) It uses that information to figure out the parameters to the more complicated drawImage method, discussed in the “Drawing Images” section earlier in this chapter. Although this code is designed to be a one-off and only useful for this specific game, you still need to separate the game data, such as the sprite data and levels, from the game engine to make it easier to test and build in pieces. Add in the SpriteSheet to the top of a new file called engine.js file and replace the startGame function in game.js with the following code: function startGame() { SpriteSheet.load({ ship: { sx: 0, sy: 0, w: 18, h: 35, frames: 3 } },function() { SpriteSheet.draw(ctx,"ship",0,0); SpriteSheet.draw(ctx,"ship",100,50); SpriteSheet.draw(ctx,"ship",150,100,1); }); } Here the StartGame function calls SpriteSheet.load and passes in the details for a couple of sprites. Next, in the callback function (after the images/sprites.png file loads) to test out the drawing function, it draws three sprites on the canvas. Modify the bottom of your index.html file to load engine.js first and then game.js:
Check out sprite_sheet/index.html in the chapter code for the preceding example in a working form. Creating the Game Object  ❘  13 Now that the game can draw sprites on the page, you can set up the main game object to orchestrate everything else. CREATING THE GAME OBJECT The main game object is a one-off object called, perhaps not surprisingly, Game. Its main purpose is to initialize the game engine for Alien Invasion and run the game loop as well as provide a mecha- nism for changing the main scene that displays. Because Alien Invasion doesn’t have an input subsystem, the Game class is also responsible for set- ting up listeners for keyboard and touch input. To start, only keyboard input is handled; touch input is added in the next chapter. Now that the game starts to take shape, a few additional considerations are necessary. Instead of just executing code willy-nilly when it is evaluated, it generally makes sense to wait for the page to finish downloading before initializing the game. The Game class takes this into consideration and listens for a “load” event from the window before booting up the game. The code for the Game class will be added at the top of engine.js. Implementing the Game Object Now walk through the 40+ lines of code that make up the Game object a section at a time. (See the full listing at the top of game_class/engine.js in the chapter code.) The class starts off much like the SpriteSheet, as a one-time class instance: var Game = new function() { Next is the initialization routine, called with the ID of the canvas element to fill, the sprite data that is passed to the SpriteSheet, and the callback when the game is ready to start. // Game Initialization this.initialize = function(canvasElementId,sprite_data,callback) { this.canvas = document.getElementById(canvasElementId); this.width = this.canvas.width; this.height= this.canvas.height; // Set up the rendering context this.ctx = this.canvas.getContext && this.canvas.getContext('2d'); if(!this.ctx) { return alert("Please upgrade your browser to play"); } // Set up input this.setupInput(); // Start the game loop this.loop(); // Load the sprite sheet and pass forward the callback. SpriteSheet.load(sprite_data,callback); }; D o wnload from Wow! eBook 14  ❘  CHAPTER 1  Flying Before You Walk Much of this code should be familiar from earlier in the chapter. The parts where you grab the canvas element and check for a 2d context are straightforward. Next is a call to setupInput(), which is discussed next. Finally, the game loop starts, and the data for the sprite sheet passes through to SpriteSheet.load. The next section sets up input: // Handle Input var KEY_CODES = { 37:'left', 39:'right', 32 :'fire' }; this.keys = {}; this.setupInput = function() { window.addEventListener('keydown',function(e) { if(KEY_CODES[event.keyCode]) { Game.keys[KEY_CODES[event.keyCode]] = true; e.preventDefault(); } },false); window.addEventListener('keyup',function(e) { if(KEY_CODES[event.keyCode]) { Game.keys[KEY_CODES[event.keyCode]] = false; e.preventDefault(); } },false); } The main point of this block is to add event listeners for keydown and keyup events for those keys that you care about: specifically the left arrow, the right arrow, and the spacebar. For those events, the listeners translate a numeric Keycode to a friendlier identifier and update a hash called Game.keys to represent the current state of the user input. The player uses the Game.keys hash to control the ship. For keys used by the game, the event handlers also call e.preventDefault(), which prevents the browser from performing any default behavior in response to the key presses. (For the arrow keys and the spacebar, the browser would normally try to scroll the page.) One more point about the preceding event handler code: It uses the W3C event model addEventListener method. This code is supported in current versions of the Chrome, Safari, and Firefox browsers, but only Internet Explorer (IE) versions 9 and above. This is not a huge deal because canvas isn’t supported pre-IE9 in any case, but if you want to add compatibility for older browsers, it’s something you need to be careful with. (The engine built starting in Chapter 9, “Bootstrapping the Quintus Engine Part I,” uses jQuery’s on method to enable easy browser-independent event attachment.) The last section of the Game class is relatively short: // Game Loop var boards = []; this.loop = function() { var dt = 30/1000; for(var i=0, len = boards.length;i 0) { ctx.drawImage(stars, 0, remaining, stars.width, intOffset, 0, 0, stars.width, intOffset); } if(remaining > 0) { ctx.drawImage(stars, 0, 0, stars.width, remaining, 0, intOffset, 18  ❘  CHAPTER 1  Flying Before You Walk stars.width, remaining); } } The code looks slightly confusing because it uses the nine-parameter version of drawImage to draw the slices, but it’s actually just slicing the starfield into a top half and a bottom half, and drawing the top half at the bottom of the game canvas and the bottom half at the top of the canvas. Listing 1-7 shows the Starfield class in its entirety, which should go into the game.js file. LISTING 1-7:  The Starfield (starfield/game.js) var Starfield = function(speed,opacity,numStars,clear) { // Set up the offscreen canvas var stars = document.createElement("canvas"); stars.width = Game.width; stars.height = Game.height; var starCtx = stars.getContext("2d"); var offset = 0; // If the clear option is set, // make the background black instead of transparent if(clear) { starCtx.fillStyle = "#000"; starCtx.fillRect(0,0,stars.width,stars.height); } // Now draw a bunch of random 2 pixel // rectangles onto the offscreen canvas starCtx.fillStyle = "#FFF"; starCtx.globalAlpha = opacity; for(var i=0;i 0) { ctx.drawImage(stars, 0, remaining, stars.width, intOffset, 0, 0, stars.width, intOffset); } // Draw the bottom half of the starfield if(remaining > 0) { ctx.drawImage(stars, Putting in a Title Screen  ❘  19 0, 0, stars.width, remaining, 0, intOffset, stars.width, remaining); } } // This method is called to update // the starfield this.step = function(dt) { offset += dt * speed; offset = offset % stars.height; } } Only two parts haven’t been discussed. The step function at the bottom gets called with the frac- tion of a second that has elapsed since the last call to step. All it needs to do is update the offset variable based on the elapsed time and the speed, and then use the modulus (%) operator to make sure the offset is between zero and the height of the Starfield. There's also a conditional to check if the clear parameter is set. This parameter is used to fill the first layer of stars with a black fill. (Later layers need to be transparent so that they overlay over each other correctly.) This prevents the need to explicitly clear the canvas between frames and saves some processing time. To see the starfield in action, you need to modify your startGame function in game.js to add some starfields. Modify it to add three starfields of varying opacity by setting it to the following: var startGame = function() { Game.setBoard(0,new Starfield(20,0.4,100,true)) Game.setBoard(1,new Starfield(50,0.6,100)) Game.setBoard(2,new Starfield(100,1.0,50)); } Only the first starfield has the clear parameter set to true. Each starfield has a higher speed combined with a higher opacity than the last. This gives an effect of stars at different distances speeding by. PUTTING IN A TITLE SCREEN An animated starfield, although nice, isn't a game. To start to build out the same elements of the game, one of the first requirements for a game is to display a title screen showing the users what they can play. The title screen for Alien Invasion isn't going to be anything special—just a text title and a subtitle. So a generic GameScreen class with a title and subtitle centered on the screen is enough to get the job done. Drawing Text on Canvas Drawing text on the canvas is straightforward and allows you to use any font loaded on the page. This flexibility means you can use any of the standard web-safe fonts as well as any fonts that have been loaded via @font-face onto the page. 20  ❘  CHAPTER 1  Flying Before You Walk The declarations for @font-face take some care because depending on the browsers that need to be supported, four different file formats need to be available. Luckily, if you aren't going to install the files locally, but rather serve them off an online service such as the free Google web fonts, all that's needed is a single linked style sheet. (You can browse the fonts available for free use at Google web fonts at (www.google.com/webfonts.) For Alien Invasion, the font Bangers gives the game a nice retro “Invasion of the Body Snatchers” feel. Add the following line to your HTML (not your JavaScript) below the base.css link tag: Alien Invasion Next, the game needs a TitleScreen class to display some text centered on the screen. To do this you must use a new canvas method that hasn’t been discussed yet, fillText, and two new canvas properties, font and textAlign. The current font used is set by passing a CSS style to context.font, for example: ctx.font = "bold 25px Arial"; This declaration would set the current font used by both measureText and fillText to 25 pixels high, make it bold, and use the Arial font family. To make sure the text is centered on a specific location horizontally, you’ll need to set the context .textAlign property to center. ctx.textAlign = "center"; After you calculate the location for the text and set the font style appropriately, you can use fillText to draw solid text onto the canvas: fillText(string, x, y); fillText takes the string to draw and an x and y location for the top-left corner. Armed with these text-drawing methods, you now have the tools to draw a title screen that shows a title and a subtitle and calls an optional callback when the user presses the fire key. Listing 1-8 shows the code to get that done. Add the TitleScreen class to the bottom of your engine.js file. LISTING 1-8:  The TitleScreen (titlescreen/engine.js) var TitleScreen = function TitleScreen(title,subtitle,callback) { this.step = function(dt) { if(Game.keys['fire'] && callback) callback(); }; Adding a Protagonist  ❘  21 this.draw = function(ctx) { ctx.fillStyle = "#FFFFFF"; ctx.textAlign = "center"; ctx.font = "bold 40px bangers"; ctx.fillText(title,Game.width/2,Game.height/2); ctx.font = "bold 20px bangers"; ctx.fillText(subtitle,Game.width/2,Game.height/2 + 40); }; Similar to the Starfield object, TitleScreen defines a step and a draw method. The step method has only one task: to check if the fire key is pressed, and if so, call the callback that was passed in. The draw does the majority of the actual work. First, it sets a fillStyle (white) that will be used on both the title and subtitle. Next, it sets the font for the title. You can horizontally center the title on the page by moving x to half the width of the canvas. Next is a call to fillText with this calcu- lated x location and half the height of the canvas. To draw the subtitle, the same calculation is repeated with a new font, and then the vertical position is offset by 40 pixels to place it below the title. You now need to add the title screen onto the page as a new board above the background starfields. Modify your startGame method as shown, and add in a new callback called playGame: var startGame = function() { Game.setBoard(0,new Starfield(20,0.4,100,true)) Game.setBoard(1,new Starfield(50,0.6,100)) Game.setBoard(2,new Starfield(100,1.0,50)); Game.setBoard(3,new TitleScreen("Alien Invasion", "Press space to start playing", playGame)); } var playGame = function() { Game.setBoard(3,new TitleScreen("Alien Invasion", "Game Started...")); } If you reload the browser, you should see a title screen, and after you press the spacebar, the title screen should update the subtitle to say “Game Started.” The playGame function will be replaced with code to actually start to play the game in the next section. ADDING A PROTAGONIST The first step to turn Alien Invasion into an actual, playable game is to add a player-controlled ship. This is the first sprite that you add to the game. In the next chapter, you create a GameBoard class to manage the many sprites that are on the page at once during normal gameplay, but for now a single sprite is enough to start. 22  ❘  CHAPTER 1  Flying Before You Walk Creating the PlayerShip Object The first step is to get a ship created and drawn on the page. Open up game.js and add the player ship class to the bottom: var PlayerShip = function() { this.w = SpriteSheet.map['ship'].w; this.h = SpriteSheet.map['ship'].h; this.x = Game.width/2 - this.w / 2; this.y = Game.height - 10 - this.h; this.vx = 0; this.step = function(dt) { // TODO – added the next section } this.draw = function(ctx) { SpriteSheet.draw(ctx,'ship',this.x,this.y,1); } } Much like a game screen, a sprite has the same two external methods: step and draw. Keeping the interface consistent allows sprites and game screens to be mostly interchangeable. In initializing the sprite, a few more variables are set that give the sprite a position on the page and a height and a width. (The next chapter uses the position and height and width to do simple bounding box colli- sion detection.) The width and height of the sprite are pulled from the sprite sheet. Although you could hard-code the width and height here, using the dimensions from the sprite sheet mean there is only one loca- tion that needs to be changed if the dimensions need to be changed. Next, modify the playGame function to read as follows: var playGame = function() { Game.setBoard(3,new PlayerShip()); } If you reload the index.html file and press the spacebar, you can see the player ship hanging out at the bottom of the page. Handling User Input The next task is to accept user input to allow the player to move the ship back and forth across the game. This is handled in the step function inside of PlayerShip. The step function has three main parts. The first is to check for user input to update the ship’s move- ment direction; the second is to update the x coordinate based on the direction; and finally the func- tion needs to check that the updated x position is within the bounds of the screen. Replace the TODO comment in the preceding step method with the following code: this.step = function(dt) { this.maxVel = 200; this.step = function(dt) { if(Game.keys['left']) { this.vx = -this.maxVel; } else if(Game.keys['right']) { this.vx = this.maxVel; } Summary  ❘  23 else { this.vx = 0; } this.x += this.vx * dt; if(this.x < 0) { this.x = 0; } else if(this.x > Game.width - this.w) { this.x = Game.width - this.w; } } } The first part of the method checks the Game.keys map to see if the user is currently pressing the left or the right arrow keys, and if so sets the velocity to the correct positive or negative value. The second part of the code simply updates the x position with the current velocity multiplied by the fraction of a second since the last update. Finally, the method checks to see if the x position is either off the left side of the screen (less than zero) or off the right side of the screen (greater than the width of the screen minus the width of the ship). If either of those conditions is true, the value of x is modified to be within that range. SUMMARY You now know how to get the framework of an HTML5 game up-and-running, including loading a sprite sheet, drawing on canvas, adding in a parallax background, and taking in user input. At this point, you can fire up the player/index.html file and fly your ship left and right using the arrow keys. Congratulations! You’re well on your way to having your first HTML5 game up-and- running. The next chapter builds on these initial pieces of code to add in enemies, levels, and the rest. Chapter 3, “Enhancing The Game,” finishes this initial game by adding in mobile support. Making It a Game WHAT’S IN THIS CHAPTER? ➤➤ Exploring scene management ➤➤ Adding projectiles and enemies ➤➤ Using collision detection ➤➤ Creating explosions WROX.COM CODE DOWNLOADS FOR THIS CHAPTER The wrox.com code downloads for this chapter are found at www.wrox.com/remtitle .cgi?isbn=9781118301326 on the Download Code tab. The code is in the chapter 02 download and individually named according to the names throughout the chapter. INTRODUCTION In Chapter 1, “Flying Before You Walk,” you put together the framework of your first HTML5 mobile game and got a spaceship flying around the screen. Until this point what's been built so far is more a toy than a game. To make it a game, you need to add some enemies and set up the various elements of the game so that they can interact with each other. CREATING THE GAMEBOARD OBJECT The first step to turning Alien Invasion into a game is to add a mechanism that handles a bunch of sprites on the page at the same time. The current Game object can handle a stack of boards, but those boards all act independently of each other. Also, although the Game object provides a mechanism to swap boards in and out, it doesn't make it easy to add an arbitrary number of sprites onto the page. Enter the GameBoard object. 2 26  ❘  CHAPTER 2  Making It a Game Understanding the GameBoard The purpose of the GameBoard object is much like the game board in a game of checkers. It provides a spot to drop all the pieces and dictates their movement. In this section you break down some of the responsibilities of this object. The responsibilities of the GameBoard can be broken down into four distinct categories: ➤➤ It is responsible for keeping a list of objects and handling adding sprites to and removing sprites from that list. ➤➤ It also needs to handle looping over that list of objects. ➤➤ It needs to respond the same way as previous boards. It needs to have a step and a draw function that calls the appropriate functions on each of the objects in the object list. ➤➤ It needs to handle checking of collisions between objects. The next few sections walk through each of the parts of the GameBoard object, which will behave like a simple scene graph. Scene graphs are discussed in detail in Chapter 12, “Building Games with CSS3.” The GameBoard class will be added to the bottom of the engine.js file. Adding and Removing Objects The first and most important responsibility of the GameBoard class is to keep track of the objects in play. The easiest way to keep track of a list of objects is simply to use an array, in this case an array called objects. The GameBoard class will be described piecemeal, but the whole thing goes at the bottom of the engine.js file: var GameBoard = function() { var board = this; // The current list of objects this.objects = []; this.cnt = []; This array is where objects that show up in the game are added to and removed from. Next, the class needs the capability to add objects. This is simple enough. Pushing objects onto the end of the objects’ list gets most of the job done: // Add a new object to the object list this.add = function(obj) { obj.board=this; this.objects.push(obj); this.cnt[obj.type] = (this.cnt[obj.type] || 0) + 1; return obj; }; For an object to interact with other objects, however, it needs access to the board it’s a part of. For this reason when GameBoard.add is called, the board sets a property called board on the object. The object can now access the board to add additional objects, such as projectiles or explosions, or remove itself when it dies. Creating the GameBoard Object  ❘  27 The board also must keep a count of the number of objects of different types that are active at a given time, so the second-to-last line of the function initializes the count to zero if necessary using a boolean OR and then increments that count by 1. Objects won’t be assigned types until later in this chapter, so this is a little bit of forward-looking code. Next is removal. This process is slightly more complicated than it first might seem because objects may want to remove themselves or other objects in the middle of a step while the GameBoard loops over the list of objects. A naive implementation would try to update GameBoard.objects but because the GameBoard would be in the middle of looping over all the objects, changing them mid- loop would cause problems with the looping code. One option is to make a copy of the list of objects at the beginning of each frame, but this could get costly to do each frame. The best solution is to first mark objects for removal in a separate array and then actually remove them from the object list after every object has had its turn. Following is the solution GameBoard uses: // Mark an object for removal this.remove = function(obj) { var wasStillAlive = this.removed.indexOf(obj) != -1; if(wasStillAlive) { this.removed.push(obj); } return wasStillAlive; }; // Reset the list of removed objects this.resetRemoved = function() { this.removed = []; } // Remove objects marked for removal from the list this.finalizeRemoved = function() { for(var i=0,len=this.removed.length;io2.y+o2.h-1) || (o1.x+o1.w-1o2.x+o2.w-1)); }; What’s going on here is that the bottom edge of object one is checked against the bottom edge of object two to see if object one is to the right of object two. Next, the top edge of object one is checked against the bottom edge of object two and so on through each of the corresponding edges. If any of these are true, you know object one doesn’t overlap object two. By simply negating the result of this detection, you can tell if the two objects overlap. With a function in your pocket to determine overlap, it becomes easy to check one object against all the other objects in the list. this.collide = function(obj,type) { return this.detect(function() { if(obj != this) { var col = (!type || this.type & type) && board.overlap(obj,this) return col ? this : false; 30  ❘  CHAPTER 2  Making It a Game } }); }; Collide uses the detect function to match the passed-in object against all the other objects and returns the first object for which overlap returns true. The only complication is the support for an optional type parameter. The idea behind this is that different types of objects want to collide with only certain objects. Enemies, for example, don’t want to collide with themselves, but they do want to collide with the player and the player’s missiles. By doing a bitwise AND operation, collisions against objects of multiple types can be performed without the loss of speed that an array or hash lookup would require. One caveat is that each of the different types must be a power of two to pre- vent overlap of different types. For example, if types were defined as the following: var OBJECT_PLAYER = 1, OBJECT_PLAYER_PROJECTILE = 2, OBJECT_ENEMY = 4, OBJECT_ENEMY_PROJECTILE = 8; an enemy could check if it collides with a player or a player’s missile by doing a bitwise OR of the two types together: board.collide(enemy, OBJECT_PLAYER | OBJECT_PLAYER_PROJECTILE) Objects can also be assigned multiple types, and the collide function would still work as planned. With that, the GameBoard class is complete. See gameboard/engine.js for the full version of the object in the code for this chapter. Adding GameBoard into the Game With the GameBoard class complete, the next step is to add it into the game. A quick modification of the playGame function from game.js does the trick: var playGame = function() { var board = new GameBoard(); board.add(new PlayerShip()); Game.setBoard(3,board); } Reload the index.html file, and you should see exactly the same behavior as at the end of Chapter 1. All that’s been done is to have the GameBoard take over managing the ship sprite. This is less than impressive because so far the game isn’t putting the GameBoard class to good use because it just has a single sprite in it. This is remedied in the next section. FIRING MISSILES Now it’s time to give the player something to do besides just fly left and right across the screen. You are going to bind the spacebar to fire off a pair of projectiles. Firing Missiles  ❘  31 Adding a Bullet Sprite The first step to giving the player some destructive capacity is to create a blueprint for the player missile object. This object is added to the game at the player’s location whenever the player presses the fire key. The PlayerShip object didn’t use the object prototype to create methods because in general there is only one player in the game at a time so it’s unnecessary to optimize for object creation speed or memory footprint. To contrast, there are going to be a lot of PlayerMissiles added to the game over the course of a level, so making sure they are quick to create and small from a memory usage standpoint is a good idea. (The JavaScript garbage collector can cause noticeable hiccups in game performance, so making its job easier is in your best interest.) Because of the frequency with which PlayerMissile objects are going to be created, using object prototypes makes a lot of sense. Functions created on an object’s prototype need to be created and stored in memory only once. Add the following highlighted text to the top of game.js to put in the sprite definition for the missile (don’t forget the comma on the previous line): var sprites = { ship: { sx: 0, sy: 0, w: 37, h: 42, frames: 1 }, missile: { sx: 0, sy: 30, w: 2, h: 10, frames: 1 } }; Next add the full PlayerMissile object (see Listing 2-1) to the bottom of game.js: LISTING 2-1:  The PlayerMissile Object var PlayerMissile = function(x,y) { this.w = SpriteSheet.map['missile'].w; this.h = SpriteSheet.map['missile'].h; // Center the missile on x this.x = x - this.w/2; // Use the passed in y as the bottom of the missile this.y = y - this.h; this.vy = -700; }; PlayerMissile.prototype.step = function(dt) { this.y += this.vy * dt; if(this.y < -this.h) { this.board.remove(this); } }; PlayerMissile.prototype.draw = function(ctx) { SpriteSheet.draw(ctx,'missile',this.x,this.y); }; The initial version of the PlayerMissile class clocks in at a mere 14 lines and much of it is boil- erplate you’ve seen before. The constructor function simply sets up a number of properties on the sprite, pulling the width and height from the SpriteSheet. Because the player fires missiles verti- cally upward from a turret location, the constructor uses the passed-in y location for the location of D o wnload from Wow! eBook 32  ❘  CHAPTER 2  Making It a Game the bottom of the missile by subtracting the height of the missile to determine its starting y location. It also centers the missile on the passed-in x location by subtracting half the width of the sprite. As discussed previously, the step and draw methods are created on the prototype to be efficient. Because the player’s missile moves only vertically up the screen, the step function needs to adjust only the y property and check if the missile has moved completely off the screen in the y direction. If the missile has moved more than its height off the screen (that is, this.y < -this.h), it removes itself from the board. Finally, the draw method just draws the missile sprite at the missile’s x and y locations using the SpriteSheet object. Connecting Missiles to the Player To actually get a missile onto the screen, the PlayerShip needs to be updated to respond to the fire key and add a pair of missiles onto the screen for each of its two turrets. You also need to add in a reloading period to limit the speed at which missiles are fired. To put in this limit, you must add a new property called reload, which represents the remain- ing time before the next pair of missiles can be fired. You also must add another property called reloadTime, which represents the full reloading time. Add the following two initialization lines to the top of the PlayerShip constructor method: var PlayerShip = function() { this.w = SpriteSheet.map['ship'].w; this.h = SpriteSheet.map['ship'].h; this.x = Game.width / 2 - this.w / 2; this.y = Game.height - 10 - this.h; this.vx = 0; this.reloadTime = 0.25; // Quarter second reload this.reload = this.reloadTime; reload is set to reloadTime to prevent the player from immediately firing a missile when they press fire to start the game. Next, modify the step method to read as follows: this.step = function(dt) { if(Game.keys['left']) { this.vx = -this.maxVel; } else if(Game.keys['right']) { this.vx = this.maxVel; } else { this.vx = 0; } this.x += this.vx * dt; if(this.x < 0) { this.x = 0; } else if(this.x > Game.width - this.w) { this.x = Game.width - this.w } this.reload-=dt; if(Game.keys['fire'] && this.reload < 0) { Game.keys['fire'] = false; Adding Enemies  ❘  33 this.reload = this.reloadTime; this.board.add(new PlayerMissile(this.x,this.y+this.h/2)); this.board.add(new PlayerMissile(this.x+this.w,this.y+this.h/2)); } } This code adds two new player missiles on the left and right sides of the ship if the player presses the fire key and is not in the process of reloading. Firing a missile simply consists of adding it to the board at the right location. The reload property is also reset to reloadTime to add in a delay between missiles being fired. To ensure the player needs to press and release the spacebar to fire and can’t just hold it down, the key is set to false. (This doesn’t quite have the intended effect because keydown events are fired on repeat.) Reload the game (or fire up http://mh5gd.com/ch2/missiles/) and test out firing some missiles. You can adjust reloadTime to see the effect it has on the speed missiles are fired. ADDING ENEMIES A space shooter isn’t any fun without enemies, so next you will add some enemies into the game by creating an Enemy sprite class. Although there will be multiple types of enemies, they are all represented by the same class and differentiated only by different templates for their image and movement. Calculating Enemy Movement You define the movement for enemies with an equation that contains a few pluggable parameters that enable enemies to exhibit relatively complex behavior without a lot of code. The equation sets the velocity of an enemy at a given time since it was added to the board: vx = A + B * sin(C * t + D) vy = E + F * sin(G * t + H) All the letters A through H represent constant numbers. Don’t let these equations intimidate you. All they say is that the velocity of an enemy is based on a constant value plus a value that repeats cyclically. (Using a sine enables the cyclical value.) Using an equation such as this allows the game to add enemies that twirl around the screen in interesting patterns and adds some dynamism to the game that a bunch of enemies flying in a straight line wouldn’t. Sines and cosines are used often in game development for animation because they provide a mechanism for smooth move- ment transitions. See Table 2.1 for a description of the effect each parameter A–H has on the movement of an enemy. NOTE  Parabolas created with quadratic equations ( a + bx + cx*x ) are also use- ful for this but don't provide periodic behavior, so they aren’t quite as useful in this situation. 34  ❘  CHAPTER 2  Making It a Game TABLE 2-1:  Parameter Descriptions PARAMETER DESCRIPTION A Constant horizontal velocity B Strength of horizontal sinusoidal velocity C Period of horizontal sinusoidal velocity D Time shift of horizontal sinusoidal velocity E Constant vertical velocity F Strength of vertical sinusoidal velocity G Period of vertical sinusoidal velocity A number of different combinations of values produce different behaviors. If B and F are set to zero, then the enemy flies straight because the sinusoidal component in both directions is zero. If F and A are set to zero, then the enemy flies with a constant y velocity but moves back and forth smoothly in the x direction. You create a variety of different enemies in the section “Setting Up the Enemies” by setting different variations of parameters. In a production game, if you don’t want to worry about handling the math yourself, you could con- sider using a tweening engine such as TweenJS (www.createjs.com/TweenJS), which can handle smoothly moving objects from one position to another in a number of interesting manners. Constructing the Enemy Object You can create enemies from a blueprint that sets the sprite image used, the initial starting location, and the values for the movement of constants A–H. The constructor also enables an override object to be passed in to override the default blueprint settings. Much like PlayerMissile, the Enemy object adds methods onto the prototype to speed object cre- ation and reduce the memory footprint. This initial version of Enemy looks much like the previous two sprite classes that have been built (PlayerShip and PlayerMissile), with a constructor function shown in in Listing 2-2 that initial- izes some state; a step method that updates the position and checks if the sprite is out of bounds; and a draw function that renders the sprite. Because of the need to copy over from the blueprint and any override parameters and set up the velocity equation parameters, the constructor function is a little more complicated than previous ones. JavaScript doesn’t have a built-in method to easily copy attributes over from another object, so you need to roll your own loop over the attributes to do it. To prevent the need for the blueprint to set each of the parameters A–H, each of those are also be initialized to zero. Adding Enemies  ❘  35 LISTING 2-2:  The Enemy Constructor var Enemy = function(blueprint,override) { var baseParameters = { A: 0, B: 0, C: 0, D: 0, E: 0, F: 0, G: 0, H: 0 } // Set all the base parameters to 0 for (var prop in baseParameters) { this[prop] = baseParameters[prop]; } // Copy of all the attributes from the blueprint for (prop in blueprint) { this[prop] = blueprint[prop]; } // Copy of all the attributes from the override, if present if(override) { for (prop in override) { this[prop] = override[prop]; } } this.w = SpriteSheet.map[this.sprite].w; this.h = SpriteSheet.map[this.sprite].h; this.t = 0; } The constructor first copies three sets of objects into the this object: the base parameters, the blue- print, and the override. Because the enemy can have different sprites depending on the blueprint, the width and the height are set afterward based on the sprite property of the object. Finally, a t parameter is initialized to 0 to keep track of how long this sprite has been alive. If the repetition in this code bothers you, don’t worry! You clean it up in the section “Refactoring the Sprite Classes” later in this chapter. Stepping and Drawing the Enemy Object The step function (see Listing 2-3) for the enemy should update the velocity based on the aforemen- tioned equation. The this.t property needs to be incremented by dt to keep track of how long the sprite has been alive. Next, the equation from earlier in this chapter can be plugged directly into the step function to calculate the x and y velocity. From the x and y velocity, the x and y location are updated. Finally, the sprite needs to check if it’s gone off the board to the right or the left, in which case the enemy can remove itself from the page. LISTING 2-3:  The Enemy Step and Draw Methods Enemy.prototype.step = function(dt) { this.t += dt; this.vx = this.A + this.B * Math.sin(this.C * this.t + this.D); this.vy = this.E + this.F * Math.sin(this.G * this.t + this.H); this.x += this.vx * dt; this.y += this.vy * dt; if(this.y > Game.height || this.x < -this.w || this.x > Game.width) { continues 36  ❘  CHAPTER 2  Making It a Game this.board.remove(this); } } Enemy.prototype.draw = function(ctx) { SpriteSheet.draw(ctx,this.sprite,this.x,this.y); } The draw function is a near duplicate of the PlayerMissile object; the only difference is that it must look up which sprite to draw in a property called sprite. Adding Enemies on the Board Now you add some initial enemy sprites to the top of game.js along with a simple enemy blueprint for one enemy that can fly down the page: var sprites = { ship: { sx: 0, sy: 0, w: 37, h: 42, frames: 1 }, missile: { sx: 0, sy: 30, w: 2, h: 10, frames: 1 }, enemy_purple: { sx: 37, sy: 0, w: 42, h: 43, frames: 1 }, enemy_bee: { sx: 79, sy: 0, w: 37, h: 43, frames: 1 }, enemy_ship: { sx: 116, sy: 0, w: 42, h: 43, frames: 1 }, enemy_circle: { sx: 158, sy: 0, w: 32, h: 33, frames: 1 } }; var enemies = { basic: { x: 100, y: -50, sprite: 'enemy_purple', B: 100, C: 2 , E: 100 } }; Next, modify playGame to add a pair of enemies to the top of the page: var playGame = function() { var board = new GameBoard(); board.add(new Enemy(enemies.basic)); board.add(new Enemy(enemies.basic, { x: 200 })); board.add(new PlayerShip()); Game.setBoard(3,board); } Using the enemies object as a blueprint for the enemy makes adding an enemy onto the page as simple as calling new Enemy() with that blueprint. To make the second enemy appear to the right of the first, an override object is passed in setting x to 200. Reload the file, and when the game starts, you should have a couple of bad guys snake their way down the screen and then disappear off the bottom. You can also take a look at http://mh5gd. com/ch2/enemies to see the effect this code has. These enemies aren’t doing any collision detection, so they won’t interact with the player. The basic enemy has only three of the enemy movement parameters defined: B (horizontal sinusoi- dal movement), C (horizontal sinusoidal period), and E (vertical fixed movement). Play with these parameters to affect the movement. Increasing C, for example, increases the frequency with which the enemies bounce back and forth. LISTING 2-3  (continued) Refactoring the Sprite Classes  ❘  37 REFACTORING THE SPRITE CLASSES At this point the game has three different sprite classes that all share a lot of the same boilerplate code. This means it’s time to apply the Rule of Three. As described by Wikipedia, the rule is: Rule of three is a code refactoring rule of thumb to decide when a replicated piece of code should be replaced by a new procedure. It states that the code can be copied once, but that when the same code is replicated three times, it should be extracted into a new procedure. The rule was introduced by Martin Fowler in Refactoring and attributed to Don Roberts. http://en.wikipedia.org/wiki/Rule_of_three_(computer_programming) Even though Alien Invasion is a one-off game engine that isn’t intended to be turned into a general- purpose engine, it still pays to put in a little bit of time to refactor the code when it makes sense to clean up any rampant duplication and make the game easier to fix and extend. No one writes perfect code the first time, especially when prototyping and trying out new features. When that code works, however, failing to refactor and clean up code during development leads to technical debt. The more technical debt you have on a project, the more painful it is to make changes and add new features. Refactoring can clean up technical debt by removing unused code, reducing code duplication, and cleaning up abstractions, all things that don’t make your game better necessarily but make your life as a game developer better. In Alien Invasion, the main culprits of duplication in these three sprite classes are the boilerplate setup code and the draw method, which is the same across all three methods. It’s time to extract those into a base object called Sprite, which can handle initialization given a set of setup param- eters as well as a sprite to use. Inside the Enemy constructor, the three loops to copy one object into another is also a good opportunity for refactoring. If you haven’t done a lot of prototypical inheritance in JavaScript, the syntax may look strange. Because JavaScript doesn’t have the idea of classes, instead of defining a class that represents the inherited properties, you create a prototype object where JavaScript will look when a parameter isn’t defined on the actual object. Creating a Generic Sprite Class In this section you create the Sprite object that all other sprites inherit from. Open up engine.js and add the following code shown in Listing 2-4: LISTING 2-4:  A Generic Sprite Object var Sprite = function() { } Sprite.prototype.setup = function(sprite,props) { this.sprite = sprite; this.merge(props); continues 38  ❘  CHAPTER 2  Making It a Game this.frame = this.frame || 0; this.w = SpriteSheet.map[sprite].w; this.h = SpriteSheet.map[sprite].h; } Sprite.prototype.merge = function(props) { if(props) { for (var prop in props) { this[prop] = props[prop]; } } } Sprite.prototype.draw = function(ctx) { SpriteSheet.draw(ctx,this.sprite,this.x,this.y,this.frame); } This code goes into engine.js because it’s generic engine code versus game-specific code. The con- structor function is empty because each sprite has its own constructor function, and the Sprite object is created only once for each of the descendant sprite object definitions. Constructor func- tions in JavaScript don’t work the same as constructors in other OO languages such as C++. To get around this, you need a separate setup function to be called explicitly in the descendant objects. This setup method takes in the name of the sprite in the SpriteSheet and a properties object. The sprite is saved in the object, and then properties are copied over into the Sprite. The width and height are also set here as well. Because copying over properties into an object is such a common need, Sprite also defines a merge method that does just that. This method is used in the setup method. Finally, the draw method, which is nearly identical in every sprite so far, can be defined once here and then will be available in every other sprite. Refactoring PlayerShip Armed with the Sprite class, the PlayerShip object can be refactored to simplify setup. The new code is marked in bold in Listing 2-5: LISTING 2-5:  A Refactored PlayerShip var PlayerShip = function() { this.setup('ship', { vx: 0, frame: 1, reloadTime: 0.25, maxVel: 200 }); this.reload = this.reloadTime; this.x = Game.width/2 - this.w / 2; this.y = Game.height - 10 - this.h; this.step = function(dt) { if(Game.keys['left']) { this.vx = -this.maxVel; } else if(Game.keys['right']) { this.vx = this.maxVel; } else { this.vx = 0; } LISTING 2-4  (continued) Refactoring the Sprite Classes  ❘  39 this.x += this.vx * dt; if(this.x < 0) { this.x = 0; } else if(this.x > Game.width - this.w) { this.x = Game.width - this.w } this.reload-=dt; if(Game.keys['fire'] && this.reload < 0) { this.reload = this.reloadTime; this.board.add(new PlayerMissile(this.x,this.y+this.h/2)); this.board.add(new PlayerMissile(this.x+this.w,this.y+this.h/2)); } } } PlayerShip.prototype = new Sprite(); At the top of the constructor function, the setup method is called, wiping out some boilerplate code. A few of the properties are set when setup is called, but a few are set afterward because they depend on the values of the other properties such as the object’s width and height, which isn’t avail- able until after setup is called. Next, the draw method is removed because it is handled by Sprite. Finally, the code to actually set up PlayerShip’s prototype comes after the PlayerShip constructor function is defined. Refactoring PlayerMissile The PlayerMissile object was already compact, but refactoring helps make it even shorter. See Listing 2-6. LISTING 2-6:  Refactored PlayerMissile var PlayerMissile = function(x,y) { this.setup('missile',{ vy: -700 }); this.x = x - this.w/2; this.y = y - this.h; }; PlayerMissile.prototype = new Sprite(); PlayerMissile.prototype.step = function(dt) { this.y += this.vy * dt; if(this.y < -this.h) { this.board.remove(this); } }; The constructor method still needs to explicitly set the x and y location because these are dependent on the width and height of the sprite (which aren’t available until after setup is called). The step method is unaffected by the refactoring, and the draw method can be removed as it’s handled by Sprite. Refactoring Enemy The Enemy object benefits the most from the refactoring, particularly in the constructor method. Instead of using a number of loops to copy parameters into the object, a few calls to merge simplify the method down to three lines. See Listing 2-7. 40  ❘  CHAPTER 2  Making It a Game LISTING 2-7:  Refactored Enemy Object (Partial Code) var Enemy = function(blueprint,override) { this.merge(this.baseParameters); this.setup(blueprint.sprite,blueprint); this.merge(override); } Enemy.prototype = new Sprite(); Enemy.prototype.baseParameters = { A: 0, B: 0, C: 0, D: 0, E: 0, F: 0, G: 0, H: 0, t: 0 }; The step method is unaffected (and so isn't shown in Listing 2-7) and the draw method can be removed. Notice that merge is called explicitly to merge in the set of baseParameters and the override parameters. The predefined baseParameters object is also pulled out of the construc- tor and put into the prototype. Although not a huge optimization, it prevents the need for the static baseParameters object to be re-created each time a new Enemy is created just for the sake of being copied over into the object. Because baseParameters isn’t going to be modified, one copy of the object will do. HANDLING COLLISIONS Alien Invasion is slowly coming together. It now has a player, missiles, and enemies flying around the screen. Unfortunately, none of these pieces are interacting by blowing each other up as is expected in a save-the-planet-from-destruction shooter game. The good news is that the majority of the hard work for handling collisions has already been done. The GameBoard object already knows how to take two objects and figure out if they are overlapping as well as determine if one object is colliding with any others of a specific type. All that’s necessary now is to add the appropriate calls to those collision functions. For collisions, Alien Invasion can use two mechanisms. The first is to do proactive checks in every object’s step function against any objects it has an interaction with. The second would be to have a general collision phase where objects trigger collision events when they hit each other. The former is simpler to implement, whereas the latter offers better overall performance and can be better opti- mized. Alien Invasion is going to go the simpler route, but the platformer game built in Chapter 18, “Creating a 2-D Platformer,” uses the more complicated mechanism. Adding Object Types To ensure that objects collide only with objects that it makes sense for them to collide with, objects need to be assigned types. This was discussed at the beginning of the chapter but has not yet been implemented in the game. The first step is to determine the different object types the game has and add some constants to keep from having to use magic numbers in the code. Add the code from Listing 2-8 to the top of game.js to define five different types of objects. Handling Collisions  ❘  41 LISTING 2-8:  Object Types var OBJECT_PLAYER = 1, OBJECT_PLAYER_PROJECTILE = 2, OBJECT_ENEMY = 4, OBJECT_ENEMY_PROJECTILE = 8, OBJECT_POWERUP = 16; NOTE  Each of these types shown in Listing 2-8 is a power of two, which is an efficiency optimization to enable the use of bitwise logic as discussed earlier. Next, add three lines to game.js setting the type of each Sprite at an appropriate spot after each Sprite’s prototype assignment code: PlayerShip.prototype = new Sprite(); PlayerShip.prototype.type = OBJECT_PLAYER; ... PlayerMissile.prototype = new Sprite(); PlayerMissile.prototype.type = OBJECT_PLAYER_PROJECTILE; ... Enemy.prototype = new Sprite(); Enemy.prototype.type = OBJECT_ENEMY; Each object now has a type that can be used for collision detection. Colliding Missiles with Enemies To prevent duplicated effort, instead of objects checking for collisions with every type of object they might hit, objects check only against objects that they actually “want” to hit. This means that PlayerMissile objects check if they are colliding with Enemy objects, but Enemy objects won’t check if they are colliding with PlayerMissile objects. Doing so keeps the number of calculations down a little bit. Now that objects can be hit, they need to have a method to deal with what should happen when they are hit. To begin with, add a method to Sprite that removes an object whenever it gets hit. This method can be overridden down the road by the various inherited objects. Add the following function to the bottom of engine.js below the rest of the Sprite object definition: Sprite.prototype.hit = function(damage) { this.board.remove(this); } This initial version of the hit method just removes the object from the board, regardless of the amount of damage done. 42  ❘  CHAPTER 2  Making It a Game Add a damage value to the PlayerMissile constructor function: var PlayerMissile = function(x,y) { this.setup('missile',{ vy: -700, damage: 10 }); this.x = x - this.w/2; this.y = y - this.h; }; Next, open up game.js, and edit the PlayerMissile step method to check for collisions: PlayerMissile.prototype.step = function(dt) { this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_ENEMY); if(collision) { collision.hit(this.damage); this.board.remove(this); } else if(this.y < -this.h) { this.board.remove(this); } }; The missile checks to see if it’s colliding with any OBJECT_ENEMY type objects and then calls the hit method on whatever object it collides with. It then removes itself from the board because its job is done. Fire up the game, and you should be able to shoot down the two enemies flying down the screen. Colliding Enemies with the Player To make it a fair fight, enemies need to have the ability to take down the player as well when they make contact. Adding essentially the same chunk of code to the Enemy step method allows the Enemy to take out the player. Modify the step method to read as follows: Enemy.prototype.step = function(dt) { this.t += dt; this.vx = this.A + this.B * Math.sin(this.C * this.t + this.D); this.vy = this.E + this.F * Math.sin(this.G * this.t + this.H); this.x += this.vx * dt; this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER); if(collision) { collision.hit(this.damage); this.board.remove(this); } if(this.y > Game.height || this.x < -this.w || this.x > Game.width) { this.board.remove(this); } } Handling Collisions  ❘  43 This code is identical to the code added to the PlayerMissile object except that it calls collide with an OBJECT_PLAYER object type. After making those changes, fire up the game and let your player be taken out by one of the ships. Making It Go Boom So far the collisions have the correct effect; however, there’s something to be said for a more dramatic effect to liven things up. The sprites.png file has a nice explosion animation in there for just that reason. The explosion image was generated using the explosion generator on http://www.positech .co.uk/. Add the sprite definition to the top of game.js for the explosion: var sprites = { ship: { sx: 0, sy: 0, w: 37, h: 42, frames: 1 }, missile: { sx: 0, sy: 30, w: 2, h: 10, frames: 1 }, enemy_purple: { sx: 37, sy: 0, w: 42, h: 43, frames: 1 }, enemy_bee: { sx: 79, sy: 0, w: 37, h: 43, frames: 1 }, enemy_ship: { sx: 116, sy: 0, w: 42, h: 43, frames: 1 }, enemy_circle: { sx: 158, sy: 0, w: 32, h: 33, frames: 1 }, explosion: { sx: 0, sy: 64, w: 64, h: 64, frames: 12 } }; Now add some health to the blueprint for a basic enemy: var enemies = { basic: { x: 100, y: -50, sprite: 'enemy_purple', B: 100, C: 4, E: 100, health: 20 } }; Next, you need to override the default hit method from Sprite for the Enemy object. This method needs to reduce the health of the Enemy, so check if the Enemy has run out of health; if so add an explosion to the GameBoard at the center of the Enemy, as shown in Listing 2-9. LISTING 2-9:  Enemy Hit Method Enemy.prototype.hit = function(damage) { this.health -= damage; if(this.health <=0) { if(this.board.remove(this)) { this.board.add(new Explosion(this.x + this.w/2, this.y + this.h/2)); } } } Finally, the Explosion class needs to be built. The class is a basic sprite that when added onto the page just flips itself through its frames and then removes itself from the board. See Listing 2-10. 44  ❘  CHAPTER 2  Making It a Game LISTING 2-10:  The Explosion Object var Explosion = function(centerX,centerY) { this.setup('explosion', { frame: 0 }); this.x = centerX - this.w/2; this.y = centerY - this.h/2; this.subFrame = 0; }; Explosion.prototype = new Sprite(); Explosion.prototype.step = function(dt) { this.frame = Math.floor(this.subFrame++ / 3); if(this.subFrame >= 36) { this.board.remove(this); } }; The Explosion constructor method takes the passed in centerX and centerY position and adjusts the x and y location by moving the sprite half of its width to the left and half the height up. The step method doesn’t need to worry about moving the explosion each frame; it just needs to update the subFrame property to cycle through each of the frames of the explosion animation. Each frame of the explosion animation plays for three game frames to make it last a little bit longer. When all 36 subFrames of the explosion have played through (12 actual frames), the Explosion removes itself from the board. Reload the game, and try to take out the enemies flying down the screen. It should take two missiles to take out an enemy now, but that enemy should explode in a nice fiery blast. REPRESENTING LEVELS Alien Invasion now has all the mechanics necessary to play the game. The only missing component is to put together some level data and a mechanism for adding enemy ships onto the screen. Before getting into the levels, add a few more enemy types to give some variety to the page. Setting Up the Enemies You could create an endless number of variations of enemy movement, but for this game you’ll set up five different types of enemy behavior using the various enemy sprite types as a start. You can play with the definitions and add more if you like. You could make a number of other varia- tions, but this set of five is a good start. Replace the enemies definition at the top of game.js with Listing 2-11. LISTING 2-11:  Enemy Definitions var enemies = { straight: { x: 0, y: -50, sprite: 'enemy_ship', health: 10, E: 100 }, Representing Levels  ❘  45 ltr: { x: 0, y: -100, sprite: 'enemy_purple', health: 10, B: 200, C: 1, E: 200 }, circle: { x: 400, y: -50, sprite: 'enemy_circle', health: 10, A: 0, B: -200, C: 1, E: 20, F: 200, G: 1, H: Math.PI/2 }, wiggle: { x: 100, y: -50, sprite: 'enemy_bee', health: 20, B: 100, C: 4, E: 100 }, step: { x: 0, y: -50, sprite: 'enemy_circle', health: 10, B: 300, C: 1.5, E: 60 } }; With just a variation on the movement parameters, the enemies have wildly differing movement styles. The straight enemy has only vertical velocity parameter E, so it moves downward at a con- stant rate. The ltr enemy (short for left-to-right) has a constant vertical velocity, but then a sinusoidal hori- zontal velocity (parameters B and C) gives it a smooth sweeping motion from left to right. The circle has primarily sinusoidal motion in both directions, but adds a time shift in the Y direction with parameter H to give a circular motion to the enemy. The wiggle and the step enemies have the same parameters set, just to different amounts. With a smaller B value and larger C and E values, the wiggle enemy just snakes down the screen, while the step enemy, with a larger B and a smaller C and E, makes its way down the page slowly by sliding back and forth across the whole screen. Setting Up Level Data Knowing that levels in Alien Invasion will be populated with strings of enemies of the same type, the next step is to figure out a good mechanism for encoding the level data in a compact manner. When that has been figured out, you can work backward and figure out what the level object needs to do to spawn those enemies onto the page. Working from how you want to use a piece of code back to the implementation is a good way to end up with code that is easy to work with. It may take a little bit more work on the implementation, but you’ll be happier in the long run. One initial impulse you might have would be to encode the starting location of each enemy and each enemy type in an array. Because a level might have a hundred or more enemies, this would get labo- rious quickly. A better option is to encode each string of enemies as a single entry with a start time, end time, and per-enemy delay. This way each string of enemies is succinctly encoded into the level data, and you can take one look at the definition and get a good understanding of what's going on. Add the level data for level 1 to the top of game.js by inserting Listing 2-12. LISTING 2-12:  Level Data var level1 = [ // Start, End, Gap, Type, Override [ 0, 4000, 500, 'step' ], [ 6000, 13000, 800, 'ltr' ], [ 12000, 16000, 400, 'circle' ], [ 18200, 20000, 500, 'straight', { x: 150 } ], [ 18200, 20000, 500, 'straight', { x: 100 } ], continues 46  ❘  CHAPTER 2  Making It a Game [ 18400, 20000, 500, 'straight', { x: 200 } ], [ 22000, 25000, 400, 'wiggle', { x: 300 }], [ 22000, 25000, 400, 'wiggle', { x: 200 }] ]; Each line gives a start time in milliseconds, an end time in milliseconds, and a gap in milliseconds between each enemy followed by the enemy type and any override parameters. Loading and Finishing a Level Defining how the level class is going to consume level data is half the battle; the other half is decid- ing on how the Level object will be used by the PlayGame method to start the game. The easiest solution is to simply create another sprite-like object that is added to the game board and spawns enemies at the correct time intervals. When the Level is out of enemies, it can make a callback to indicate success. Again working backward, you write the way the Level object should be used before tackling the actual implementation. Replace the existing playGame method with the one shown in Listing 2-13, and add new winGame and loseGame methods as well. LISTING 2-13:  Modified Game Initialization Methods var playGame = function() { var board = new GameBoard(); board.add(new PlayerShip()); board.add(new Level(level1,winGame)); Game.setBoard(3,board); } var winGame = function() { Game.setBoard(3,new TitleScreen("You win!", "Press fire to play again", playGame)); } var loseGame = function() { Game.setBoard(3,new TitleScreen("You lose!", "Press fire to play again", playGame)); } Adding the level becomes as trivial as adding a new Level sprite to the board and passing in the level data level1 and the success callback winGame. The winGame method just reuses the TitleScreen object to show a success message and a message letting the player know they can replay the game. The loseGame method works the same way as the winGame method but with a less congratulatory message. Lose game so far isn’t called yet anywhere, but this can be remedied by adding a custom LISTING 2-12  (continued) Representing Levels  ❘  47 hit method to the PlayShip object. Add the following definition to game.js under the rest of the PlayerShip methods (make sure to add it underneath where the prototype is set): PlayerShip.prototype.hit = function(damage) { if(this.board.remove(this)) { loseGame(); } } The PlayerShip doesn’t get an explosion when it dies; this is just for simplicity’s sake. However, you could add one in and add a callback to the end of the explosion step to show the loseGame screen only after the PlayerShip has finished blowing up. Implementing the Level Object All that’s left now is the implementation of the Level object. This object’s duties have already been defined by how the level data and playGame and winGame methods were set up. The Level object has only two methods: the constructor function, which makes a copy of the level data for its own use (and modification) and the step method, which loops through the level data and adds enemies onto the board as necessary. Add the constructor function shown in Listing 2-14 to the bottom of engine.js. LISTING 2-14:  Level Object Constructor var Level = function(levelData,callback) { this.levelData = []; for(var i =0; i curShip[1]) { // If so, remove the entry remove.push(curShip); } else if(curShip[0] < this.t) { // Get the enemy definition blueprint var enemy = enemies[curShip[3]], override = curShip[4]; // Add a new enemy with the blueprint and override this.board.add(new Enemy(enemy,override)); // Increment the start time by the gap curShip[0] += curShip[2]; } idx++; } // Remove any objects from the levelData that have passed for(var i=0,len=remove.length;i Summary  ❘  49 the length of between-enemy gap. Modifying the start time allows the step method to handle adding a string of enemies on the page without any additional logic. ➤➤ The second section of the step method should look familiar from the GameBoard object. All it is does is look at all the entries in levelData that have been added to the remove list and splices them out of the array, much like the finalizeRemoved method in GameBoard did. ➤➤ The final section consists of a conditional that checks if there are no more upcoming enemies in levelData and if the number of enemies on the board is zero. If both of those conditions are true, then the level is considered over, and the callback, if one is set, is called. This allows the level to know when it has been completed. Finally, the Level object needs a draw method so that it can play nicely with GameBoard, but that method is just a stub that doesn’t actually do anything. Fire up the game with all the Level pieces in, and you should see the game and enemies in all their glory. SUMMARY Congratulations! You took the stub of a game—a lonely spaceship flying around empty space—and turned it into a playable game with waves of enemies and win and failure screens. You may have noticed a slight issue so far, though—it's not mobile. The next chapter remedies this when you add touch controls and support for resizing. A few finishing touches, such as scoring, can turn Alien Invasion into a polished, playable mobile game that works on the desktop as well. Finishing Up and Going Mobile WHAT’S IN THIS CHAPTER? ➤➤ Exploring scene management ➤➤ Adding projectiles and enemies ➤➤ Using collision detection ➤➤ Creating explosions WROX.COM CODE DOWNLOADS FOR THIS CHAPTER The wrox.com code downloads for this chapter are found at www.wrox.com/remtitle .cgi?isbn=9781118301326 on the Download Code tab. The code is in the chapter 03 download and individually named according to the names throughout the chapter. INTRODUCTION One of the much-touted advantages of HTML5 is its support on mobile devices, something that, despite the name of the book, has been ignored in the game so far. This is remedied in this chapter. Adding mobile support to Alien Invasion means recognizing when the game is played on a touch device and responding correctly. In this case it means adding in touch con- trols and resizing the game to fit the device. ADDING TOUCH CONTROLS Since the introduction of the iPhone in 2007, the direction of input mobile devices has been clear: The touchscreen has won. To make Alien Invasion playable on mobile and table devices, it must be playable with only the screen as an input device. 3 52  ❘  CHAPTER 3  Finishing Up and Going Mobile Drawing Controls To make mobile gameplay possible, the common solution is to add visible touch controls to the screen. These controls can consist of three square buttons at the bottom of the page: a left arrow to move the ship left, a right arrow to move the ship right, and an "A" button to fire. To add in the controls, a new game board at a higher position than anything else is added in. Because it will be rendered after everything else, the controls always sit nicely on top of the page. The game needs to handle different screen resolutions. To this end, instead of drawing fixed size input squares (which could end up being too large or too small depending on the device), the game adjusts the size of the squares based on the width of the game. Based on some informal testing, dividing the width of the game into five regions works well enough. Buttons are large enough to be hit easily but don't take up too much screen real estate. The first step is to add the controls onto the page. Open up engine.js and add the following object (as shown in Listing 3-1) to the bottom. LISTING 3-1:  TouchControls for Alien Invasion var TouchControls = function() { var gutterWidth = 10; var unitWidth = Game.width/5; var blockWidth = unitWidth-gutterWidth; this.drawSquare = function(ctx,x,y,txt,on) { ctx.globalAlpha = on ? 0.9 : 0.6; ctx.fillStyle = "#CCC"; ctx.fillRect(x,y,blockWidth,blockWidth); ctx.fillStyle = "#FFF"; ctx.textAlign = "center"; ctx.globalAlpha = 1.0; ctx.font = "bold " + (3*unitWidth/4) + "px arial"; ctx.fillText(txt, x+blockWidth/2, y+3*blockWidth/4+5); }; this.draw = function(ctx) { ctx.save(); var yLoc = Game.height - unitWidth; this.drawSquare(ctx,gutterWidth,yLoc, "\u25C0", Game.keys['left']); this.drawSquare(ctx,unitWidth + gutterWidth,yLoc, "\u25B6",Game.keys['right']); this.drawSquare(ctx,4*unitWidth,yLoc,"A",Game.keys['fire']); ctx.restore(); Adding Touch Controls  ❘  53 }; this.step = function(dt) { }; }; This object sets up some values based on the width of the game that will be used to draw objects. Each block is set up to be 1/5th of the width minus a 10-pixel gutter to separate the buttons. For each frame, the object’s draw method is called. This method calls an internal method, drawSquare, which draws a single rectangle with some text on it at the specified location. Instead of drawing tri- angles, the code uses the Unicode UTF-8 symbols for the left and right arrows. The characters \u25C0 and \u25B6 represent left and right triangles. NOTE  Unicode characters can be expressed in JavaScript by prefixing backslash u (\u) in front of the UTF-8 code for that letter or symbol. The draw method uses the save and restore methods on the 2-D canvas context to prevent the changes to opacity and font from affecting any other canvas calls. The drawSquare method does most of the actual work. It takes in an x and y location, the text to draw on the button, and determines whether the button is currently held down; then it draws a filled rectangle and text to create the button. The button state is used to set the opacity using the globalAlpha property for the background of the button so that players can see when they press down the button. To actually have this board appear, it needs to be added to the Game object on initialization. Modify the Game.initialize in the engine.js method by adding the setBoard call as well as a couple of properties onto Game that are used by TouchControls: // Game Initialization this.initialize = function(canvasElementId,sprite_data,callback) { ... this.setupInput(); this.setBoard(4,new TouchControls()); this.loop(); SpriteSheet.load(sprite_data,callback); }; // Game Initialization this.initialize = function(canvasElementId,sprite_data,callback) { this.canvas = document.getElementById(canvasElementId); this.width = this.canvas.width; this.height= this.canvas.height; this.ctx = this.canvas.getContext && this.canvas.getContext('2d'); if(!this.ctx) { return alert("Please upgrade your browser to play"); } this.setupInput(); this.loop(); SpriteSheet.load(sprite_data,callback); }; 54  ❘  CHAPTER 3  Finishing Up and Going Mobile Touch controls aren’t yet enabled to control the player, but if you use the keyboard, you should see the buttons light up in response to the controls as if they were pressed. Responding to Touch Events To make these boxes work with touch events, the game needs to be set up to listen for a new set of browser events: touchstart, touchmove, and touchend. You’ve most likely come across browser events before, such as the well-known click event. These new events are available on non-Windows touch devices only and are special in that they contain not only the details about the event, but also about any other touches currently on the device. The details for these additional events are held in three arrays inside of the event object, described in Table 3-1. TABLE 3-1:  Touch Event Properties EVENT PROPERTY DESCRIPTION event.touches All the touches currently on the devices event.targetTouches All the touches on the same DOM object as the event event.changedTouches All the touches changed in this event The game uses both the targetTouches array and the changedTouches array to good effect. The targetTouches is used for the two buttons on the left that control movement. You want the user to be able to press and hold down either button to move left and right. As such, each time there is a touch event, the game sees if there are any touches currently hitting either of those two buttons and marks the button as down if that is the case, even if the touch that triggered the event isn’t on either button. For firing, as a design choice, the game requires the player to press the Fire button each time they want to fire a missile. (Holding down the fire key doesn't count.) For that reason, the game counts the fire key as down only if the user actually pressed that key in the last step. Add the code in Listing 3-2 to the TouchControls class before the ending curly brace: LISTING 3-2:  TouchControls touch tracking var TouchControls = function() { ... this.step = function(dt) { }; this.trackTouch = function(e) { var touch, x; e.preventDefault(); Game.keys['left'] = false; Game.keys['right'] = false; for(var i=0;i unitWidth && x < 2*unitWidth) { Game.keys['right'] = true; } } if(e.type == 'touchstart' || e.type == 'touchend') { for(i=0;i 4 * unitWidth) { Game.keys['fire'] = (e.type == 'touchstart'); } } } }; Game.canvas.addEventListener('touchstart',this.trackTouch,true); Game.canvas.addEventListener('touchmove',this.trackTouch,true); Game.canvas.addEventListener('touchend',this.trackTouch,true); Game.playerOffset = unitWidth + 20; }; In the preceding description, the controls have been referred to as “buttons” because that is the way they are drawn. But if you examine the hit detection code, you notice they are actually targeted as columns. Only the x location of the hit is used to determine if a user is pressing a button. This is a behavior used in a number of mobile app store games, and it works well because players can be less exact when trying to press the buttons and can place their hands vertically on the device where they feel comfortable. This code adds in a method called trackTouch to TouchControls that acts as the universal handler for any touch events. The first thing trackTouch does is call e.preventDefault(). This gets rid of any existing behavior that might be associated with that event, including scrolling, clicking, zoom- ing, and so on. Doing this prevents the page from exhibiting any default behavior when the user interacts with the canvas element. (At least on iOS it does. As of this writing, on Android you can still trigger scroll and zoom via multitouch. Hopefully that will be fixed soon.) Next, the trackTouch method sets both the left and right keys to false. It does this because either or both of these keys will be set back to true if there is a touch noted on the button. Performing the detection this way allows users to slide their finger between the two buttons to move back and forth or swap fingers without the game missing a beat. For any touches, the game sees if they are located in the first two units on the left of the canvas and if so maps those to the left and right movement buttons. For firing missiles, only the changedTouches are looked at. This is, as mentioned before, because the player is forced to press the Fire button repeatedly to fire missiles in rapid succession. The game checks if any of the touches are in the last section on the right and if so sets the fire key to true or false depending on whether the event is a touchstart or a touchend, respectively. 56  ❘  CHAPTER 3  Finishing Up and Going Mobile Finally a variable called playerOffset is set to the unitWidth + 20. The point of this is to have the player move up on the screen if touch controls are present, but sit on the bottom of the screen if the game is played on a desktop browser. For this to have an effect, the PlayerShip needs to be initialized with a new y location. Modify the bolded line of PlayerShip in game.js: var PlayerShip = function() { this.setup('ship', { vx: 0, reloadTime: 0.25, maxVel: 200 }); this.reload = this.reloadTime; this.x = Game.width/2 - this.w / 2; this.y = Game.height - Game.playerOffset - this.h; ... The player will now be set up off the bottom of the screen as is appropriate for the device to prevent the control buttons from obscuring gameplay. Testing on Mobile To test this game on an actual mobile device, you need to run the game on a web server, either by setting one up on your development machine or by deploying the code to a web host. Both of these methods are a bit outside the scope of this book. NOTE  You can find lots of hosting companies on the web of varying quality. DreamHost (http://dreamhost.com) is usually an acceptable choice if you are just starting. In the long run, you need to test your games without having to deploy them. This enables you to make changes and quickly test them without any intermediate steps to slow down the process. If you use Windows, you can most likely install IIS, depending on your version of Windows, but IIS configuration can be involved and, unless you’re comfortable with window configuration tasks, you may want to use one of the following options. If you use a Mac, you can access Web Sharing from the Sharing section of System Preferences. On Linux you can install Apache. If getting a fully configured web server seems daunting, you can check out WAMP at http://www .wampserver.com/en/. WAMP is a project designed to give you a zero-configuration Apache server on Windows. Web sharing on OS X and native packaging of Apache on Linux is usually a better option for the other platforms. For simple needs you can also try mongoose at http://code.google .com/p/mongoose/, a web server that you execute from the directory you want to serve. Assuming you are on a network with Wi-Fi, and your development machine and your mobile device are on the same network, you should now access your development machines from your mobile device when you have a web server set up and configured and your files are in the proper location. (This depends on the server and configuration.) Look up the IP address for your machine on the local network. This is most likely different from the Public IP address that machines on the web see because most Wi-Fi networks are behind a router. To find your IP address on Windows, the easiest way is to bring up the Command Prompt program (usually in Accessories) and type ipconfig. Maximizing the Game  ❘  57 You should see a number that looks like xxx.xxx.xxx.xxx (usually something like 192.168.0.50) in addition to some other cruft. You may see a couple of other IP addresses that end in 1, such as 192.168.0.1. This is the gateway address and not the address of your computer. On a Mac or Linux, bring up Terminal and type ifconfig. On Linux you may need to type sudo ifconfig. Again you should see a number that looks like an IP address among a bunch of other lines of information. Armed with that IP address and the path underneath the document root (the directory where your web server serves files from) of your game, you should now bring up your game on a mobile device by typing in the IP address followed by the path. You can also run the version of the game to this point at http://mh5gd.com/ch3/touch/. If you fire the game up on a mobile device, you immediately notice a problem: While the game is playable, it’s small by default, and the canvas element is overriding the touch events, which means zooming in is difficult. (You can zoom by pinching on the whitespace around the canvas.) This is remedied in the next section. MAXIMIZING THE GAME Screen real estate on mobile devices is valuable especially for mobile games. The last thing you want to do is waste some of that real estate by not having maximized the game. Setting the Viewport The first step is to tell the browser that you don’t want to let users zoom in and out of the page. This is done by setting a viewport tag in the HTML. The viewport tag began its life as an iOS-only feature but has since spread to Android as well. Add the following to the of your HTML document. This tag tells the browser to set the width of the page to the actual device’s pixel width and not to let the user zoom in and out. Chapter 6, “Being a Good Mobile Citizen,” discusses this tag in depth. If you reload the page, you notice the game is zoomed in a bit but still doesn’t correctly fit on the page. Resizing the Canvas To fix the size issue and set the game up on the page so it fits as well as possible, there are a few extra steps that need to be taken. This is more difficult than it may seem due to various mobile peculiarities. Chapter 6 covers this topic in depth, but following is the basic pseudo-code: Check if browser has support for touch events Exit early if screen is larger than a max size or no touch support Check if the user is in landscape mode, 58  ❘  CHAPTER 3  Finishing Up and Going Mobile if so, ask them to rotate the browser Resize container to be larger than the page to allow removal of address bar Scroll window slightly to force removal of address bar. Set the container size to match the window size Check if you're on a larger device (like a tablet) if so, set the view size to be twice the pixel size for performance If not, set canvas to match the size of the window. Finally, set the canvas to absolute position in the top left of the window Moving on to the actual code, add the method from Listing 3-3 to the bottom of the definition of the Game object in engine.js before the return statement: LISTING 3-3:  setupMobile this.setupMobile = function() { var container = document.getElementById("container"), hasTouch = !!('ontouchstart' in window), w = window.innerWidth, h = window.innerHeight; if(hasTouch) { mobile = true; } if(screen.width >= 1280 || !hasTouch) { return false; } if(w > h) { alert("Please rotate the device and then click OK"); w = window.innerWidth; h = window.innerHeight; } container.style.height = h*2 + "px"; window.scrollTo(0,1); h = window.innerHeight + 2; container.style.height = h + "px"; container.style.width = w + "px"; container.style.padding = 0; if(h >= this.canvas.height * 1.75 || swx >= this.canvas.height * 1.75) { this.canvasMultiplier = 2; this.canvas.width = w / 2; this.canvas.height = h / 2; Maximizing the Game  ❘  59 this.canvas.style.width = w + "px"; this.canvas.style.height = h + "px"; } else { this.canvas.width = w; this.canvas.height = h; } this.canvas.style.position='absolute'; this.canvas.style.left="0px"; this.canvas.style.top="0px"; }; The innerWidth and innerHeight need to be checked multiple times. This is because the size of the window changes over the course of the method call after the user rotates the device and after the window.scrollTo method is called to remove the address bar. The other trick is that the CSS size of the canvas element can be set independently from its pixel size (specified with the width and height attributes on the tag.) This enables you to scale the visual size of the element up without having to push lots more pixels. The downside to this is that pixels will be effectively four times as large, making the game look slightly pixelated. In the case of a retro-shooter such as Alien Invasion, this isn’t a huge deal, but it’s something to note. The setupMobile now must be called from Game.initialize. In addition, the game should add touch controls onto the page if only they are supported by the device. Modify the method to read // Game Initialization this.initialize = function(canvasElementId,sprite_data,callback) { this.canvas = document.getElementById(canvasElementId); this.playerOffset = 10; this.canvasMultiplier= 1; this.setupMobile(); this.width = this.canvas.width; this.height= this.canvas.height; this.ctx = this.canvas.getContext && this.canvas.getContext('2d'); if(!this.ctx) { return alert("Please upgrade your browser to play"); } this.setupInput(); if(this.mobile) { this.setBoard(4,new TouchControls()); } this.loop(); SpriteSheet.load(sprite_data,callback); }; With a check for this.mobile, the game will add only the visual touch controls and bind to touch events if the device supports it. 60  ❘  CHAPTER 3  Finishing Up and Going Mobile Adding to the iOS Home Screen There’s a last set of meta tags needed to reach HTML5-gaming nirvana: full-screen play. This code works only on an iOS device, iPad, iPhone, or iPod Touch. Add the following two tags to the below the viewport declaration: Now reload the game, and then click the button to add it to your home screen. With the excep- tion of a small sliver of status bar at the top of the page, your game can now run full screen. (See Chapter 6 for a full explanation of these tags.) You can also run the version of the game to this point at http://mh5gd.com/ch3/resize. ADDING A SCORE There’s still one obvious piece to the game that is clearly missing: a point system for users to brag about to their friends. This is something that you can remedy quickly by adding a new game board to the game. Add the contents of Listing 3-4 to the bottom of engine.js. LISTING 3-4:  GamePoints var GamePoints = function() { Game.points = 0; var pointsLength = 8; this.draw = function(ctx) { ctx.save(); ctx.font = "bold 18px arial"; ctx.fillStyle= "#FFFFFF"; var txt = "" + Game.points; var i = pointsLength - txt.length, zeros = ""; while(i-- > 0) { zeros += "0"; } ctx.fillText(zeros + txt,10,20); ctx.restore(); } this.step = function(dt) { } } This object has one purpose in its life: to draw the score in the top left of the game. The current score for the game is stored directly on the Game object in a property named points. Every time Making It a Fair Fight  ❘  61 a new GamePoints object is created, the game assumes a new game is beginning and resets the score to 0. For every frame, the game grabs the current score and pads it with leading zeros so that it’s always pointsLength digits long. It then calls fillText to draw the points onto the screen. To get the points onto the page, a GamePoints object needs to be created. Open up game.js and add the initializer to the fifth board: var playGame = function() { var board = new GameBoard(); board.add(new PlayerShip()); board.add(new Level(level1,winGame)); Game.setBoard(3,board); Game.setBoard(5,new GamePoints(0)); }; Board 5 was chosen because Board 4 was just used by the TouchControls in the last section. If you were to reload the game, you’d now see the points in the top left of the page, but they are sadly stuck at zero. Because the player should get points every time an enemy is killed, the easiest thing to do is add some logic to the Enemy.hit method. Modify that method in game.js to read: Enemy.prototype.hit = function(damage) { this.health -= damage; if(this.health <=0) { if(this.board.remove(this)) { Game.points += this.points || 100; this.board.add(new Explosion(this.x + this.w/2, this.y + this.h/2)); } } }; The points are increased on a per-enemy basis, but if the enemy doesn’t have a point property set, it defaults to 100. You can modify the enemies blueprint to make the point amounts vary by enemy type. Reload the game, and you should be able rack up a score. You can also run the version of the game to this point at http://mh5gd.com/ch3/score. MAKING IT A FAIR FIGHT Alien Invasion is now down to its last enhancement, giving the enemies a little bit of fire power to fight back. Cribbing from PlayerMissile, the game needs an object, EnemyMissile, to represent the enemy projectiles being fired. Add the code in Listing 3-5 to the bottom of game.js to create EnemyMissile. 62  ❘  CHAPTER 3  Finishing Up and Going Mobile LISTING 3-5:  The EnemyMissile object var EnemyMissile = function(x,y) { this.setup('enemy_missile',{ vy: 200, damage: 10 }); this.x = x - this.w/2; this.y = y; }; EnemyMissile.prototype = new Sprite(); EnemyMissile.prototype.type = OBJECT_ENEMY_PROJECTILE; EnemyMissile.prototype.step = function(dt) { this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER) if(collision) { collision.hit(this.damage); this.board.remove(this); } else if(this.y > Game.height) { this.board.remove(this); } }; EnemyMissile is much like the evil twin to PlayerMisisle. It has a different vertical direction, a different type, a different type to collide against, and a different check for when it’s off the board. The functionality is all the same; it’s just doing it in reverse. To get EnemyMissile objects onto the page, the Enemy step function needs to fire some off at some random interval. As an added complication, some enemies can fire two missiles at a time, much like the player, and some can fire just one, straight down the center. The sprite enemy_missile also needs to be defined, so add this entry to the sprites list at the top of game.js: var sprites = { ship: { sx: 0, sy: 0, w: 37, h: 42, frames: 1 }, missile: { sx: 0, sy: 30, w: 2, h: 10, frames: 1 }, enemy_purple: { sx: 37, sy: 0, w: 42, h: 43, frames: 1 }, enemy_bee: { sx: 79, sy: 0, w: 37, h: 43, frames: 1 }, enemy_ship: { sx: 116, sy: 0, w: 42, h: 43, frames: 1 }, enemy_circle: { sx: 158, sy: 0, w: 32, h: 33, frames: 1 }, explosion: { sx: 0, sy: 64, w: 64, h: 64, frames: 12 }, enemy_missile: { sx: 9, sy: 42, w: 3, h: 20, frame: 1 } }; Modify the Enemy object as highlighted here to add in missile firing capabilities: Enemy.prototype = new Sprite(); Enemy.prototype.type = OBJECT_ENEMY; Enemy.prototype.baseParameters = { A: 0, B: 0, C: 0, D: 0, E: 0, F: 0, G: 0, H: 0, t: 0, firePercentage: 0.01, Making It a Fair Fight  ❘  63 reloadTime: 0.75, reload: 0 }; Enemy.prototype.step = function(dt) { this.t += dt; this.vx = this.A + this.B * Math.sin(this.C * this.t + this.D); this.vy = this.E + this.F * Math.sin(this.G * this.t + this.H); this.x += this.vx * dt; this.y += this.vy * dt; var collision = this.board.collide(this,OBJECT_PLAYER); if(collision) { collision.hit(this.damage); this.board.remove(this); } if(this.reload <= 0 && Math.random() < this.firePercentage) { this.reload = this.reloadTime; if(this.missiles == 2) { this.board.add( new EnemyMissile(this.x+this.w-2,this.y+this.h/2) ); this.board.add( new EnemyMissile(this.x+2,this.y+this.h/2) ); } else { this.board.add( new EnemyMissile(this.x+this.w/2,this.y+this.h) ); } } this.reload-=dt; if(this.y > Game.height || this.x < -this.w || this.x > Game.width) { this.board.remove(this); } }; The first change affects baseParameters. A couple of additional defaults need to be added to the enemy to control the likelihood of firing and the speed at which the enemy can fire: firePercent- age and reloadTime, respectively. firePercentage is a number against which a random number is checked. If the random number is less than firePercentage, the enemy fires one or more missiles. Because this method is called each step frame, firePercentage needs to be a relatively small number to prevent the enemies from firing constantly. Next is reloadTime and reload, which work exactly like their PlayerShip counterparts, prevent- ing missiles from being fired in rapid succession. 64  ❘  CHAPTER 3  Finishing Up and Going Mobile The code to actually fire missiles also matches the code from the player, except that based on the number of missiles the Enemy has been configured with (1 or 2), the code needs to check whether to send one missile firing from the center of the enemy or two missiles firing from the left and the right side of the Enemy. Much like PlayerShip, the Enemy needs be prevented from firing missiles in rapid succession. To prevent this, the reload time is checked, and only after the Enemy reloads its weapons does it check against a randomly generated number to see if it should fire. If you load up the game, you should have enemies firing missiles as expected; however, all the ene- mies will be firing just one missile at the same frequency. To adjust the frequency of firing, you need to modify the enemy blueprints at the top of game.js. Modify the enemies array to have the ltr and wiggle enemies each fire two missiles at a time (matching their sprite image) and reduce the firePercentage of the straight and wiggle enemies to 0.001 to prevent them from firing too many missiles at once, as shown here: var enemies = { straight: { x: 0, y: -50, sprite: 'enemy_ship', health: 10, E: 100, firePercentage: 0.001 }, ltr: { x: 0, y: -100, sprite: 'enemy_purple', health: 10, B: 75, C: 1, E: 100, missiles: 2 }, circle: { x: 250, y: -50, sprite: 'enemy_circle', health: 10, A: 0, B: -100, C: 1, E: 20, F: 100, G: 1, H: Math.PI/2 }, wiggle: { x: 100, y: -50, sprite: 'enemy_bee', health: 20, B: 50, C: 4, E: 100, firePercentage: 0.001, missiles: 2 }, step: { x: 0, y: -50, sprite: 'enemy_circle', health: 10, B: 150, C: 1.2, E: 75 } }; With that, reload the game, and you should have a playable game with active enemies. You can also play the game at http://mh5gd.com/ch3/fair/. SUMMARY It’s been a whirlwind in the first three chapters, having gone from making the first few marks onto the canvas to building a fully functional mobile space shooter. As a demo game, Alien Invasion isn’t bad, but as a full-fledged space shooter there’s still lots that could be done: high scores, ship anima- tions, sounds, longer and varied levels, new enemies, and boss fights. The good news is that the code on Github at https://github.com/cykod/AlienInvasion can be forked and enhanced. If you’ve been following along, you’ve stepped through every line of the game and should know it inside and out. Check the readme file for what others have done. PART II Mobile HTML5 ⊲⊲ CHAPTER 4:  HTML5 for Mobile ⊲⊲ CHAPTER 5:  Learning Some Helpful Libraries ⊲⊲ CHAPTER 6:  Being a Good Mobile Citizen Download from Wow! eBook HTML5 for Mobile WHAT’S IN THIS CHAPTER? ➤➤ Getting acquainted with the history behind HTML5 ➤➤ Understanding feature detection and progressive enhancement ➤➤ Using HTML5 for gaming ➤➤ Using HTML5 for mobile ➤➤ Understanding the state of mobile browsers WROX.COM CODE DOWNLOADS FOR THIS CHAPTER The wrox.com code downloads for this chapter are found at www.wrox.com/remtitle .cgi?isbn=9781118301326 on the Download Code tab. The code is in the chapter 04 download and individually named according to the names throughout the chapter. INTRODUCTION HTML5 is a wonderful technology that, by the time it's fully implemented in all browsers in 2020, is going to pick up your dry cleaning, tidy up your apartment, walk your dog, and bring about world peace. Actually, it will do none of those things, but from some of the hype lauded onto the standard, you might think it would. There is one thing HTML5 is guaranteed to do: make the world a more interesting place. 4 68  ❘  CHAPTER 4  HTML5 for Mobile CAPTURING A BRIEF HISTORY OF HTML5 Technically, HTML5 is the next standard in a long line of standards being worked on and promoted by the World Wide Web consortium. The World Wide Web Consortium (online at www.w3.org), known as the W3C, is the primary standards body responsible for standardizing the web so that different content producers and browsers makers can build technology, including HTML5, that interoperates correctly. Understanding How HTML5 Grew Up “Different” HTML5 began life a little differently from its predecessors and didn’t start its life as the brainchild of the W3C. Rather, HTML5 was birthed in many ways as a rebellion to the standard the W3C was pushing at the time: XHTML 2.0. XHTML 2.0 had a lot of things going for it and, if it had really taken off, would have made the web a more consistent place instead of the Wild West of bad markup that exists today. But it suffered from a fatal flaw that made it practically a nonstarter: It wasn’t backward compatible. That meant that if you had a perfectly valid HTML 4 site, you would have to throw that site out and start from scratch to make it XHTML 2.0-compliant. In addition, jumping back to 2004, the speed at which the W3C was innovating the web was slow as molasses, with the last update to the HTML 4 stan- dard, HTML 4.01, having been released four years previously in 2000. In response to disappointment over the XHTML 2.0 standard, an offshoot known as the Web Hypertext Application Technology Working Group (WHATWG) formed in 2004. The WHATWG was made up of members from Apple, Mozilla, and Opera, and it immediately began to work on a new standard. Fast forward to 2007 and the standard the WHATWG had been working on over the previous three years and which had been gaining some significant momen- tum is proposed to the W3C as the starting point for a new standard called HTML5, to be devel- oped concurrently with XHTML 2. The W3C relented and started working on HTML5, pushing out the first working draft at the beginning of 2008. Furthermore, it abandoned XHTML 2.0 in 2009 when it let the charter of the working group that was developing the spec expire, an acceptance of the reality of the time that XHTML was a dead standard. Looking Toward HTML6? HTML7? Nope, Just HTML5 In January 2011, the editor of the HTML5 spec at the WHATWG, Ian Hickson, announced that the working group was going to treat the HTML5 spec as a “living document” that would continue to be updated and worked on indefinitely. The W3C was still going to release an official snapshot of HTML5, but the document itself will continue to be updated as new technical recommendations come in. What does that mean for developers? On the good side, there’s lots of cool stuff coming down the pipeline that will take it from idea to single browser implementation to being well supported and in the specification—in a fraction of the time that it used to take. As a developer you’re going to get lots of goodies, which makes it a fun time to be building stuff. On the down side, there’s a lot of stuff coming down the pipeline, such as direct access to video cameras and support for joypads, but browser fragmentation is again a big issue, as well as just keeping up with everything going on. Capturing a Brief History of HTML5  ❘  69 Going to the Spec One of the great things about the HTML5 spec is that it’s readable. Even though it’s a document aimed at browser implementers, it’s nonetheless an incredibly useful document for web developers and worth checking out whenever you need to figure something out authoritatively. A lot of times, the spec can answer your question more efficiently than the normal practice of Googling for the answer. If you haven’t been there already, take a quick visit to the permanent home of the HTML spec, “Living Standard,” which is permanently housed at www.whatwg.org/html. The next time you look something up, such as the parameters to a variation of drawImage, spend a bit of time getting comfortable with the format and organization of the spec, because it provides the easiest way to look up specific features of HTML5. Only when there’s a nonstandard implementa- tion or not yet a spec for a feature should you start elsewhere. Differentiating the HTML5 Family and HTML5 Since the term HTML5 entered the public’s consciousness, generally agreed to be around April 2010 when Steve Jobs wrote his infamous “Thoughts on Flash” letter (www.apple.com/hotnews/ thoughts-on-flash), “HTML5” has been used as an umbrella term for a number of different stan- dards. Some of those standards were part of HTML5 at some point and have since been broken out, whereas others have always been their own standard. Some of the standards that are often included when someone says “HTML5” are as follows: ➤➤ SVG ➤➤ CSS3 ➤➤ WebGL ➤➤ Web Workers ➤➤ Web Storage ➤➤ Web SQL Database ➤➤ Web Sockets ➤➤ Geolocation ➤➤ Microdata ➤➤ Device API ➤➤ File API The use of the umbrella term HTML5 to include all these is technically wrong, but it’s also rather convenient. HTML5 is the buzzword people know and understand. To most developers it just means building something natively in the browser without plug-ins, and I think that’s ok. This book is clear when referring to a specific part of the HTML5 specification or another speci- fication, but most of the time it refers to the family of technologies that HTML5 has come to encompass. 70  ❘  CHAPTER 4  HTML5 for Mobile USING HTML5 THE RIGHT WAY As explained in the last section, through a fortuitous confluence of circumstances, for the first time in the history of the web, web developers have an official W3C-approved specification (okay, it’s a “working draft” right now) that syncs up with the realities and desires of day-to-day development. For web developers that had been starved for so long by the stagnation of the web, the current renaissance of activity truly feels like being suddenly handed a large piece of cake after having had to dig around for scraps of bread. The number of goodies added to the web developer’s toolbox in the past few years is staggering. Even Microsoft, traditionally mired in a bog in proprietary technology, has jumped in and is making a serious push toward supporting standards-based web development without proprietary plug-ins. Having Your Cake and Eating It, Too HTML5 is truly a browser-driven spec in that the browser makers are the ones who are pushing the standard forward. This means that a lot of features that start out in one browser or multiple brows- ers with incompatible implementations are eventually unified as the browser makers come to an agreement on details and implementation. The most obvious example of this evolution from initial implementation to standard is with CSS3 vendor prefixes. (As noted earlier, technically CSS3 is not part of HTML5.) When new CSS3 fea- tures leap onto the scene, you generally must write a number of lines that may differ only slightly by vendor prefix. For example, in 2010, to add a drop shadow onto a container, you would have had to write the following: -moz-box-shadow:5px 5px 10px #000;; -webkit-box-shadow:5px 5px 10px #000;; -ms-box-shadow:5px 5px 10px #000;; -o-box-shadow:5px 5px 10px #000;; box-shadow:5px 5px 10px #000;; That includes four vendor-specific versions and then a forward-looking standards-based version. Fast forward to 2011, and it becomes possible to simply write this: box-shadow:5px 5px 10px #000; Although keeping track of the rate of change is daunting, as a developer you get the best of both worlds: shiny tools you can use immediately (albeit carefully, especially when standards aren’t yet finalized) combined with standardization coming over months instead of years. Sniffing Browsers In the bad old days of web development, you might see the following littered throughout the of an HTML document: WARNING  The following code is an example of what not to do, so please don't use either of these examples. Using HTML5 The Right Way  ❘  71 Alternatively, you might also at some point have written this: function isIE() { if(navigator.userAgent.match(/MSIE (\d+\.\d+);/i)) { isVersion = new Number(RegExp.$1); return true; } else { return false; } } if (isIE()) { if(ieVersion == 6) { /* IE6 only Code */ } else if(ieVersion == 7) { /* IE7 only Code */ } } The first of these snippets is known as conditional comments (an Internet Explorer-only [IE-only] feature), whereas the second is known as UA sniffing because it tries to decipher the browser being used from the string of information provided by the browser, called the userAgent. Although using these snippets to determine how your application should act might have been a workable solution in 2007, when accommodating three browser versions—IE6, IE7, and Firefox 2— would have accounted for nearly 95% of the market, the current round of browser wars have shaken things up dramatically, as shown in Figure 4-1, which uses data provided by statcounter.com. 2005 100% 2006 2007 2008 2009 2010 2011 80% 60% 40% 20% 0% Opera Safari Chrome Firefox IE FIGURE 4-1:  Desktop browser usage. As of this writing, IE on the desktop has slipped to just more than 50% of the browser share and is split between four different versions: IE6, IE7, IE8, and IE9, with IE10’s release just around the corner. Chrome is on the rise, now in the double digits; and Firefox, although declining a bit, is still more than 20%. Safari has been slowly and steadily on the rise and may hit double digits in 2012 if 72  ❘  CHAPTER 4  HTML5 for Mobile Apple continues to roll. With the exception of IE, most users of other browsers are most likely to use a current version or one of the previous two releases due to the way the browsers are now actively pushing auto-updates. IE has also rolled out auto-updates, but users of older operating systems are limited to the browser they can use (IE6 for Windows 2000, IE8 for Windows XP, and IE9 for Windows Vista). Auto-update notwithstanding, taking into consideration still-in-use previous versions of all the browsers, you’re looking at more than 15 combinations of desktop browsers and versions that need to be supported. To make things worse, this book isn’t talking primarily about desktop browsers, is it? On mobile devices the dominant browser players in the United States are iOS and Android, with Firefox, Windows Phone 7 (WP7), Opera, Symbian, and Blackberry also in the running. Add in a boatload of different devices and screen sizes, the rise of the tablets, and fragmentation across Android, and your head should start to spin. You could probably start writing conditional comments and doing browser sniffing right now and never stop because new devices are released all the time. Determining Capabilities, Not Browsers It’s not all doom and gloom, however. With the right approach, you can develop for both the now and the future. The most important aspect of this approach is the idea of testing the capabilities of browsers rather than trying to identify the browser itself. An initial naive way to check for support (which was common in pre-HTML5 days) would be to scour the Internet to figure out which browsers support, for example, the Canvas tag and then match versions. You might try something like the following code: WARNING  The following code is again an example of what not to do. var canvasSupported = (isIE() && ieVersion >= 9) || (isFirefox() && ffVersion >= 1.5) || (isOpera() && oVersion >= 9) || ... And so on .. As you probably figured out, this is a bad idea. It suffers from needing to keep up-to-date on all the different types of browsers that people use and knowing what’s supported in which. It’s a recipe for disaster. Life would be good if you could just write function isCanvasSupported() { // Directly check if the browser knows about the canvas element } Actually you can do just that, and you can do that for just about every feature you care about in HTML5. The most common method is to try to create an element and check if it supports a certain method. Or if the functionality is not per DOM-element, you can just check if the browser has a necessary method. Following is an example of each: function isCanvasSupported(){ // First create a element Using HTML5 The Right Way  ❘  73 var elem = document.createElement('canvas'); // Next make sure it supports getContext and can return a 2D context return !!(elem.getContext && elem.getContext('2d')); } function isGeolocationSupported() { // Check if the geolocation object is defined return navigator.geolocation; } Now, before you go off and check the spec and write functions for each of the features you want to support, the good people behind Modernizr (ww.modernizr.com) have done all the hard work for you, all for the cost of loading one script that is less than 7 kb when served compressed. If you want to pull the file size down further, you can add only the checks you need to your custom download. Modernizr enables you to reduce feature detection checks to the following: if(Modernizr.canvas) { // Do something with canvas } Modernizr provides more than 40 checks for support for next-generation features and is adding checks often, so it should be your go-to resource. Enhancing Progressively Now that you have the ability to know exactly what features are supported in the browser your code runs in, how do you best use that information? The answer is, “It depends.” In some situations, the lack of support for a specific feature is a nonstarter. If your game depends on canvas, for example, lack of canvas support means the game isn’t going to run. In other situations, lack of a feature might reduce the user’s experience, but it shouldn’t prevent the user from accessing your game. PROGRESSIVE ENHANCEMENT IN THE REAL WORLD My company built a game for GamesForLanguage.com called SpaceWords, which lets multiple players use their smartphones as controls for the game. If the browser supports orientation events, the game uses those events as the movement input, allowing players to control their ship by rotating their phone. If the smartphone doesn’t support those events, the game uses touch events. Finally, if the phone doesn’t support touch events, the game uses normal MouseDown events. In each case, access to more functionality means you could bring a better experience to the player without leaving those on less-capable devices out of the game entirely. Progressive enhancement is the buzzword for starting out with a base level of functionality and including additional features for only those that support it. 74  ❘  CHAPTER 4  HTML5 for Mobile In the best of situations, you can use the same code for both the minimal support and the enhanced features, and only include additional code for the enhanced experience. As most developers do their development and testing on the most capable devices, this means you have a better chance of having working code on the less-capable devices than if you use completely different codebases for the two. Polyfilling in the Gaps The last section discussed how the lack of support for a specific feature can be a nonstarter for some situations. This isn’t exactly true because sometimes you can find a polyfill to fill in the gaps. A polyfill is a chunk of code that backports features to browsers that don’t support the feature natively. For mobile, this may not be an issue because the mobile stack is generally good as long as you are on a recent smartphone. The support diminishes, however, the minute you step out of the iOS, Android, and WP7 space into Blackberrys and feature phones. In those situations polyfills, such as those for local storage and CSS3 features, become very useful. The advantage of detecting features instead of browsers comes to the forefront again because a true polyfill exposes the same interface as the native feature. This means that you can often add a polyfill script to the head of your document and add enhanced functionality to older browsers for free. CSS3 Pie (http://css3pie.com/), for example, provides a polyfill that adds CSS3 decorations like rounded corners, gradients, and drop shadows to older versions of IE. Not surprisingly, given its focus, Modernizr provides a great list of the polyfills on its wiki: https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills. CONSIDERING HTML5 FROM A GAME PERSPECTIVE In this chapter you’ve heard a lot about HTML5 but not much about how HTML5 can help you build games on mobile devices. This section discusses the main ways to build games with HTML5, and the next section covers mobile-friendly features that can make your games more interesting. Now look briefly at the three main ways you can build games from an HTML5 perspective. (Each of these is covered in much more detail in later chapters, and Chapter 12, “Building Games with CSS3” explains which method to pick for your specific game.) Canvas Canvas, which is discussed in detail in Chapter 15, “Learning Canvas,” and used throughout the book, is in many ways the most interesting feature game-wise of the actual HTML5 standard. It gives developers access to a fast frame buffer where you can draw images and graphics. Most discussions of Canvas in this book mean 2-D canvas because that is the only canvas context that’s currently well supported on mobile devices. But there will be a discussion about the Webgl context briefly as well as support for 3-D canvas, which is poised to appear on mobile devices (or may already be there by the time this book gets in your hands). Figure 4-2 shows the canvas plat- former built in Chapter 18, “Creating a 2D Platformer.” Considering HTML5 from a Game Perspective  ❘  75 FIGURE 4-2:  A mobile 2D platformer. CSS3/DOM As you see in Chapter 12, “Building Games with CSS3,” CSS3 adds a lot of power to traditional HTML DOM elements and can definitely be considered a viable technology to build a game on. For games with touch interfaces (that is, mobile), it may be quicker to use CSS3 and the DOM because the browser handles a lot of the hit detection and interaction for you. In addition, support for hardware- accelerated transforms and animation on mobile WebKit gives a performance boost over canvas in many situations. Figure 4-3 Shows the CSS3 RPG built in Chapter 13, “Crafting a CSS3 RPG.” FIGURE 4-3:  A CSS3 RPG. 76  ❘  CHAPTER 4  HTML5 for Mobile SVG The black sheep of the family, SVG has actually been hanging out doing its thing since 2004. However, with the release of IE9 in April 2011, as the first release of IE to support it natively, people are coming around slowly to its benefits and potential uses. Scalable Vector Graphics (SVG) provides a way to draw resolution-independent graphics. Much like Flash, SVG stores the instructions to draw elements rather than the resultant pixels that make up those elements. This means that, provided it’s used correctly, SVG creates small file sizes good for mobile devices. It also generates its own scene graph—much like the standard DOM—and is well supported on WebKit mobile and useful in touch games. In many ways SVG combines the best of both worlds between Canvas and CSS3. The major problem is that performance is lacking, so if you are building an action game, SVG is probably not an option. Figure 4-4 shows the SVG game built in Chapter 14, “Building Games with SVG and Physics.” FIGURE 4-4:  An SVG cannon game. CONSIDERING HTML5 FROM A MOBILE PERSPECTIVE One of the phrases that you hear a lot these days is “mobile first.” This phrase means considering mobile devices as your primary target and considering support for additional browsers later on. This might not seem obvious with mobile browsers, as of 2012, barely in the double digits of overall usage, but it’s more than just a numbers game. Considering mobile devices first means you start with a number of significant constraints and work out from there. Mobile devices have small screens and screens of different sizes and aspect ratios. They have limited processing power and bandwidth and often have limited storage. All these constraints force you, as a developer, to optimize your web app—make it more adaptable; make it load faster and be more performant. Not surprisingly, these are all things that can bring a better experience to users with desktop browsers as well. Web developers have been a bit lazy, viewing their projects on 30-inch monitors connected to fat Internet pipes and running on four-core multithreaded processors. Most likely a good portion of your target demographic for casual web games doesn’t share the same hard- ware specifications. Considering the mobile usage of your site as a primary consideration can help you move away from that attitude. Surveying the Mobile Browser Landscape  ❘  77 Understanding the New APIs The family of specifications tied together as “HTML5” is a large family, and some pieces you couldn’t care less about from a game perspective. Are advances in semantic, tags such as the