Home >
jQuery and AIR - Moving from web page to application
My last few entries have all dealt with the Aptana program and how you can use to create Adobe AIR applications based on HTML. Being that I'm a jQuery fan boy, my examples have all made use of that framework as well. We've discussed how to setup and create your project in Aptana as well as how to create a distributable AIR file and badge for your installation. Now it's time to look into how we can really extend jQuery to make use of Adobe AIR.
To begin this process, I'm going to use as my base a simple jQuery application: Hangman. For folks who may not be from this planet and know what Hangman is - it's a game with a simple premise. You are given a word where all the letters are represented by dashes. You guess one latter at a time. As you guess, if your guess matches one of the letters in the word, the dashes are replaced. If you guess wrong, however, a picture of a hangman gradually gets drawn out. If the hangman picture completes, you've lost the game.
So with that in mind I whipped up a quick demo. This does not make use of any AIR features at all. I wanted to get the game built first and then gradually start to improve it. The game could also be written a bit better. I'm beginning to get a bit more experienced with JavaScript, and jQuery in particular, and while I don't think I write great code, I feel like I'm beginning to recognize where things can be better. My game's JavaScript code really should move into a package by itself (and maybe later on I'll do that) but for now it works good enough.
I began by simply creating a "layout area" for all the regions of my game:
I used some nice CSS (well, ok, I used CSS) to layou out the divs how I wanted. And with that I then began slinging code. First off, my jQuery initialization block:
There isn't much here really as I moved the game logic to initGame(). I do have a listener to a click even on playagain. That div doesn't actually exist - hence the need for the live feature of jQuery. Now let's look at initGame():
In a nutshell, this block sets some defaults for my variables. Lettersused, for example, represents my guesses. currentWord is the word you need to guess for the current game. (Currently this is simply an array of around 20 words.) Both the drawWord and drawHangman functions though are pretty interesting:
The dragHangman function works on the basis that my images are numbered and match the number of misses. My first image begins with one so I need to add one to it first. In my first build I actually used HTML to create an IMG tag which was then inserted into the page. This worked but created a "flash" as the image loaded. By changing the source I get a much smoother affect.
drawWord is a bit more complicated. For each letter in the word it checks to see if you've guessed that letter. If you have, we add the letter, otherwise we add a dash. So in the word "dog", if you have guessed ABCD, then you will see: "d--".
The last part of the initGame() function simply listens to my keyboard. Now here is where things got a bit weird. In my tests I was able to enter "a" or "A". But when I deployed to a "real" AIR install, entering "a" always returned "A". I blogged about this but have yet to figure out why. As it stands, I really want to ignore lowercase characters anyway so my code just upper cases anything. The range filter in there ensures I ignore letters and other characters.
handleGuess handles, well, the guess. It is relatively simple:
Basically - ensure we haven't guessed before and if not, add it to our lettersused variable. Finally, see if we hit or miss on the guess. checkDeath and checkWin both see if the game has ended in either state:
If the number of misses is 9, the game has ended, and if the word display equals are chosen word, the user won.
I've packaged this up as an AIR install you can grag here. (No AIR badge install here yet as I'm unsure if I can do that in a blog entry here.)
Check it out and see if you can win a few rounds. As I said, this is minimally an AIR application. It makes no use of the file system or any other special feature. But I bet we can improve that!
To begin this process, I'm going to use as my base a simple jQuery application: Hangman. For folks who may not be from this planet and know what Hangman is - it's a game with a simple premise. You are given a word where all the letters are represented by dashes. You guess one latter at a time. As you guess, if your guess matches one of the letters in the word, the dashes are replaced. If you guess wrong, however, a picture of a hangman gradually gets drawn out. If the hangman picture completes, you've lost the game.
So with that in mind I whipped up a quick demo. This does not make use of any AIR features at all. I wanted to get the game built first and then gradually start to improve it. The game could also be written a bit better. I'm beginning to get a bit more experienced with JavaScript, and jQuery in particular, and while I don't think I write great code, I feel like I'm beginning to recognize where things can be better. My game's JavaScript code really should move into a package by itself (and maybe later on I'll do that) but for now it works good enough.
I began by simply creating a "layout area" for all the regions of my game:
<!-- Game Area -->
<div id="gameArea">
<!-- Hangman pic -->
<div id="hangmanStatus"><img id="hangmanimage" src=""></div>
<!-- right area, used for various text -->
<div id="mainText">
<p class="instruction">
To begin, simply type the letter you would like to guess. Right answers will help reveal the mystery word. Wrong answers will lead to your untimely demise!
</p>
<!-- where to put used letters -->
<div id="usedLetters">
<p>
Used Letters: <span id="letterList"></span>
</p>
</div>
<!-- where to place guesses -->
<div id="gameStatus">
</div>
</div>
<!-- word display -->
<div id="wordDisplay"></div>
</div>
I used some nice CSS (well, ok, I used CSS) to layou out the divs how I wanted. And with that I then began slinging code. First off, my jQuery initialization block:
//My uber Ready to Go block. This is where the magic happens...
$(document).ready(function() {
initGame()
$("#playagain").live("click", function() {
initGame()
return false
})
})
There isn't much here really as I moved the game logic to initGame(). I do have a listener to a click even on playagain. That div doesn't actually exist - hence the need for the live feature of jQuery. Now let's look at initGame():
function initGame() {
lettersused = ''
$("#letterList").html(lettersused)
$("#gameStatus").html('')
//First, pick the word for our game.
currentWord = pickRandomWord()
//current status of hangman, no misses
misses = 0
//draw the word in DASHES in the wordDisplay area.
drawWord()
//now draw the hangman initial graphic
drawHangman()
//now begin listening for key clicks
$("BODY").keypress(function(e) {
//only care if between A and z
if(e.which >= 65 && e.which <= 122) {
var c = String.fromCharCode(e.which)
c = c.toUpperCase()
handleGuess(c)
}
})
}
In a nutshell, this block sets some defaults for my variables. Lettersused, for example, represents my guesses. currentWord is the word you need to guess for the current game. (Currently this is simply an array of around 20 words.) Both the drawWord and drawHangman functions though are pretty interesting:
//I draw the hangman based on the # of misses. We have a nice one to one correlation with the graphic and number of misses
function drawHangman() {
var currentGfx = "images/Hangman-" + (misses+1) + ".png"
$("#hangmanimage").attr("src",currentGfx)
}
//I draw the word in the game area, smartly replacing unknown letters with -
function drawWord() {
var maskedWord = ""
for(var i=0; i<currentWord.length;i++) {
var thisLetter =""
thisLetter = currentWord.substring(i,i+1)
if(lettersused.indexOf(thisLetter) >= 0) maskedWord += thisLetter
else maskedWord += "-"
}
$("#wordDisplay").html(maskedWord)
}
The dragHangman function works on the basis that my images are numbered and match the number of misses. My first image begins with one so I need to add one to it first. In my first build I actually used HTML to create an IMG tag which was then inserted into the page. This worked but created a "flash" as the image loaded. By changing the source I get a much smoother affect.
drawWord is a bit more complicated. For each letter in the word it checks to see if you've guessed that letter. If you have, we add the letter, otherwise we add a dash. So in the word "dog", if you have guessed ABCD, then you will see: "d--".
The last part of the initGame() function simply listens to my keyboard. Now here is where things got a bit weird. In my tests I was able to enter "a" or "A". But when I deployed to a "real" AIR install, entering "a" always returned "A". I blogged about this but have yet to figure out why. As it stands, I really want to ignore lowercase characters anyway so my code just upper cases anything. The range filter in there ensures I ignore letters and other characters.
handleGuess handles, well, the guess. It is relatively simple:
function handleGuess(l) {
//ok, first off, was this already used?
if(lettersused.indexOf(l) >= 0) {
alert('You already used the letter '+l)
return
}
//add the latter
lettersused+=l
$("#letterList").html(lettersused)
//bad letter?
if(currentWord.indexOf(l) == -1) {
misses++
drawHangman()
checkDeath()
} else {
//redraw our word
drawWord()
checkWin()
}
}
Basically - ensure we haven't guessed before and if not, add it to our lettersused variable. Finally, see if we hit or miss on the guess. checkDeath and checkWin both see if the game has ended in either state:
function checkDeath() {
if(misses == 9) {
$("#gameStatus").html("Game over, man! You lost!<br/><a href='' id='playagain'>Play Again?</a>")
$("BODY").unbind("keypress")
}
}
function checkWin() {
if($("#wordDisplay").html() == currentWord) {
$("#gameStatus").html("Congratulations! You Won!!<br><a href='' id='playagain'>Play Again?</a>")
$("BODY").unbind("keypress")
}
}
If the number of misses is 9, the game has ended, and if the word display equals are chosen word, the user won.
I've packaged this up as an AIR install you can grag here. (No AIR badge install here yet as I'm unsure if I can do that in a blog entry here.)
Check it out and see if you can win a few rounds. As I said, this is minimally an AIR application. It makes no use of the file system or any other special feature. But I bet we can improve that!




Facebook Application Development
Hi Raymond,
I love Hangman game and would love to play it when I have some free time. It is a such a nice game that helps improve and increase one's vocabulary. Please keep me posted where I would be able to access it.
And thanks for coming out with your very own 'flavor'.
Text Anil Atluri - Impeccably authentic freelance content provider.