Far Out Fowl: An exercise in webOS game development

Palm’s webOS has in many ways revolutionized the way use developers write applications, utilizing the web technology techniques we use nearly everywhere else to write applications that run on the local device.  It’s a great way to quickly write applications for all sorts of needs such as contact management, calendaring, eMail, messaging and note taking.  But, what about games you ask?  Can these same techniques be used to create action-packed games for the on-the-go player too?  You bet, and in this article I’ll show you how!

 

Introduction

I’ve always felt that the best programmers are game programmers.  I don’t just simply mean that game programmers are the best programmers though.  What I really mean is that programmers who program games tend to be better overall programmers than those who don’t.

 

Why is that?  I think for a couple of reasons.  First, programming games forces you to touch on so many different disciples and thought processes.  From physics to AI, audio/visual coding and data structures, all of it and more are things you’ll have to dive into when developing a game. 

 

Second, you have to be a very creative person to develop games!  Obviously to create things like storylines and level maps and such, but also in terms of coding you often-times have to think outside the box to solve sticky problems that come up.

 

Third, I think that game programmers tend to have fun with what they’re doing and can transfer that sense of fun to non-game programming.  Oh, I’m sure at the big game houses it’s more of a grind than two guys in a garage working on a game, but I’m sure they still have their share of fun.

 

Game programming is challenging and rewarding, and now with Palm’s webOS platform to target this is even truer today!  The challenge aspect of it comes from figuring out what the platform can do, where the boundaries are and how to push past them.  In this regard, developing games for webOS is very much like the old-school days when we wrote games on 8-bit machines.

 

The rewarding part comes not only from that sense of accomplishment you have for completing a game and actually playing it and showing it off, but if you’re lucky, actual financial reward from selling your product!  The webOS platform represents a whole new opportunity, and a rapidly growing one most importantly, for us code monkeys to get rich off our hard work (that, as I mentioned earlier, tends to be pretty fun too!)

 

So, how do you get started developing games for webOS?  As it happens, owing to the web technology focus of the platform, it’s not much different from developing a game for the web.

 

Who is this article for?

This article provides a starting point to show you exactly how to get going.  It’s not really a step-by-step tutorial, although there’s certainly some of that.  It assumes you’ve already delved into webOS and can get a basically application up and running on your own.  It assumes you have a decent grasp of HTML, CSS and JavaScript, all of which are prerequisites for webOS development in general.

 

This article walks you through a complete, full, working webOS game.  Step by step, hand-in-hand I’ll walk you through its structure, the how’s and why’s of things, and in the process I’ll talk about some of the general concerns you’ll have to take into account.  To be sure, this article is for those that like to “learn by example”, that like to look at real code, tear it apart and maybe even put it back together yourself a little differently. 

 

If that’s you, then read on, I think you’re going to enjoy the ride!

 

The game, in a nutshell

The first thing we’re going to do is talk a bit about what the game is, how you play it and all that jazz.  Conceptually it’s very simple and if you happen to have had an Atari 2600 at some point in your past you probably remember the game Kaboom!  Well, Far Out Fowl, the title of this game, borrows rather heavily from Kaboom! (That is, if by “borrow” you mean basically rips it off unapologetically!)

 

I’m a sci-fi nut, so the theme of alien invasion is something I’ve very much familiar with.  This game asks the age-old question: what would happen if a giant space chicken who hurled poisonous eggs at the Earth invaded?  How would we defend ourselves?  If your answer is that some egg farmer named Joe would defend us by perpetually catching all the eggs in an egg basket while at the same time firing missiles at the chicken, then you’ve got the idea of this game already!

 

 

Here’s a look at the game as it might appear in the midst of the action.  As you can see, the chicken is up top and moves left and right.  Your egg basket is at the bottom and the eggs are falling.  The hands at the bottom simulate you playing this at an arcade machine, or perhaps at the controls of the basket (let’s assume it’s controlled remotely… that’s one advanced egg basket!).  As you play the game for real you’ll notice that the hands actually work: as you move the basket left and right so too does the left hand move the joystick left and right.  Likewise, when you shoot a missile at the chicken, the right hand appears to press the button.  It’s just a neat little graphical touch to make things a little more interesting.  The same is true of the lights around the border of the screen, which flash randomly.  Note too that apparently the chicken can be blocked by a simple brick wall which serves as a backdrop for the action.  Hey, it’s a game after all so it doesn’t really have to make sense!  It’s just got to be fun and interesting, and being a bit bizarre can help accomplish both goals.

 

There are only a few simple rules as you play the game.  First, for each egg that is not caught it will splatter, releasing toxins into the atmosphere.  These toxins also do damage to your basket.  If too much damage is done, the game ends.  As I mentioned, you can fire missiles at the chicken as well.  When they hit the chicken pauses temporarily, and some of the damage to your basket is repaired.  The eggs drop faster and faster the more you catch.

 

For the sake of simplicity, there really isn’t any ultimate goal to this game.  In fact, you are doomed to failure ultimately no matter what you do because the only way the game can end is for you to miss too many eggs.  It may take a few hours if you’re really good and determined, and have an exceptionally strong bladder!  In the end though, you’re doomed.  The only real goal is to achieve the high score, which is recorded via a cookie and displayed at the start of the game.

 

The game can be controlled in three different ways: keyboard, touch screen or accelerometer.  The Q and P keys serve as left and right, and spacebar fires a missile.  The player can also tap the left and right sides of the screen to move the basket.  Finally, tilting your device left or right also moves the basket.  Firing a missile can also be done by flicking the device forward.  All of these control methods are available simultaneously, so it’s completely up to the player which they prefer to use and they could even switch methods in mid-game if they want to.

 

As you can see, the game itself isn’t rocket science.  The rules are simple, the goals are straightforward, and the design.  However, what it does is provides a real nice example to learn from because it touches on all of the basics of creating a webOS game.  Now that we have an idea what the game concept is all about, let’s talk about some technical decisions we have to make before we can get into the actual code.

 

Decision point #1: DOM, canvas or the PDK?

The first choice any prospective webOS game development has to make is whether to develop a DOM-based, canvas-based or PDK-based game.  All of these are perfectly valid choices and each has it strengths and weaknesses.  Some people get pretty adamant about one approach over another, but I try to take a more practical approach and base my decision on factors such as what the game required technically, time to market and what I’m most comfortable working with.

 

The larger question is whether to go with the PDK, or Plugin Development Kit, or the more typical webOS approach using web technologies.  The PDK is a C-based approach that allows you to write your code at a more low level, closer to the metal so to speak.  The PDK was created with advanced games in mind, those that require complex 3D graphics and such.  Some of the top webOS games available today, like Need for Speed, Let’s Golf and Brain Challenge make use of the PDK.

 

For this particular game, the PDK would probably be overkill.  There’s no 3D graphics, no performance limitations that web technologies would present and no advanced audio requirements.  We can do this game without it, and that’s true of many games.

 

So, having decided on the more standard webOS model, that is, using web technologies, the next question to ask is whether to use canvas or plain old DOM, including things like CSS transitions.  This decision probably comes down more to personal preference than anything else.  While it is true that you can often times get somewhat better performance with CSS animations and effects, the trade-off is that you don’t get the more low-level, pixel-oriented nature of canvas.

 

Writing a canvas-based game is more like what most people know who have written games before: you literally get a blank canvas and the ability to draw on it down to the pixel level if you wish.  This is the approach I usually prefer, and it’s the approach that will be employed in this game.  Once again, examining your needs and comparing the options is the smart thing to do, don’t just pick canvas because that’s what this article and this game uses.

 

Decision point #2: Game engine or manual coding?

Once you decide which approach to take, the next question that comes to mind is whether you should track down an existing game engine, write one yourself from scratch or don’t bother with an engine at all?

 

Even before you try to answer that question though it helps to know what a “game engine” is!

 

A game engine can actually mean a number of things, but there are a few common components that nearly all will provide, beginning with a sprite engine.  A sprite is a graphical element (things like our chicken, the basket, eggs and explosion when a missile hits the chicken) that is manipulated in the game and is in essence a character in the game.  The term character is a little broader here because it could mean things like missiles, explosions or even background objects that don’t impact gameplay.

 

A sprite engine will provide some sort of object called a sprite that you use in your code, and this object will provide some basic functionality such as animation (flipping between multiple frames of animation), movement, collision detection and so on.  Every sprite engine will be different of course and provide other features, but things like this tend to be the basics that they all provide.

 

In simplest terms, a sprite engine might in fact be all you need!  Sprites certainly are the basis of nearly every game, and sometimes that’s really all you need.  This game is a good example of that.

 

A game engine will also usually provide a basic skeleton for you to extend.  For example, it will have a basic main loop function, functions for various player input methods, initialization and cleanup function and so on.  It is your job as a game developer to implement these functions as necessary, but the engine provides the basic skeletal structure and also deals with calling these functions at the appropriate time.  For example, the engine will typically ensure that your initialization function is called once at startup and then that your main processing loop is called multiple times per second in accordance with some sort of “heartbeat” timer that corresponds, in simple games at least, to the desired frame rate of the game.

 

A game engine might also provide a finite state machine for dealing with core game logic and transition between screens and parts of the game.  Input processing is also typically provided for, as is audio capabilities like playing sound effects and background music.  There might be some artificial intelligence capabilities built into the engine as well.

 

What are the benefits to using a game engine?  The most obvious one is that it saves you from having to reinvent the wheel.  The basic structure of a typical game is pretty well-understood and tends to be largely boilerplate.  Not having to think about any of that saves you time and effort.  Having a sprite engine means you don’t have to think about how to animate your sprites or how to move them or deal with collisions, that sort of stuff is already all done for you.

 

More advanced game engines can do more than save you time, they can actually allow you to create games you might not otherwise have been able to.  Not everyone can write a particle effects system, and not everyone understand the geometry and math for doing 3D games, and some engines provide all of that.

 

That all sounds great of course, but is there a down-side?  Yes, there is, a few actually.  First, you’ll have to take the time to learn the engine and conform your thinking to it.  Good engines will of course have some flexibility, but there’s always a certain degree of inflexibility you have to deal with.  Second, the engine can sometimes get in your way in terms of performance.  A game engine is usually tuned to a relatively low common denominator, settings that will work decent in most cases.  If you find your frame rate isn’t quite what you need, getting in and tweaking the engine to do what you want may be more trouble than it’s worth.

 

Once again, the decision you have to make should be based on your needs and not any preconceived notion about what is best.  Far Out Fowl, being a relatively simple game so it doesn’t really require what a proper game engine provides.  In fact, it doesn’t really need a simple sprite engine (although that is, I’ll admit, debatable).  It’s really easy enough to write it all ourselves, which gives us maximum control over every aspect of the game.  Besides, as a learning example I think it’s better for you to see what the “manual labor” approach looks like and that way if you decide to use a game engine later you’ll have a grasp on what it’s likely to be doing under the covers for you.  That understanding is something I find to be very valuable even if you don’t have to sweat the details any more when using that fancy new pre-existing engine!

 

Far Out Fowl: The dissection begins!

Now it’s time to start exploring the code of Far Out Fowl.  Let’s begin by looking at the application’s overall directory structure.  As you can see, it’s a perfectly typical webOS application:

 

 

I didn’t expand the images directory because it would have made the image a bit unwieldy.  In any, the content of that directory is just a collection of PNG files anyway, so you probably wouldn’t gain much by seeing that here.

 

We will of course be exploring each of the source files, but a brief overview is certainly in order.  This game consists of just a single scene, main.  There are also two dialogs, instructions and gameOver.  Each has an assistant naturally, as well as a view definition HTML file.  The core code of the game itself, in fact where we’ll be spending 90% of our time, is in the aptly-named game.js file. 

 

The basic configuration files

The usual lineup of suspects in the root directory and they primarily deal with configuring the application and telling Mojo and webOS what they need to know about it.  Let’s take a quick look at those, even though they are very much typical.  We’ll skip the icon.png file, the icon for the application, and jump to the JSON files.  The required appinfo.json file is there, and it contains the following:

 

{

    "id": "com.etherient.faroutfowl",

    "version": "1.0.0",

    "vendor": "Etherient",

    "type": "web",

    "main": "index.html",

    "title": "FarOutFowl",

    "icon": "icon.png"

}

 

There shouldn’t be any surprises there; it’s a perfect ordinary appinfo.json file.  We also have a sources.json file:

 

[

    {"source": "app/game.js"},

    {"source": "app/assistants/stage-assistant.js"},

    {"source": "app/assistants/instructions-assistant.js"},

    {"source": "app/assistants/gameOver-assistant.js"},

    {

        "scenes": "main",

        "source": "app/assistants/main-assistant.js"

    }

]

 

Again, it’s perfectly ordinary and simply imports the source files for the main scene, the two dialogs, the stage and the main game code.

 

There’s also an optional framework_config.json file:

 

{

  "logLevel" : 0

}

 

This allows us to see some logging messages if we need to (in this application that amounts to frame timing information).  As set here, no log messages will be outputted, which is what you’d want in your final code.

 

The stylesheet

Beyond the basics in the root directory, in the stylesheet directory is a single stylesheet for the application, and because this is a canvas-based game there really isn’t much in it.  To be precise, there are exactly two style definitions in it!  The first one is this:

 

body.palm-default {

  background-color : #000000;

}

 

That simply overrides the default styling of a scene’s body to ensure we have a black background.  The other style we’ll see as we look at the main scene’s view markup. 

 

The index.html file

Since a webOS application kicks off by loading an HTML file, usually index.html in the root of the application as is the case here, let’s take a look at that now:

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"

  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>

  <title>FarOutFowl</title>

  <script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1" />

  <link href="stylesheets/faroutfowl.css" media="screen" rel="stylesheet" type="text/css" />

</head>

<body></body>

</html>

 

There certainly isn’t anything special going on there; in fact it’s a little boring!  We need Mojo of course, and we need the main stylesheet, so both are imported and that’s all we need to do.

 

Setting the stage: The stage assistant

The application’s real executable code kicks off with the stage, which naturally has its own assistant in the stage-assistant.js file:

 

function StageAssistant() { }

 

 

StageAssistant.prototype.setup = function() {

 

  this.controller.pushScene("main");

 

};

 

The only task this code has to accomplish is to push the main scene, which is exactly what it does.

 

The main scene

So far, we’ve seen the foundation being built, and it’s all pretty ordinary webOS code.  As you can see, writing a game in webOS is, at its most fundamental level, no different from writing any other type of webOS application.  There’s one more piece of somewhat basic setup to be done, and that’s encapsulated in the assistant for the main scene, namely in the main-assistant.js file.  Before we get to that though let’s have a look at main-scene.html, the view markup for the scene:

 

<canvas id="mainCanvas400" width="320" height="400"

  class="cssMainCanvas"></canvas>

 

<canvas id="mainCanvas480" width="320" height="480"

  class="cssMainCanvas"></canvas>

 

Yes, that’s actually it!  Two <canvas> elements are all we need.  Note that because of a rendering bug in WebKit, the engine that underpins webOS, you have to specify the width and height of the <canvas> element with the width and height attributes.  Just using the equivalent CSS attributes will result in some odd problems where you can only render content on half of the canvas.  I learned that by trial and error and it took a good bit of screaming and yelling before I found out about it!  Each <canvas> tag also has the cssMainCanvas style class applied to it, and that’s the other style definition I mentioned earlier.  Here it is now:

 

.cssMainCanvas {

  display : none;

  position : absolute;

  left : 0px;

  top : 0px;

}

 

As you can see, this will result in both <canvas> elements being hidden from view and also positioned anchored to the upper left-hand corner of the screen.  So, they would occupy the same place on the page.  If you look at the width and height attributes you’ll notice that they have different heights.  We’ll see why this is shortly.

 

Let’s now get into the code for the assistant itself:

 

function MainAssistant() { }

 

 

MainAssistant.prototype.setup = function() {

 

  this.controller.enableFullScreenMode(true);

 

  game.mainAssistant = this;

 

};

 

 

MainAssistant.prototype.activate = function() {

 

  game.init();

 

  if (game.screenHeight == 400) {

    $("mainCanvas400").style.display = "block";

    game.ctx = $("mainCanvas400").getContext("2d");

  } else if (game.screenHeight == 480) {

    $("mainCanvas480").style.display = "block";

    game.ctx = $("mainCanvas480").getContext("2d");

  }

 

  Mojo.Event.listen(this.controller.document, Mojo.Event.keydown,

    game.keyDownBind, true);

  Mojo.Event.listen(this.controller.document, Mojo.Event.keyup,

    game.keyUpBind, true);

  Mojo.Event.listen(this.controller.document, Mojo.Event.tap,

    game.tapHandlerBind, true);

 

  this.controller.listen(this.controller.document, "orientationchange",

    game.orientationChangeBind, true

  );

 

  this.controller.listen(this.controller.document, Mojo.Event.stageActivate,

    game.stageActivateBind, true

  );

  this.controller.listen(this.controller.document, Mojo.Event.stageDeactivate,

    game.stageDeactivateBind, true

  );

 

  game.dialog = game.mainAssistant.controller.showDialog({

    template : "instructions-dialog",

    assistant : new InstructionsAssistant(),

    preventCancel : true

  });

 

};

 

The first important thing that happens is in the setup() method: the application is put into full-screen mode.  For many games this is necessary: you want to have as much screen real-estate available to you as possible.  Getting rid of the status bar and notification bar buys you 56 pixels and, more importantly, makes your game more immersive for the player.  Not getting distracted by things happening on those two UI components means they are focused more on the actual gameplay, which is exactly what you (and they, even if they don’t realize it) want.

 

Also in setup(), a reference to this assistant is cached and a reference to it stored in the game object which, as we’ll see, is the object created in the game.js file.  This is done because showing the gameOver dialog requires an assistant, and while it’s not too difficult to get a reference to the current scene’s assistant, since we know that the main scene will be the current scene all the time we might as well save that effort by storing the reference now and not having to worry about retrieving it later dynamically.

 

This reference storing seems trivial on the surface, but it’s actually a key point when writing games for webOS: caching references wherever possible so you don’t have to look them up later is extremely important.  In this particular case it frankly wouldn’t matter much, but imagine if this reference is something we needed to retrieve multiple times a second as part of the main game code.  If this lookup was expensive then you’d probably quickly impact your frame rate in a negative way.  Any time you can cache a reference to an object you will need frequently it is a good idea to do so.  That’s a point you’ll see more of as we examine the main game code.

 

There’s still code here to explore though, the activate() method to be precise.  The first line of code calls the init() method of an object game.  As mentioned before, this object is created by virtue of the game.js file being imported (remember that global-scope code in any .js file you import is executed at the time it’s imported).  We’ll be getting into that code shortly; for now it’s enough to know that initializes the main game code.

 

After that comes a block of code, an if…else statement, that is part of how the game handles multiple screen resolutions.  As you know, webOS is screen resolution-independent, and right now that really just means the Pre has a resolution of 320x480 while the Pixi has a resolution of 480x400.  I personally wish Palm had picked a screen size and stuck with it because it makes life more difficult on us game devs!  But, at least for this game, it’s pretty easy to deal with and this block of code begins that handling.  Two things happen here.  First, one of the two <canvas> elements is shown, the one appropriate for the height of the screen (which is determined as part of the game.init() call we can guess).  Second, a reference to the 2D context of the canvas is retrieved and cached on the game object.  Once again, caching this reference allows us to not have to retrieve it during main game code processing (get this reference every time is a common mistake seen in <canvas> example code on the web).

 

Following that are a couple of Mojo.Event.listen() calls to hook up handlers for various events.  Since the game will allow control using keyboard, screen and accelerometer, we need to handle all of those.  All of them are set up on the document object, which makes sense given that this is a full-screen game, and uses some function binds that are set up as part of the call to game.init().

 

In addition to player control we also want to deal with activation and deactivation of the stage.  This will allow us to be good webOS citizens: when the stage is deactivated, which happens when the user “minimizes” the application’s card (i.e., when they go to card view) we want to pause the game.  This is important because if you leave code running in the background then it will be chewing up system resources and eating away at battery life, and that’s not cool!  Of course, when the stage is activated we’ll want to start the action up again, so we need to listen for both of those events too and hook up event handlers for them.

 

You should notice at this point that all of the handlers are part of the game object.  This represents a fairly typical structure for a webOS game.  Would it be possible to have all the game code included as part of the main assistant?  Absolutely it would, and in some ways it’s even easier that way.  However, in terms of good code structure I believe it’s better to separate out the main game code from the scene that initiates it.  One of the things this allows you to do is to take the main game code and work on it on your desktop.  There are some bits in the main game code that are webOS-specific, but they aren’t too extensive.  Therefore, you could actually work on the game in, say, Firefox, with Firebug, on your desktop.  You might have to create some fake stub versions of a few Mojo functions, but it’s a pretty light lift to do that.

 

In any case, the last thing done in activate() is to show the instructions dialog, so this is the first thing the user sees when the game starts up.  This dialog is where we’re headed next in our exploration of Far Out Fowl.

 

The instructions dialog

The instructions dialog looks something like this:

 

 

There are multiple pages of instructions, four in total, and the user navigates between them with the Prev and Next buttons.  Here’s the second page:

 

 

As you can see, the Prev and Next buttons enable and disable as necessary.  The final page has the Next button disabled:

 

 

This dialog also shows the current high score, if any, at the top.  The high score is stored in a cookie because that’s about the simplest data storage mechanism available to a webOS application and is quite sufficient for a simple high score.

 

Notice this is all done in the same dialog; there are not four different dialogs for each page of instructions.  Therefore, the markup must include all the instructions, and it does, as you can see here for yourself:

 

<div class="palm-dialog-title" style="text-align:center;">

  High Score: <span id="instructions_divHighScore"></span>

</div>

<div class="palm-dialog-separator"></div>

<br>

 

<div id="instructions_divPage1">

  <b>Why did the giant space chicken cross the GALAXY?  Wo cares, welcome to

  Far Out Fowl!</b>

  <br><br>

  The cosmic destroyer, a fowl beast (get it?!?) has launched an all-out attack

  on the Earth.  It's up to you, chicken farmer Joe, to defeat this menace from

  beyond the stars!

</div>

 

<div id="instructions_divPage2" style="display:none;">

  Catch the poison eggs the chicken

  drops before they splatter and release their toxins upon the world.

  <br><br>

  Control your basket by pressing the Q and P keys to move

  left and right, or tap the left and right sides of the screen, or

  tilt your device left and right.

</div>

 

<div id="instructions_divPage3" style="display:none;">

  You also have available to you a missile system with which to attack the

  chicken.  Hitting the chicken causes it to pause temporarily.

  <br><br>

  Fire your missile by pressing space bar or flicking your device forward.

  Note that you can only have a single missile in flight at a time.

</div>

 

<div id="instructions_divPage4" style="display:none;">

  You get points for catching eggs and hitting the chicken.

  Splattered eggs cost points and damage your basket.  Too much damage

  ends the game.  Missile strikes on the chicken repairs your basket

  a bit.

  <br><br>

  Click Start whenever you're ready Joe and get to saving the world!

</div>

 

<br>

<div class="palm-dialog-separator"></div>

<table border="0" width="100%"><tr>

  <td width="33%" align="center">

    <div id="instructions_btnPrevious" x-mojo-element="Button"></div>

  </td>

  <td width="33%" align="center">

    <div id="instructions_btnNext" x-mojo-element="Button"></div>

  </td>

  <td width="34%" align="center">

    <div id="instructions_btnStart" x-mojo-element="Button"></div>

  </td>

</tr></table>

 

The four <div>’s containing the text of the instructions will be displayed and hidden based on what page the player is looking at.  The buttons at the bottom are standard Mojo button definitions laid out using a table to get them all across the screen in a line.

 

Moving on to the assistant for this dialog I’m going to break it up a bit so we can discuss it little by little, beginning with some basic object definitions:

 

function InstructionsAssistant() { };

 

 

InstructionsAssistant.prototype.instructionsPage = null;

 

 

InstructionsAssistant.prototype.btnPrevModel = {

  label : "<< Prev", buttonClass : "palm-button affirmative", disabled : true

};

InstructionsAssistant.prototype.btnNextModel = {

  label : "Next >>", buttonClass : "palm-button affirmative", disabled : false

};

 

The instructionsPage field of the InstructionsAssistant object holds which page number is currently being viewed so that the Prev and Next buttons can be enabled or disabled as appropriate.  Those two buttons also have models defined explicitly so we can enable and disable them later easily.

 

After that comes the setup() method:

 

InstructionsAssistant.prototype.setup = function() {

 

  this.instructionsPage = 1;

 

  game.mainAssistant.controller.setupWidget("instructions_btnPrevious", { },

    this.btnPrevModel

  );

  Mojo.Event.listen(game.mainAssistant.controller.get(

    "instructions_btnPrevious"),

    Mojo.Event.tap, function() {

      if (this.instructionsPage > 1) {

        this.instructionsPage = this.instructionsPage - 1;

      }

      this.doCommonButtonWork();

    }.bind(this)

  );

 

  game.mainAssistant.controller.setupWidget("instructions_btnNext", { },

    this.btnNextModel

  );

  Mojo.Event.listen(game.mainAssistant.controller.get(

    "instructions_btnNext"),

    Mojo.Event.tap, function() {

      if (this.instructionsPage < 4) {

        this.instructionsPage = this.instructionsPage + 1;

      }

      this.doCommonButtonWork();

    }.bind(this)

  );

 

  game.mainAssistant.controller.setupWidget("instructions_btnStart", { },

    { label : "Start", buttonClass : "palm-button negative" }

  );

  Mojo.Event.listen(game.mainAssistant.controller.get(

    "instructions_btnStart"),

    Mojo.Event.tap, function() {

      game.dialog.mojo.close();

      game.startNewGame();

    }.bind(this)

  );

 

};

 

We start off on the first page of instructions, and then set up all the event handlers for the buttons.  You’ll notice that I’ve done something here that you generally shouldn’t do: I’ve put the event handler functions inline.  This is generally a Very Bad Thing™ to do because every call to bind() results in a new function being created, and it also means that every call to setupWidget() with an inline handler like this will result in a new copy of the same function being created.  However, in this case, this scene will only appear once, so setup() will only be called once and therefore this issue isn’t really a concern.  I prefer the code being inline like this from a readability standpoint.  I know that some people don’t agree, but not having to jump around the source code to see what happens when a button is tapped I find to be a nice thing.  That being said, I think it’s fair to say that this code represents a counter example, in other words, it demonstrates what you shouldn’t do, most of the time at least.

 

Note too that the Start button has its model inline.  This is because nothing in this model needs to be changed later, so there’s no real point in storing a reference to it.  I’m generally not a fan of the style of code where a field is dynamically added to the assistant that is a reference to the model defined inline (as you see frequently in Palm’s own example code).  I find that to be confusing and prone to error.  This is strictly a stylistic choice however, either approach works just fine.

 

The handlers themselves are pretty simplistic and I suspect self-explanatory.  The doCommonButtonWork() method at the end of the handler code the Prev and Next buttons we’ll look at shortly and I think it’ll become apparent why it’s broken out into a separate method (hint: it’s all about reducing redundant code!).  The Start button handler has the chore of closing the dialog by calling the mojo.close() method on the instance of the dialog, a reference to which is cached on the game object when the dialog is shown, as we saw earlier in the main scene’s assistant.  Finally, a call to startNewGame() on the game object kicks off the action.

 

Next in this assistant we encounter the activate() method:

 

InstructionsAssistant.prototype.activate = function() {

 

  var highScoreCookie = new Mojo.Model.Cookie("Etherient_FarOutFowl_HighScore");

  var highScore = highScoreCookie.get();

  if (highScore) {

    $("instructions_divHighScore").innerHTML = highScore;

  } else {

    $("instructions_divHighScore").innerHTML = "None yet";

  }

 

};

 

The job here is simple: read in the cookie that contains the current high score and display it.  If this is the first time the game is being played then there of course is no high score, so suitable text is inserted into the <div> at the top of the dialog where the high score is displayed.

 

Finally we come to that doCommonButtonWork() method I mentioned earlier:

 

InstructionsAssistant.prototype.doCommonButtonWork = function() {

 

  this.btnPrevModel.disabled = false;

  this.btnNextModel.disabled = false;

 

  if (this.instructionsPage == 1) {

    this.btnPrevModel.disabled = true;

  }

 

  if (this.instructionsPage == 4) {

    this.btnNextModel.disabled = true;

  }

 

  game.mainAssistant.controller.modelChanged(this.btnPrevModel);

  game.mainAssistant.controller.modelChanged(this.btnNextModel);

 

  $("instructions_divPage1").style.display = "none";

  $("instructions_divPage2").style.display = "none";

  $("instructions_divPage3").style.display = "none";

  $("instructions_divPage4").style.display = "none";

  $("instructions_divPage" + this.instructionsPage).style.display = "";

 

};

 

The idea is simple: enable and disable the Prev and Next buttons appropriately for the page of instructions we’re on, and of course show the appropriate page by hiding all but the current pages’ <div>.  Both buttons are initially enabled, then either Prev or Next is disabled if page 1 or 4 is being viewed respectively.  For pages 2 and 3 neither button needs to be disabled as navigation in either direction is valid.  The scene controller is then told that the models for the two buttons have been updated, and then the appropriate pages’ <div> is shown by hiding them all and then displaying only the current one.

 

The heart of the matter: The main game code

Now it’s time to dive into the largest chunk of code, that which is found in the game.js, namely the game object itself.  We’ve seen this object called a couple of times already, its init() and startNewGame() methods specifically, and now it’s time to see what’s behind the curtain so to speak and see what really makes this application tick.

 

Before we get into those details though, let’s talk basic architecture, the underlying structure of a typical game (not just a webOS or even a plain old JavaScript game, but almost any kind of game you’ll ever see).

 

While there are some other less-used approaches, a game typically involves one primary component called, rather obviously, the main game loop.  As its name implies, this is a loop that executes many times per second.  In the simplest possible model it will execute once for every frame, and by frame I mean the frame you see talked about in the term fps, or frames per second (not to be confused with FPS, which means First-Person Shooter, which is a type of game).

 

The main game loop is, usually, responsible for most of the core logic of the game and also putting stuff on the screen.  If the loop executes 30 times a second, that corresponds to a frame rate of 30 frames per second, which is a reasonable level at which animation appears smooth.  The main game loop will also usually deal with things like updating the position of objects on the screen, calculating the next movement based on AI algorithms and playing sounds.

 

In most games, the main game loop is literally an endless loop, typically a function that calls itself at the end, or even simpler, just a while(true) inside the first function called.  This approach works fine on a desktop PC because you have multithreading available to you.  So, while this main game loop may put stuff on the screen and calculating movements and such, player input can be handled on another thread.  Frequently you’ll have other threads doing AI and physics and other things and then the main game loop becomes responsible for little more than drawing the current scene as it should appear with all the movements and such taken into account.

 

The main game loop may have pauses in it too.  Say the target frame rate is 30fps, but the main game loop only takes 2ms to execute.  Since 30fps means each frame takes approximately 33ms, the main game loop really can’t draw another scene for 31ms, otherwise the frame rate would be too far.  So, a 31ms “do nothing” statement will be executed in the loop to hold off the next iteration until it’s time.

 

Another approach is to take how long the previous frame took to process and use that to calculate how far objects should move.  If the last frame only took 2ms to execute, then objects will move slower since the assumption is that the next iteration will only take 2ms as well.  If a given iteration of the loop takes longer than the objects will be moved a little faster (meaning a little farther on the screen during a given frame) so compensate.  This is a time-based approach to the main game loop.  The benefit is that object will move a consistent distance over a period of time, but they may move at different speeds.  This is generally a good way to do things when you have to support multiple hardware platforms with varying degrees of processing power.  However, it leads to a somewhat less optimal experience for the user.

 

Here’s the dirty little secret to webOS game development, and in fact JavaScript game development in general: most of what I just discussed is irrelevant!  JavaScript, as I’m sure you know, it a single-threaded language.  That means that everything that happens occurs on a single thread… the code you want to execute, handling of user input events, redrawing what’s displayed on the page, all of it happens on a single thread.

 

Imagine what would happen if you had an endless loop in JavaScript.  The short answer is nothing good: you’ll lock up the browser in no time because no input or display processing will be able to occur.

 

Given that, it becomes obvious that you can’t use a game loop as described above in JavaScript.  There’s really not a whole lot of choice in the matter and the answer most people quickly come to is to use intervals or timeouts.

 

The way it works is that you set an interval for the desired frame rate, say 33ms for a 30fps experience.  The function that executes is the main game loop.  But at the end of the function you simply do nothing (alternatively, you can execute the function to start and have it set a timeout at the end).  As long as your main game loop function never takes more than 33ms to execute you’ll have a nice, smooth frame rate and a happy player!

 

You can use the timeout approach if you want to use a time-based loop approach.  Simply adjust the timeout value according to how long the main loop took to execute.  Keep in mind that both setInterval() and setTimeout() in JavaScript have a minimum value they’ll accept.  On webOS that value seems to be in the 10ms range, so most of the time I’d say the interval approach will yield a better outcome because if you need to set a timeout with a resolution of less than 10ms with the time-based approach, you won’t get the results you expect.  I’d prefer to optimize my main game loop code to always work in the allotted time instead.

 

Writing tight code: Pre-allocation and avoiding GC activity

If you’re guessing that most of the code we’re about to look at is what you’d call the main game loop, you’d be absolutely right.  Now, given all that I said in terms of timing and make sure the game loop executes in the allotted time, it should be clear that optimization is a major theme here, and indeed it is.  However, that optimization begins long before the main game loop first executes and it boils down to one key concept: pre-allocation.

 

Garbage Collection (GC) in JavaScript is fairly expensive.  It’s of course extremely nice to not have to worry about memory allocation and de-allocation as you do if you’ve ever worked in C, but it comes at a cost.  If you had done any game development prior to webOS version 1.3.1, or even had simply played games before that update was available, you almost certainly would have seen the result of GC activity in games: stutters and seriously messed up gameplay.  Much to Palm’s credit, webOS 1.3.5 went a long way to alleviating this situation to the point now where GC activity, while still noticeable, is profoundly less problematic.

 

That being said, smart coding is still a must because you still can get hammered by GC activity if you really do things poorly.  Fortunately, doing things smartly isn’t all that tough, it just takes some understanding.

 

It’s not so much allocating memory when new objects are created that’s the problem; it’s when those objects are no longer needed and their memory is released by the GC that you take a hit that often manifests in pauses in what’s happening on the screen.  This is the activity that we want to avoid any time we can.  Doing so requires two things: pre-allocating objects and ensuring they are always references by something.

 

Pre-allocating simply means that you create as many objects up-front as you can rather than creating them as you actually need them in the main game loop.  Yes, this means your application will have a larger memory footprint, so you do need to be careful that you aren’t allocating huge amounts of objects and memory.  For a typical game you’re really talking about graphics mostly, which all totaled probably isn’t too much (of course, if your game has multiple levels or other breakdowns then you can allocated only what’s needed for a given level; there’s no need to allocated every last object you’ll ever need for the entire game; again, we’re talking about smart coding here!)

 

The other part of the equation, the more important part as it happens, is to ensure that something that won’t itself be GC’d holds a reference to those pre-allocated objects.  For example, in this application, we have this game object in global scope.  Anything in global scope is never eligible to be GC’d, and therefore if this object holds a reference to other object (as members of the game object to be precise) then they too will never be GC’d.  We could of course just hold the references to everything we pre-allocate in global scoped variables to get the same effect, but that’s considered a code smell because it “pollutes” the global namespace.  Placing everything inside a single game object keeps things clean and tidy while achieving the desired goal of avoiding GC activity.

 

Starting the game object

So, let’s get to the code already!  Our game object is defined in the usual way:

 

var game = { … };

 

The … is of course where all the fun it!  The first thing that’s present is a whole batch of fields on the game object.  Here’s a rundown of those:

 

 

Six of those fields are themselves objects with a bunch of attributes themselves.  Let’s go over them now:

 

 

As you can image, these fields will make considerably more sense once you see them used in context.  However, I think it will help set the table to see them in a list format like this.

 

Initializing the game object

The init() method is the first method we encounter in the game object, and you’ll recall it’s what gets called from the main assistant’s activate() method.  In a nutshell, this method is responsible for all the one-time setup tasks, things like pre-loading images, pre-allocating and so forth.  The code for this method is as follows:

 

init : function() {

 

  var i = null;

 

  this.screenHeight = Mojo.Environment.DeviceInfo.screenHeight;

  this.backgroundHeight = this.screenHeight - 134;

  this.gameConsole.frameHeight = this.screenHeight - 80;

 

  this.mainLoopBind = this.mainLoop.bind(this);

 

  this.keyUpBind = this.keyUp.bind(this);

  this.keyDownBind = this.keyDown.bind(this);

  this.tapHandlerBind = this.tapHandler.bind(this);

 

  this.orientationChangeBind = this.orientationChange.bind(this);

  this.stageActivateBind = this.stageActivate.bind(this);

  this.stageDeactivateBind = this.stageDeactivate.bind(this);

 

  this.background = new Image();

  this.background.src = "images/background-" + this.screenHeight + ".png";

  this.gameConsole.frame = new Image();

  this.gameConsole.frame.src = "images/console-frame-" +

    this.screenHeight + ".png";

  this.gameConsole.left = new Image();

  this.gameConsole.left.src = "images/console-left.png";

  this.gameConsole.middle = new Image();

  this.gameConsole.middle.src = "images/console-middle.png";

  this.gameConsole.right = new Image();

  this.gameConsole.right.src = "images/console-right.png";

  this.gameConsole.leftHand.push(new Image());

  this.gameConsole.leftHand[0].src = "images/left-hand-neutral.png";

  this.gameConsole.leftHand.push(new Image());

  this.gameConsole.leftHand[1].src = "images/left-hand-left.png";

  this.gameConsole.leftHand.push(new Image());

  this.gameConsole.leftHand[2].src = "images/left-hand-right.png";

  this.gameConsole.rightHand.push(new Image());

  this.gameConsole.rightHand[0].src = "images/right-hand-up.png";

  this.gameConsole.rightHand.push(new Image());

  this.gameConsole.rightHand[1].src = "images/right-hand-down.png";

  for (i = 0; i < 5; i++) {

    this.gameConsole.lightsLeft[i].img = new Image();

    this.gameConsole.lightsLeft[i].img.src =

      "images/frame-l-" + i + ".png";

    this.gameConsole.lightsRight[i].img = new Image();

    this.gameConsole.lightsRight[i].img.src =

      "images/frame-r-" + i + ".png";

  }

  for (i = 0; i < 4; i++) {

    this.catcher.imgs[i] = new Image(this.catcher.width, this.catcher.height);

    this.catcher.imgs[i].src = "images/catcher-" + i + ".png";

  }

  for (i = 0; i < 2; i++) {

    this.chicken.imgs.push(new Image(

      this.chicken.width, this.chicken.height

    ));

    this.chicken.imgs[i].src = "images/chicken-" + i + ".png";

  }

  this.eggData.egg = new Image(this.eggData.eggWidth, this.eggData.eggHeight);

  this.eggData.egg.src = "images/egg.png";

  this.eggData.eggSplat = new Image(

    this.eggData.eggSplatWidth, this.eggData.eggSplatHeight

  );

  this.eggData.eggSplat.src = "images/egg-splat.png";

  for (i = 0; i < 2; i++) {

    this.missile.imgs.push(new Image(

      this.missile.width, this.missile.height

    ));

    this.missile.imgs[i].src = "images/missile-" + i + ".png";

  }

  for (i = 0; i < 4; i++) {

    this.explosion.imgs.push(new Image(

      this.explosion.width, this.explosion.height

    ));

    this.explosion.imgs[i].src = "images/explosion-" + i + ".png";

  }

 

}

 

First, we get the height of the screen via the Mojo.Environment.DeviceInfo.screenHeight attribute.  Using that, the proper height for the background image and border frame can be calculated.  The reason we need to calculate this is because it allows us, at least in part, to deal with the different screen heights we need to support.  If you look in the images directory you’ll see that the background and frame images come in two versions, one suitable for a 400 pixels tall screen and the suitable for a 480 pixels tall screen.  Having the height of the screen we can dynamically load the appropriate image and make our game work at both resolutions.

 

You’ll see the screenHeight variable used throughout the code to allow the game to work at multiple resolutions.  For example, when the catcher is drawn, its vertical location uses this variable to calculate the appropriate location so that it’s near the bottom of the play area in either case.  Similarly, when eggs are dropping from the chicken, where they splatter depends on the height of the screen since at 480 pixels tall they have to fall further. 

 

Dealing with multiple resolutions can be a tricky issue.  One of the first choices you have to make is whether to have multiple versions of art resources or to scale them on-the-fly.  Scaling of course incurs a performance penalty, but multiple versions of resources means more memory usage (if only in storage space on the users’ device).  For this game, the only real concern is the background and frame images, so the choice was relatively simple.  Still, having to calculate values throughout the code based on the value of screenHeight is something to be careful of because it means overhead (although, as we’ll see later, not much).  In some cases it might be more efficient to have multiple versions of your main game loop code specific to a given resolution.  That’s something you’d probably never do in a business application, where code maintainability is a primary concern.  In game programming though, decisions like that are a bit less clear-cut!

 

The next step is to create a function bind around the mainLoop() method.  This is of course our main game loop, and we always want that to execute within the context of the game object itself.  Since this will be executed as a result of an interval, the bind makes sure that is always the case.  Similarly, the keyup, keydown and screen tap events are bound as are the orientation change and stage activate/deactivate events.  The orientation change event will be required to allow accelerometer control of the game, as we’ll see shortly.

 

With the binds out of the way, it’s time to pre-load all our game images.  This is just like pre-loading images for a web site to avoid flickering for mouse hover events, but here we’re doing it to avoid the overhead in the main game loop.  Since all of these resources are being served locally, there’s no real benefit like there is when loading them remotely in terms of avoiding that flicker because the load would be pretty much instantaneous (although, there’s nothing to say you couldn’t serve some of your game assets from a remote server if you wanted to, even though the game itself runs locally).

 

I won’t go into detail of each of the image loads because, by and large, they follow the same pattern.  They all look something like this:

 

this.gameConsole.left = new Image();

this.gameConsole.left.src = "images/console-left.png";

 

That’s a typical image preload snippet, so no surprises there.  There’s not a whole lot of point to specifying the Image objects’ dimensions as we have always been admonished to do on a web site because the reasoning behind that was to allow the browser to allocate the object on the screen at the correct size before the content was loaded form the server.  Since everything is loading locally though, and more importantly, because none of these images are being shown as part of a DOM load, there’s no real benefit, and in fact it’ll make our code that much harder to maintain because if we change any of the image sizes we need to modify this pre-load code too.

 

As noted, the background and border frame images are loaded based on the screen height, so the code is slightly different:

 

this.background = new Image();

this.background.src = "images/background-" + this.screenHeight + ".png";

 

The only other variance to this basic code structure is for those game sprites that have multiple frames of animation, the explosion for example, which has four frames to it.  To load that we have a little loop:

 

for (i = 0; i < 4; i++) {

  this.explosion.imgs.push(new Image());

  this.explosion.imgs[i].src = "images/explosion-" + i + ".png";

}

 

Once again, nothing too surprising there, and nothing too different from the rest either.  With all of the images loaded and ready for use, the init() method is complete.

 

Starting a new game

The startNewGame() method is next and it is called any time a new game is started, whether the first time since the application was called or when the player wants to try again after the game ends.  Its job is to reset all variables and state so that the game starts with a clean slate.  It’s also responsible for kicking off the interval that fires our main game loop 30 times a second:

 

startNewGame : function() {

 

  this.ctx.fillStyle = "rgb(255,255,255)";

  this.ctx.font = "normal normal bold 12pt arial";

 

  this.score = 0;

  this.previousScore = 0;

  this.scoreFlipAmount = 25;

 

  this.chicken.x = 128;

  this.chicken.animationFrame = 0;

  this.chicken.animationDelay = 0;

 

  this.chicken.dropX = Math.floor(Math.random() * (200 - this.xAdj)) + 28;

  this.chicken.speed = 3;

 

  this.catcher.damage = 0;

  this.catcher.x = 128;

  this.catcher.collisionBox.x1 = this.catcher.x - 5;

  this.catcher.collisionBox.y1 = this.screenHeight - 168;

  this.catcher.collisionBox.x2 = this.catcher.x + 64;

  this.catcher.collisionBox.y2 = this.screenHeight - 154;

 

  this.missile.inFlight = false;

  this.missile.animationFrame = 0;

  this.missile.animationDelay = 0;

  this.explosion.exploding = false;

  this.explosion.animationFrame = 0;

  this.explosion.animationDelay = 0;

 

  this.eggData.count = 0;

  this.eggData.eggs = [ 100 ];

 

  this.gameConsole.lightsDelay = 999;

  this.gameConsole.leftHandLast = null;

  this.gameConsole.rightHandLast = null;

  this.gameConsole.leftHandCurrentState = this.gameConsole.LEFT_HAND_NEUTRAL;

  this.gameConsole.rightHandCurrentState = this.gameConsole.RIGHT_HAND_UP;

 

  this.ctx.drawImage(this.gameConsole.left, 0, this.screenHeight - 80,

    39, this.gameConsole.consoleBottomHeight);

  this.ctx.drawImage(this.gameConsole.middle, 144, this.screenHeight - 80,

    49, this.gameConsole.consoleBottomHeight);

  this.ctx.drawImage(this.gameConsole.right, 287, this.screenHeight - 80,

    33, this.gameConsole.consoleBottomHeight);

 

  this.drawHands();

 

  this.gameInProgress = true;

  this.mainLoopInterval = setInterval(this.mainLoopBind, 33);

 

}

 

First, font styling is set on the canvas so that we have white text for the score.  After that, the three score-related variables are reset.  The scoreFlipAmount is initially set to 25 so that when score reaches that threshold the speed of the chicken and eggs will increase.  At that point, scoreFlipAmount will be increased too so that the game gets faster and faster, but does so slower and slower as time goes on.

 

The chicken needs to be set up next, and that begins with starting it off in the center of the screen, around horizontal location 128.  The animation frame and delay variables are reset as well.  A random horizontal location is also chosen at which an egg will be dropped, and the speed of the chicken and eggs is set.  When the chicken reaches the chosen location, the egg will be dropped and another location will be chosen for the next egg… but I’m getting ahead of myself a bit, that’s all done in the main loop, which is still to come!

 

One thing I should point out here is that if you’ve done any game programming in the past you’ll recognize that especially in terms of the animation-related code, the objects for the chicken, catcher, explosion and the eggs look a lot like what you’d expect a sprite class to look like.  Since I decided not to use a sprite or game engine here, I have to do all that work myself, and that means keeping track of what animation frame to show and when it is time to flip to the next frame.  That’s where these variables come in.  The benefit to having to do this work for ourselves is being in complete control and being able to optimize as much as possible.

 

The catcher is then set up, initially specifying that no damage is done.  If you’d like to know what it looks like when there is damage, have a look at this screenshot:

 

 

There isn’t too much damage done just yet, but as more eggs splatter, more damage is done, as you can see here:

 

 

At this point, one more splattered egg will end the game.

 

In addition to the damage, the initial horizontal location is also set, again centering the catcher on the screen.  Finally, the collisionBox object is calculated.  This is done based on the location of the catcher and the coordinates define a box a little bit above and to the sides of the catcher.  This gives the player a little bit of leeway when catching eggs, meaning it can be a touch imprecise, which is only fair when the speed kicks in! 

 

This box will be recalculated any time the player moves the catcher, but only when movements occur.  Calculating it every frame would have been a waste, and that’s another key optimization point: optimization by design is just about the best kind of optimization.  In this game, things are only drawn on the screen when they really have to be, even though the code would have been simplified by redrawing everything with every tick of the main game loop.  However, that would have caused the main loop to take more time each frame, which if nothing else means there’s less headroom if I wanted to add stuff to the game.

 

The missile is the next thing to be set up, and that means making sure it starts out not in flight, and its animation-related variables are reset.  The explosion is set up the same basic way.

 

Initially, there are no eggs being dropped, so we reset the count to zero and also clear out the array of eggs so we’re starting fresh.

 

Some setup needs to be done for the game console itself, meaning the flashing lights and the hands.  First, a high value is set for lightsDelay.  Since the lights are only changed every 11 frames (again, a simple optimization!), there would be an initial delay of 11 frames if we started the lightsDelay off at zero, as you might expect given how everything else is reset.  However, since I don’t want that delay, because it’s noticeable for the user, I want to ensure the lights are updated the very first frame, and setting the value to 999 ensures that.

 

The left and right hands are reset so that they start off in their initial, “neutral” positions (the left hand isn’t moving in any direction and the right hand is up ready to press the button).

 

Next, the bottom of the game console is drawn, but only the filler pieces.  These pieces are to the left and right of the hands, and in between the hands.  They form the control console of our virtual arcade machine.  Since these images never need to be drawn again we can again get a bit of an optimization by drawing them here and never having to think about them again!

 

After that, the drawHands() method is called.  We’ll see that code later, but I’m sure you can guess from its name that it draws the hands.  It uses the current state variables to determine which version of the hand images to draw.  This method will be called any time the player moves, so it’s got to be a separate function as it is.

 

Finally, we flip the flag to indicate a game is in progress and kick off the interval, calling the mainLoopBind function bind which wraps the mainLoop() method.  And in fact, that mainLoop() method is our very next stop!

 

Ready for action: The main game loop

The mainLoop() method is rather long and can look daunting if taken in all at once.  So, to avoid that, I’m going to break it up into chunks and discuss it little by little.  I think taking the pieces bit by bit you’ll find that there’s really nothing complex going on at all!

 

The first chunk we’ll look at is the very beginning of the method:

 

mainLoop : function() {

 

  var startTime = new Date().getTime();

  var i = 0;

 

First, the current time is grabbed so that we can do some frame timing logging at the end.  The variable i is declared for no other reason than my real-time JavaScript validator in Eclipse doesn’t like seeing the same variable declared more than once, and I’m in the habit of doing that, and this reminds me not to!

 

Next we come to a block of code responsible for updating the lights around the frame and putting the score on the screen:

 

var propName = "y" + this.screenHeight;

this.gameConsole.lightsDelay = this.gameConsole.lightsDelay + 1;

if (this.gameConsole.lightsDelay > 11) {

  this.ctx.drawImage(this.gameConsole.frame, 0, 0, 320,

    this.gameConsole.frameHeight);

  var scoreText = "Score: " + this.score;

  var textMetrics = this.ctx.measureText(scoreText);

  this.ctx.fillText(scoreText, (320 - textMetrics.width) / 2,

    this.screenHeight - 84);

  this.gameConsole.lightsDelay = 0;

  for (i = 0; i < 5; i++) {

    var n = Math.floor(Math.random() * 2);

    if (n == 1) {

      this.ctx.drawImage(

        this.gameConsole.lightsLeft[i].img,

        0, this.gameConsole.lightsLeft[i][propName],

        27, this.gameConsole.lightsLeft[i].height

      );

    }

    n = Math.floor(Math.random() * 2);

    if (n == 1) {

      this.ctx.drawImage(

        this.gameConsole.lightsRight[i].img,

        293, this.gameConsole.lightsRight[i][propName],

        27, this.gameConsole.lightsRight[i].height

      );

    }

  }

}

 

First, recall that the console object has two arrays, lightsLeft and lightsRight.  Also recall that each element of those arrays is an object that has attributes y400 and y480 that species the vertical location of a given light.  The propName variable here is calculated to specify either y400 or y480 so that we can dynamically get the appropriate location from the objects in these arrays when we get down to drawing the lights.

 

Next, the lightsDelay field of the gameConsole object is incremented and checked to see if it’s time to change the lights (every one-third of a second).  If it is, the frame is first redrawn because that image has none of the lights turned on.  That’ll be the next step.

 

Before even that though, since the frame would have just overwritten our score text, that needs to be redrawn first.  Note that the score text is only constructed once.  As it happens, string concatenations result in object creation, and therefore GC activity, so we want to minimize that as much as possible, and in this case that simply means ensuring we only build that string once.  We use the measureText() method of the 2D context of the canvas to see how wide that text is, and this is used to center the text on the screen.  Note too that as implemented, the score will only be updated three times a second, not as the score actually change.  If you watch the score as you play you’ll be able to (just barely I hope!) notice a slight lag between catching an egg and the score increasing.  I think three times a second is fast enough so that it’s not a problem, and the benefit is not having to do this work every single iteration of the game loop, so again, optimization by design comes into play.  You should always try to minimize the work you do in your main loop, most especially when it comes to drawing on the screen, since that’s likely to be some of the most time-consuming work your code has to do.  No need to update every last part of the screen every frame if you don’t have to!

 

With the score refreshed, it’s time to do the lights.  There are five lights on each side of the frame, hence the loop running for five iterations.  We choose a random number, either a zero or a one, with one representing the light being lit.  The gameConsole’s lightsLeft and lightsRight arrays contain the information we need to draw a light that is lit, namely the image of course, plus the vertical location (using that propName variable now to get the location appropriate for the screen’s height), and the height of the light image.  The width is always the same, and the horizontal locations are hardcoded for the left and right sides (each random number chosen corresponds to a light on the left and right).

 

At this point let me note something about this code in general.  You’ll notice in a number of places that I do something that is generally considered bad form, and that’s making the code less readable by using things like “magic numbers” and hardcoded values.  When it comes to writing games, speed is a key consideration, and there is a balancing act you have to play between optimized code and code readability and maintainability.

 

Instead of writing 267 in the two drawImage() calls for example, I could have defined a variable (a field on the game object most likely) called LIGHT_WIDTH perhaps.  That would have made those calls more readable since you wouldn’t have to guess what 27 was (not to mention that if I want to change the dimensions of those images I can’t just change that one variable).

 

However, there’s a trade-off to made, and that’s that you’ll incur some degree of performance penalty by doing so.  If nothing else, you’ll have a scope chain lookup cost, especially if make that value a field on the game object.  Now, taken on its own, this cost is probably next to nothing and you wouldn’t have to worry about it under normal circumstances.  In a game however, and inside the main loop no less, those costs can amortize quickly and combine to cost you real processing time that you could have used to make the game better.

 

So, you have to play a bit of a cost-benefit analysis game.  Is making the code as readable as possible the most important consideration?  Is ensuring maximum performance?  The answer is likely to be some degree of both, so you have to decide which is more important (and yes, you can debate my choices if you wish… I did!)

 

Anyway, back to the code!  With the frame, lights and score we can move on to the main game area, and the first task is to clean the play area:

 

this.ctx.drawImage(this.background, 27, 30, 266, this.backgroundHeight);

 

When you write a game you really have two choices to build up the current scene: either clear it and redraw everything, or keep track of where each sprite is so that you can repaint the parts of anything behind it that was previously occluded (blocked) before you move it to its new location.  If that sounds like more work than just clearing everything you’re completely right!  In fact, you’ll often times find that the loop takes a lot more time that way then just clearing and redrawing everything.  The logic involved can be more time-consuming than all the draw operations.

 

Another subtle benefit is that you’ll tend to get more consistent frame times this way since the amount of drawing will be more consistent from frame to frame.  What’s going on in the game of course plays into this, so it’s a general statement at best.

 

How you clear the play area is also determined by how your game is designed.  In this case, there’s a background image so simply drawing that background image does exactly what we want.  If you had some sort of dynamic background, say a moving starfield or something like that, you might have to clear it by drawing a filled in rectangle and then redrawing all the stars, and only then all the sprites.  With a background image though it’s a lot easier!

 

The next step is to deal with the eggs:

 

for (i = 0; i < this.eggData.count; i++) {

 

  if (this.eggData.eggs[i].y > 900) {

    this.mainAssistant.controller.serviceRequest(

      "palm://com.palm.audio/systemsounds", {

        method : "playFeedback", parameters : { name : "appclose" }

      }

    );

    this.ctx.drawImage(this.eggData.eggSplat,

      this.xAdj + this.eggData.eggs[i].x - 14,

      this.yAdj + (this.screenHeight - 150),

      this.eggData.eggSplatWidth, this.eggData.eggSplatHeight

    );

    this.eggData.eggs[i].y--;

    if (this.eggData.eggs[i].y < 980) {

      this.eggData.eggs[i].x = 0;

      this.eggData.eggs[i].y = 0;

      this.catcher.damage = this.catcher.damage + 1;

      if (this.catcher.damage > 3) {

        this.mainAssistant.controller.serviceRequest(

          "palm://com.palm.audio/systemsounds", {

            method : "playFeedback", parameters : { name : "card_02" }

          }

        );

        this.gameInProgress = false;

        clearInterval(this.mainLoopInterval);

        this.dialog = this.mainAssistant.controller.showDialog({

          template : "gameOver-dialog",

          assistant : new GameOverAssistant(),

          preventCancel : true

        });

        return;

      }

    }

  } else {

    this.ctx.drawImage(this.eggData.egg, this.xAdj + this.eggData.eggs[i].x,

      this.yAdj + this.eggData.eggs[i].y,

      this.eggData.eggWidth, this.eggData.eggHeight

    );

  }

 

  if (this.eggData.eggs[i].x >= this.catcher.collisionBox.x1 &&

    this.eggData.eggs[i].x <= this.catcher.collisionBox.x2 &&

    this.eggData.eggs[i].y >= this.catcher.collisionBox.y1 &&

    this.eggData.eggs[i].y <= this.catcher.collisionBox.y2) {

    this.score = this.score + 5;

    if (this.score > (this.previousScore + this.scoreFlipAmount)) {

      this.chicken.speed = this.chicken.speed + 1;

      this.scoreFlipAmount = this.scoreFlipAmount + 50;

      this.previousScore = this.score;

    }

    this.eggData.eggs[i].x = 0;

    this.eggData.eggs[i].y = 0;

  }

 

  if (!(this.eggData.eggs[i].x == 0 && this.eggData.eggs[i].y == 0) &&

    this.eggData.eggs[i].y < this.screenHeight) {

    this.eggData.eggs[i].y = this.eggData.eggs[i].y + this.chicken.speed;

    if (this.eggData.eggs[i].y > (this.screenHeight - 150)) {

      this.score = this.score - 5;

      if (this.score < 0) {

        this.score = 0;

      }

      this.previousScore = this.score;

      this.eggData.eggs[i].y = 1000;

    }

  }

 

}

 

That’s a fairly large chunk of code, but it’s pretty logical as you walk through it.  We’re going to process each egg that is currently falling, which is what the eggData.count field tells us.  For each, we begin by checking its vertical position.  If the value there is greater than 900, which is a special case that only occurs when an egg reaches the bottom of the screen and splatters, then we play a sound.

 

Note that I’m using the standard system sounds here.  This is actually an area where there is currently some work Palm needs to do.  You can use the HTML5 Audio object to play custom sounds, which is really what you’d want to do here to get a proper “splat” sound of some sort.  The problem is that the Audio object is notoriously problematic in terms of sounds not playing when they should, and worse, all but destroying frame rates.  It is, in simplest terms, unusable at the present time.  The only way to have sounds in webOS applications at the moment without impacting playability is to use the same set of system sounds that you’ll notice nearly every app today uses.  The PDK of course gives you proper audio capabilities, but since we’re not talking about the PDK here that doesn’t do us much good.  Hopefully a future webOS/Mojo update will alleviate the Audio problems and give game developers a proper way to do audio in the games, but for now, the system sounds will have to do.

 

The splattered egg image is then drawn at the appropriate location.  Since the splattered egg image is wider than the falling egg image, the horizontal location has to be adjusted so that the splatter appears centered against where the egg was.  In other words, if you drop a real egg on the table, you expect it to splatter where you dropped it, not a few inches to the side!


Next, the y field of the egg descriptor object (the object that describes the egg we’re currently working with) is decreased.  This is because that field is now being used as a sort of timer.  When its value falls below 980, only then will the splattered egg be cleared.  When it is determined (near the bottom of the chunk of code) that the egg has reached its “splatter point”, so to speak, the y value is set to 1000.  That means the egg will appear splattered for about two-thirds of a second (y is decreased by 1 every iteration of the loop, from 1000 to 980, so it’ll take 20 frames).

 

When y does fall below 980, the x and y fields are both set to zero, which is another “special” condition that will be checked for later to determine when that egg can be “destroyed”.  In addition, the damage to the catcher is increased and is then checked.  If it’s greater then three, then it’s time for the game to end.  Another system sound is played, and the gameInProgress field is set to false.  The main loop interval is cleared and the gameOver dialog is shown (we’ll look at that after we’re done with the main loop code, and a few other bits).

 

At this point it’s important to note that the interval was in fact cleared.  At first blush you may think you could get away with simply checking the value of gameInProgress with each iteration of mainLoop() and if its false, simply return right away.  Yes, that would work, but there’s a significant problem with that approach: your app won’t be a good webOS citizen!  If the interval keeps running, that means that even with your app minimized in card view it’ll still be doing some work, albeit minimal work.  That means it’s using up CPU cycles, which means it’s using up battery power, little by little.  This is something you always want to avoid any time your application doesn’t have focus.  As we’ll see a little later, the stage activate and deactivate events play into this, but even when we’re showing the gameOver dialog there’s no real point in having that loop continue in the background, even if it were to really not do anything.

 

Now, if the egg’s y location is less than 900 then that means the egg is falling, so we now need to draw the non-splattered egg image.

 

The next thing that needs to happen is to see if the egg has been caught.  This is accomplished by seeing if its location (x and y values) falls within the collisionBox we saw defined earlier.  If it does then the score is increased and the egg’s x and y values are set to zero.  The other thing that happens here is we see if the score now crosses the threshold to increase game speed.  If it does then the speed is increased, and the next threshold is also calculated.  The score is also recorded as previousScore so this check works as expected the next time around.

 

The final step is to move the egg.  So long as the egg’s x and y values aren’t zero, and so long as the egg’s horizontal location is still on the screen, we add to its y value using the chicken.speed value.  We then check to see if the egg has reached its “splatter point”, and if so we deduct a bit form the score and set the egg’s y value to 1000 so that the previously discussed logic kicks in to deal with the egg splattering.  That will of course not happen until the next execution of mainLoop(), but that’s fine.

 

One more bit of housekeeping is required to fully deal with the eggs:

 

for (i = 0; i < this.eggData.eggs.length; i++) {

  if (this.eggData.eggs[i].x == 0 && this.eggData.eggs[i].y == 0) {

    this.eggData.eggs.splice(i, 1);

    this.eggData.count = this.eggData.count - 1;

  }

}

 

We go through the array of eggs and remove any that have an x and y value of zero.

 

Now that the eggs are done its now time to deal with that pesky chicken.  Drawing the eggs before the chicken ensures that the eggs will always be behind the chicken as they emerge, and that looks a little more realistic!

 

this.ctx.drawImage(this.chicken.imgs[this.chicken.animationFrame],

  this.xAdj + this.chicken.x, this.yAdj + 2,

  this.chicken.width, this.chicken.height);

this.chicken.animationDelay = this.chicken.animationDelay + 1;

if (this.chicken.animationDelay > 2) {

  this.chicken.animationDelay = 0;

  this.chicken.animationFrame = this.chicken.animationFrame + 1;

  if (this.chicken.animationFrame > 1) {

    this.chicken.animationFrame = 0;

  }

}

if (!this.explosion.exploding) {

  var dropEgg = false;

  if (this.chicken.x < this.chicken.dropX) {

    this.chicken.x = this.chicken.x + this.chicken.speed;

    if (this.chicken.x >= this.chicken.dropX) {

      dropEgg = true;

    }

  } else {

    this.chicken.x = this.chicken.x - this.chicken.speed;

    if (this.chicken.x <= this.chicken.dropX) {

      dropEgg = true;

    }

  }

  if (dropEgg) {

    this.mainAssistant.controller.serviceRequest(

      "palm://com.palm.audio/systemsounds", {

        method : "playFeedback", parameters : { name : "down2" }

      }

    );

    this.eggData.eggs[this.eggData.count] =

      { x : this.chicken.x + 32, y : 52 };

    this.eggData.count = this.eggData.count + 1;

    this.chicken.dropX = Math.floor(Math.random() *

      (200 - this.xAdj)) + 28;

  }

}

 

The first task, naturally enough, is to actually draw the chicken.  The appropriate frame of animation is used from the imgs array in the chicken object, and then the animation variables are updated to keep the animation going.

 

Here again is another instance where performance trumps code clarity.  Using a sprite engine would almost certainly take care of this animation for us; indeed, a sprite engine without that capability wouldn’t be worth much.  However, it would require function calls.  We’d probably be calling something like an update() method on the chicken sprite object, which would take care of the animation, probably even its movements.  However, a function call has a certain degree of overhead.  It wouldn’t much matter in this game since we don’t have too many sprites, but imagine a game with dozens or hundreds of sprites.  Multiple the function call overhead by that number and you might start to see a more significant hit.  As with all the optimizations as trade-offs I’ve been discussing, it’s a judgment call.  In a more complex game you may very well put more weight into the cleaner code using a sprite engine would result in.  Ultimately though, this is the sort of code that the sprite engine would have to be doing for you basically, so it helps to see it here and understand it before you decide to cede that control to someone else’ code.

 

Back to the chicken though!  The next step is to see if an explosion is occurring, since during that period the chicken will pause.  If no explosion is occurring then the chicken needs to be moved.  Recall earlier that a random location was chosen for the next position an egg will drop from.  So, the code moves the chicken left or right towards that location.  If the location is reached then a new one is chosen and a flag is set to indicate an egg needs to be dropped.  At the end, that flag is checked and if set we play a sound and add a new egg descriptor object to the eggData.eggs array, which contains object describing each of the eggs currently falling.  Finally, a new dropX value is randomly chosen to indicate where the next egg will drop from (and also determines what direction the chicken will now move in).  If an explosion was occurring then none of this happens this frame, effectively pausing the chicken.

 

The player’s catcher basket needs to be dealt with next:

 

this.ctx.drawImage(this.catcher.imgs[this.catcher.damage],

  this.xAdj + this.catcher.x, this.yAdj + (this.screenHeight - 156),

  this.catcher.width, this.catcher.height

);

if (this.gameConsole.leftHandCurrentState ==

  this.gameConsole.LEFT_HAND_LEFT) {

  this.catcher.x = this.catcher.x - 4;

  if (this.catcher.x < 10) {

    this.catcher.x = 10;

  }

} else if (this.gameConsole.leftHandCurrentState ==

  this.gameConsole.LEFT_HAND_RIGHT) {

  this.catcher.x = this.catcher.x + 4;

  if (this.catcher.x > 212) {

    this.catcher.x = 212;

  }

}

if (this.gameConsole.leftHandCurrentState > 0) {

  this.catcher.collisionBox.x1 = this.catcher.x - 5;

  this.catcher.collisionBox.y1 = this.screenHeight - 168;

  this.catcher.collisionBox.x2 = this.catcher.x + 64;

  this.catcher.collisionBox.y2 = this.screenHeight - 154;

}

 

It’s fairly straightforward to deal with as compared to the eggs and chicken.  Once the catcher is drawn at the appropriate location, the current state of the left hand is checked.  This is used to determine whether the catcher should move left or right (or not at all).  At the end, if the catcher moved, we calculate a new collisionBox.  This is again a simple optimization: if the catcher isn’t moving then there’s no need to recalculate this, so we’re avoiding some work during some loop iterations.

 

The next thing to do is to determine if the player has changed directions since the last loop iteration:

 

if (this.gameConsole.leftHandLast !=

  this.gameConsole.leftHandCurrentState ||

  this.gameConsole.rightHandLast !=

  this.gameConsole.rightHandCurrentState) {

  this.drawHands();

}

this.gameConsole.leftHandLast = this.gameConsole.leftHandCurrentState;

this.gameConsole.rightHandLast = this.gameConsole.rightHandCurrentState;

 

If they current hand state of the left and/or right hand has changed then drawHands() is called.  Once again, this only occurs if the direction actually changed, so we’re not redrawing the hands during every frame, only when they’ve actually changed.

 

Only two things remain to deal with in the main game loop, and that’s the missile and explosion.  The missile, which you can see firing in the following screenshot, is first.

 

 

The code that deals with the missile is as follows:

 

if (this.missile.inFlight) {

  this.ctx.drawImage(this.missile.imgs[this.missile.animationFrame],

    this.xAdj + this.missile.x, this.yAdj + this.missile.y,

    this.missile.width, this.missile.height

  );

  this.missile.animationDelay = this.missile.animationDelay + 1;

  if (this.missile.animationDelay > 2) {

    this.missile.animationDelay = 0;

    this.missile.animationFrame = this.missile.animationFrame + 1;

    if (this.missile.animationFrame > 1) {

      this.missile.animationFrame = 0;

    }

  }

  if (this.missile.y <= 60 && this.missile.y >= 20 &&

    this.missile.x >= (this.chicken.x + 10) &&

    this.missile.x <= (this.chicken.x + this.chicken.width - 10)) {

    this.mainAssistant.controller.serviceRequest(

      "palm://com.palm.audio/systemsounds", {

        method : "playFeedback", parameters : { name : "focusing" }

      }

    );

    this.explosion.x = this.missile.x;

    this.explosion.y = this.missile.y - 20;

    this.explosion.animationFrame = 0;

    this.explosion.animationDelay = 0;

    this.explosion.exploding = true;

    this.missile.inFlight = false;

    this.score = this.score + 50;

    this.catcher.damage = this.catcher.damage - 1;

    if (this.catcher.damage < 0) {

      this.catcher.damage = 0;

    }

  }

  this.missile.y = this.missile.y - 6;

  if (this.missile.y <= 0) {

    this.missile.inFlight = false;

  }

}

 

This only executes is a missile has actually been fired of course, but if it has we begin with the usual tasks of actually drawing the missile on the screen and updating its animation.  Next, we see if its vertical location is within a range where the chicken is.  If so, we then check to see if its horizontal location also intersects the chicken.  If it does then a sound is played to indicate a hit and we set up for the explosion.  This means the x/y location of the collision is recorded, after adjusting it a bit so the explosion is centered on the strike point.  The explosion’s animation-related variables are reset and the score is increased.  Finally, since hitting the chicken is a good thing, we decrease the damage on the catcher a little bit.  If the missile flies off the top of the screen then that’s the end, we reset the inFlight flag so another missile can be fired.

 

The explosion itself is processed next if the explosion is in progress:

 

if (this.explosion.exploding) {

  this.ctx.drawImage(this.explosion.imgs[this.explosion.animationFrame],

    this.xAdj + this.explosion.x, this.yAdj + this.explosion.y,

    this.explosion.width, this.explosion.height

  );

  this.explosion.animationDelay = this.explosion.animationDelay + 1;

  if (this.explosion.animationDelay > 3) {

    this.explosion.animationDelay = 0;

    this.explosion.animationFrame = this.explosion.animationFrame + 1;

    if (this.explosion.animationFrame > 3) {

      this.explosion.exploding = false

    }

  }

}

 

It’s just animation to deal with this time around since the explosion doesn’t actually move, so it’s considerably simpler than most of the other sprites.  Once all the frames of animation are cycled through the explosion.exploding flag is set to false so the chicken can move again.  The following screenshot shows the explosion in progress.

 

 

One last thing is done in the main game loop, and that’s to calculate how long the frame took to process:

 

var endTime = new Date().getTime();

Mojo.Log.info("#### Frame Time : " + (endTime - startTime));

 

If you enable the appropriate log level in framework_config.json you’ll be able to watch the timings as they occur.  Interestingly, on a real Palm Pre, the average frame time is about 4ms.  This is a clear indication that all the optimizations were not for nothing!  There’s a ton of overhead left over to enhance the game with.  We could add multiple chickens, or multiple missiles, or maybe little baby chickens with bazookas hatching out of the splattered eggs and shooting at the catcher!  All of this is made possible by the smart, effective design choices made throughout to make the main loop function take as little time as possible.  In fact, we could go back and create out own rudimentary sprite engine to take care of the animation for us and make the code in the mainLoop() function less verbose, which would be a nice cleanup task to do.  At the end of the day we can get away with all those things because the code was written efficiently and avoids GC overhead as much as possible, which is the main point I’ve been stressing throughout!

 

Drawing some hands

We’ve seen the drawHands() function called a couple of time, and now its finally time to see it:

 

drawHands : function() {

 

  this.ctx.drawImage(

    this.gameConsole.leftHand[this.gameConsole.leftHandCurrentState],

    39, this.screenHeight - 80, this.gameConsole.leftHandWidth,

    this.gameConsole.consoleBottomHeight

  );

  this.ctx.drawImage(

    this.gameConsole.rightHand[this.gameConsole.rightHandCurrentState],

    193, this.screenHeight - 80, this.gameConsole.rightHandWidth,

    this.gameConsole.consoleBottomHeight

  );

 

}

 

A bit anticlimactic perhaps, it’s pretty simple!  Only the hands themselves need to be redrawn, not the console filler pieces in between and to the sides.

 

Handling input: keyDown events

With the main game loop out of the way we can now turn our attention to dealing with user input.  The game can be controlled in three ways: keyboard, screen taps and/or accelerometer.  Let’s begin with the keyboard input, which is dealt with primarily in the keyDown() function that we saw earlier is bound to the corresponding keyDown event:

 

keyDown : function(inEvent) {

 

  if (this.gameInProgress) {

 

    switch (inEvent.originalEvent.keyCode) {

 

      case Mojo.Char.q: case Mojo.Char.q + 32:

        this.gameConsole.leftHandCurrentState =

          this.gameConsole.LEFT_HAND_LEFT;

      break;

 

      case Mojo.Char.p: case Mojo.Char.p + 32:

        this.gameConsole.leftHandCurrentState =

          this.gameConsole.LEFT_HAND_RIGHT;

      break;

 

      case Mojo.Char.spaceBar:

        if (!this.missile.inFlight) {

          this.mainAssistant.controller.serviceRequest(

            "palm://com.palm.audio/systemsounds", {

              method : "playFeedback", parameters : { name : "back_01" }

            }

          );

          this.missile.inFlight = true;

          this.missile.y = this.yAdj + (this.screenHeight - 206)

          this.missile.x = this.catcher.x + 24;

          this.gameConsole.rightHandCurrentState =

            this.gameConsole.RIGHT_HAND_DOWN;

        }

      break;

 

    }

 

  }

 

}

 

This function only has to do something when the game is in progress, at which point we determine which key was pressed.  Note that the code checks for both upper and lower-case versions of the Q and P keys (left and right movement respectively) so there are no problems if caps lock is on.  For those two keys it’s just a matter of setting the current state of the left hand to one of the constant values defined in the gameConsole object.

 

The spacebar can also be clicked to fire a missile.  Only one missile at a time can be in flight though, so this event is ignored it one is already in flight.  If not, a sound is played to indicate missile launch and the initial location of the missile is determined based on the location of the catcher (the adjustments made ensure it fires from the center of the catcher).  The state of the right hand is also changed so that it will appear to press the button when redrawn during the next mainLoop() iteration.

 

Handling input: keyUp events

We also have to handle keyUp events, but the corresponding keyUp() function is very simple:

 

keyUp : function() {

 

  if (this.gameInProgress) {

    this.gameConsole.leftHandCurrentState =

      this.gameConsole.LEFT_HAND_NEUTRAL;

    this.gameConsole.rightHandCurrentState =

      this.gameConsole.RIGHT_HAND_UP;

  }

 

}

 

The current state of both hands is reset to their non-actuated positions.  Since we don’t keep track of what keys are pressed explicitly, resetting both hands is required here.

 

Handling input: Screen tap events

Building the keyDown() method first was actually very important because the other input handling will in fact piggyback off of it, as you can see here:

 

tapHandler : function(inEvent) {

 

  if (this.gameInProgress) {

    if (inEvent.down.x <= 160) {

      this.keyDown({ originalEvent : { keyCode : Mojo.Char.q } });

    } else {

      this.keyDown({ originalEvent : { keyCode : Mojo.Char.p } });

    }

  }

 

}

 

If the tap location is on the left side of the screen then we simulate the Q key being pressed by creating an object that Mojo would generate (sans all the details we don’t actually need) and calling keyDown() with it.  The P key is simulated being pressed for taps on the right side of the screen.

 

Handling input: Orientation changes (accelerometer)

With keyboard and screen tap events taken care of, we now need to deal with accelerometer input.   In this game we need only the simplest form of accelerometer access, namely detecting device orientation changes.

 

orientationChange : function(inEvent) {

 

  if (this.gameInProgress) {

    if (inEvent.pitch < -45 && inEvent.pitch > -90) {

      this.keyDown({ originalEvent : { keyCode : Mojo.Char.spaceBar } });

    }

    if (inEvent.roll < -5) {

      this.keyDown({ originalEvent : { keyCode : Mojo.Char.q } });

    }

    if (inEvent.roll > 5) {

      this.keyDown({ originalEvent : { keyCode : Mojo.Char.p } });

    }

  }

 

}

 

When the pitch of the device indicates it has been flicked forward (so that the screen is facing up), and when that pitch is within a defined range (so it doesn’t have to be flat on its back but also so that slight tilts, which is a natural viewing angle) then we simulate pressing the spacebar to fire a missile.  The same basic approach is taken for left and right movements: if the roll of the device is a bit off-center left or right, the Q and P keys are simulated.

 

Stage activation and deactivation

Earlier I talked about making sure the game is a good webOS citizen and doesn’t chew up resources when it isn’t being played.  I mentioned that the stage activation and deactivation are the hooks that allow us to this and we saw how function binds were created to the stageActivate() and stageDeactivate() method.  Well, don’t look now but here comes those methods:

 

stageActivate : function() {

 

  if (this.gameInProgress) {

    this.mainLoopInterval = setInterval(this.mainLoopBind, 33);

  }

 

}

 

 

stageDeactivate : function() {

 

  clearInterval(this.mainLoopInterval);

 

}

 

As discussed earlier, it’s a simple matter of clearing the interval when the stage is deactivated and restarting it when the stage is activated again.  Yep, that’s really all there is to it!

 

 

You of course can’t tell from this static screenshot, but when card-ified the game simply freezes and then restarts when it has focus again.

 

A job well done (maybe): The game over dialog

Whew, the main game loop code was certainly a lot to take in!  The good news though is that we’re nearly done exploring the code for this game.  In fact, there’s just one part left and that’s the gameOver dialog that appears when the game ends.  It all starts with some view markup, just like the instructions dialog:

 

<center>

 

  <h1>Game Over</h1>

 

  <h2>The chicken won.<br>Tough break for Earth!</h2>

 

  <h3>Final score: <span id="gameOver_spanFinalScore"></span></h3>

 

  <h3 id="gameOver_divNewHighScore" style="display:none;">

    You got the new high score!

  </h3>

 

</center>

 

<table border="0" width="100%"><tr>

  <td width="50%" align="center">

    <div id="gameOver_btnNewGame" x-mojo-element="Button"></div>

  </td>

  <td width="50%" align="center">

    <div id="gameOver_btnExit" x-mojo-element="Button"></div>

  </td>

</tr></table>

 

Well, that couldn’t be any simpler!  It’s just some simple HTML, nothing fancy, with two button widgets at the bottom.  The markup results in a dialog that looks like this:

 

 

As with any dialog, there’s an assistant backing it, and here is is:

 

function GameOverAssistant() { };

 

 

GameOverAssistant.prototype.setup = function() {

 

  game.mainAssistant.controller.setupWidget("gameOver_btnNewGame", { },

    { label : "New Game", buttonClass : "palm-button affirmative" }

  );

  Mojo.Event.listen(game.mainAssistant.controller.get(

    "gameOver_btnNewGame"),

    Mojo.Event.tap, function() {

      game.dialog.mojo.close();

      game.startNewGame();

    }

  );

 

  game.mainAssistant.controller.setupWidget("gameOver_btnExit", { },

    { label : "Exit App", buttonClass : "palm-button negative" }

  );

  Mojo.Event.listen(game.mainAssistant.controller.get(

    "gameOver_btnExit"),

    Mojo.Event.tap, function() {

      window.close();

    }

  );

 

};

 

 

GameOverAssistant.prototype.activate = function() {

 

  $("gameOver_spanFinalScore").innerHTML = game.score;

  var highScoreCookie = new Mojo.Model.Cookie("Etherient_FarOutFowl_HighScore");

  var highScore = highScoreCookie.get();

  if (!highScore || game.score > highScore) {

    highScoreCookie.put(game.score);

    $("gameOver_divNewHighScore").show();

  }

 

};

 

The setup() method takes care of the usual tasks: hooking up event handlers to the buttons.  I think the handler functions for them are pretty self-explanatory, so we won’t spend any time there.

 

The other task that needs to be accomplished is to see if the player achieved a new high score and to display their final score in either case.  Displaying the score is a simple insertion into a <div>’s innerHTML.  The high score cookie is then retrieved and the score is checked.  If there was no previous high score, or if the new score beats it, then the cookie is written out with the new value and an initially hidden <div> is shown to indicate they got the new high score.

 

 

It’s not much of a reward I suppose, but then, the game was going to eventually end in the Earths’ demise anyway so it seems fitting in a demented sort of way!

 

Wrapping things up

So, we’ve reached the end of our journey!  It took a while, but the reward is a fun (to some degree at least) game that is efficient and doesn’t suffer from stutters and slowdowns, all using standard web technologies.  In the process of exploring the code you got a look at multiple optimization techniques, which is probably the key takeaway from this article.  Designing things smartly, minimizing the work you do during your main loop and avoiding GC activity are all keys to great webOS game performance.  The trade-offs between hand-coding things or using a library was discussed, as was the trade-offs between code readability and maximizing performance.  Those two items especially are a continuum, there’s no right or wrong answer that will work in every case.  If nothing else, this article, and the project discussed in it, gives you an example of what one side of the coin looks like and the results you can achieve with it.

 

I encourage you now to take this exercise even further and try to expand on the game.  Add in some new play elements and see if you can keep the frame rate solid and stutter-free.  There’s certainly a lot of overhead available to you since the main loop takes only a few milliseconds at present, but trying to make that continue to be true as you add things to it is a worthwhile exercise I believe.

 

In the end, I hope you’ve enjoyed this article and learned a lot from it.  Remember, at the end of the day we’re talking about games here so if you aren’t having fun then you’re doing something seriously wrong!

 

-Frank W. Zammetti