Showing posts with label canvas. Show all posts
Showing posts with label canvas. Show all posts

Saturday, September 13, 2008

Javascript Hangman

Hangman is a popular pencil and paper game. One player chooses a word and draws dashes to represent the length of the word.

The other player guesses letters. If the letter is in the word the dash is replaced with the letter. If the guessed letter is not in the word then a part of the hanging body is drawn (head, body, left leg, right leg, left arm, right arm) once the body is completely drawn or the entire word has been guessed the game is over.

I decided to re-create this game using Javascript and the html canvas object. Javascript is used to handle the game while the canvas is used to draw the hangman character when the guesses are incorrect.

To start lets define a simple html page that includes our canvas and a couple of spans to hold the word and messages for the user.

<html>
<body onload="draw();" onkeyup="handleKeyUp(event);">
<table>
<tr>
<td colspan=2>
<span id='alreadyGuessed' style="visibility:hidden">Letter already guessed</span>
<span id='strike' style="visibility:hidden">Strike!</span>
</td>
</tr>
<tr>
<td>
<canvas id='hangman' width=150 height=150>
</td>
<td>
<span id='word'></span>
</td>
</tr>
</table>
</body>
</html>


When the page is loaded we call 'draw()' and we setup a keyboard listener to listen to keystrokes. We've defined a few simple span's that will be messages to the user, a canvas to draw the victim and a span to hold the word that the user will be guessing.

The game expects a character from A-Z so our keyboard listener should filter out all other values here is what our listener looks like:

function handleKeyUp(evt) {
var e = evt ? evt : event;
if (e.keyCode >= 65 && e.keyCode < (65+26) ) {
guess(String.fromCharCode(e.keyCode));
}
draw();
}



The keyCode value is the ASCII representation we know that the ASCII characters are in sequence with capital 'A' being 65 and capital 'Z' being 65+26 characters away. If the user enters a valid character we enter our 'guess' function else we do nothing. After guessing our draw() function is called to redraw the screen.

The draw function as you have now seen is called when the game is first loaded and after each keypress lets see what it does.

function draw() {
var str='';
for(i=0;i<word.length;++i) {
if (foundLetters[i]) {
str += word[i];
} else {
str += '_';
}
str += ' ';
}
document.getElementById('word').innerHTML = str;
}



The draw function looks at our internal data structures which will explore later and determines if the user has guessed a letter yet or not. If the letter has been guessed the letter is shown, else a '_' is shown instead.


So now to the heart of the game, the guess function.

function guess(key) {
hideMessages();
if (guessedLetters[key]) {
showAlreadyGuessed();
return;
}
guessedLetters[key] = true;
var found = false;
for(i=0;i<word.length;++i) {
if (word[i] == key) {
foundLetters[i] = true;
found=true;
}
}
if(!found) showStrike();
return found;

}



The guess function iterates over the chosen word and determines if the character in the word has been guessed. If it has it marks foundLetters[index] where index is the index of the character that has been revealed. We saw in the 'draw' function how this is used to change the display.

The last thing to note is how we use the canvas element to draw a very crude hangman as the user guesses incorrectly.


function drawHangMan(numberOfStrikes) {
var canvas = document.getElementById('hangman');
if(canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.save() ;
ctx.translate(45,45);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
if(numberOfStrikes >= 1) ctx.fillRect(0,0,10,10); //head
if(numberOfStrikes >= 2) ctx.fillRect(-5,10,20,20); //body
if(numberOfStrikes >= 3) ctx.fillRect(-20,10,20,5); //left arm
if(numberOfStrikes >= 4) ctx.fillRect(0,10,30,5); // right arm
if(numberOfStrikes >= 5) ctx.fillRect(-5,30,5,10); // left leg
if(numberOfStrikes >= 6) ctx.fillRect(10,30,5,10); // right leg

ctx.fill();
ctx.restore();
}
}



This method is pretty self explanatory. Based on the number of strikes more of the hangman's body will be revealed.

Here is the entire code listing, let me know if you have any questions. Enjoy...


<html>
<head>
<script type="application/x-javascript">

var words = new Array();
words[0] = "Ford";
words[1] = "Chevy";
words[2] = "Mazda";
words[3] = "Volvo";
words[4] = "Javascript";
words[5] = "Google";
words[6] = "Microsoft";
words[7] = "Nvidia";


var rand_no = Math.random();
rand_no = Math.ceil(rand_no * words.length)-1;


word = words[rand_no].toUpperCase();
var foundLetters = new Array();


var guessedLetters = new Array();
function hideMessages() {
document.getElementById("alreadyGuessed").style.visibility='hidden';
document.getElementById("strike").style.visibility='hidden';
}
function showAlreadyGuessed() {
document.getElementById("alreadyGuessed").style.visibility='';
}

function drawHangMan(numberOfStrikes) {
var canvas = document.getElementById('hangman');
if(canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.save() ;
ctx.translate(45,45);
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
if(numberOfStrikes >= 1) ctx.fillRect(0,0,10,10); //head
if(numberOfStrikes >= 2) ctx.fillRect(-5,10,20,20); //body
if(numberOfStrikes >= 3) ctx.fillRect(-20,10,20,5); //left arm
if(numberOfStrikes >= 4) ctx.fillRect(0,10,30,5); // right arm
if(numberOfStrikes >= 5) ctx.fillRect(-5,30,5,10); // left leg
if(numberOfStrikes >= 6) ctx.fillRect(10,30,5,10); // right leg

ctx.fill();
ctx.restore();
}
}

var numberOfStrikes=0;
function showStrike() {
numberOfStrikes++;
drawHangMan(numberOfStrikes);
document.getElementById("strike").style.visibility='';
}


function guess(key) {
hideMessages();
if (guessedLetters[key]) {
showAlreadyGuessed();
return;
}
guessedLetters[key] = true;
var found = false;
for(i=0;i<word.length;++i) {
if (word[i] == key) {
foundLetters[i] = true;
found=true;
}
}
if(!found) showStrike();
return found;

}
function draw() {
var str='';
for(i=0;i<word.length;++i) {
if (foundLetters[i]) {
str += word[i];
} else {
str += '_';
}
str += ' ';
}
document.getElementById('word').innerHTML = str;
}
function handleKeyUp(evt) {
var e = evt ? evt : event;
if (e.keyCode >= 65 && e.keyCode < (65+26) ) {
guess(String.fromCharCode(e.keyCode));
}
else {
//alert("You entered " + e.keyCode);
}
draw();
}


</script>
</head>
<body onload="draw();" onkeyup="handleKeyUp(event);">
<table>
<tr>
<td colspan=2>
<span id='alreadyGuessed' style="visibility:hidden">Letter already guessed</span>
<span id='strike' style="visibility:hidden">Strike!</span>
</td>
</tr>
<tr>
<td>
<canvas id='hangman' width=150 height=150>
</td>
<td>
<span id='word'></span>
</td>
</tr>
</table>
</body>
</html>

Friday, September 12, 2008

HTML Canvas Element - Part 3

This is Part 3 of the HTML Canvas Tutorial. If you haven't already you should read Part 1 and Part 2.

In this section we will create a key press listener and zoom our triangle in when we press 'z' and out when we press 'x'.

To do this we add a onKeyUp event to the body tag, and a corresponding handleKeyUp javascript function:

function handleKeyUp(evt) {
var e = evt ? evt : event;
if (e.keyCode == 90) {
scale+=.1;
} else if(e.keyCode == 88) {
scale-=.1;
}
draw();
}


<body onload="draw();" onkeyup="handleKeyUp(event);">
<canvas id="canvas" width="150" height="150"></canvas>
</body>


The variable scale is defined as a global javascript variable and we'll use it to call 'ctx.scale(x,y)'

Before we do that though we'll have to call clearRect(x,y,width,height) to clear the image and redraw. The entire script is displayed below:

<html>
<head>
<script type="application/x-javascript">

var scale=1;
function draw() {
// Get Reference to the 'canvas' tag
var canvas = document.getElementById("canvas");
if (canvas.getContext){
// Get a context that allows us to draw on.
var ctx = canvas.getContext('2d');
ctx.save();
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.scale(scale,scale);

// Move cursor and draw the outline of the Triangle
ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(50,0);
ctx.lineTo(100,100);
ctx.lineTo(0,100);

// Actually Draw, you could call stroke instead which will draw the outline
ctx.fill();
ctx.restore();

}

}
function handleKeyUp(evt) {
var e = evt ? evt : event;
if (e.keyCode == 90) {
scale+=.1;
} else if(e.keyCode == 88) {
scale-=.1;
}
draw();
}


</script>
</head>
<body onload="draw();" onkeyup="handleKeyUp(event);">
<canvas id="canvas" width="150" height="150"></canvas>
</body>
</html>


That's it! I hope that got you interested in the Canvas element. If you have any questions leave a comment and I would be glad to answer them.

For more information I recommend the following sites:
http://developer.mozilla.org/en/Canvas_tutorial
http://en.wikipedia.org/wiki/Canvas_(HTML_element)
http://blog.vlad1.com/2008/06/04/html-canvas-in-firefox-3/

HTML Canvas Element - Part 2

In Part 1 of the series we set up a simple template to build the rest of the example on.

Our goal is to display a triangle and allow the user to zoom in and zoom out.

In this part we will display a black triangle on a white background. Replace your draw function with this one and then refresh your browser.

function draw() {
// Get Reference to the 'canvas' tag
var canvas = document.getElementById("canvas");
if (canvas.getContext){
// Get a context that allows us to draw on.
var ctx = canvas.getContext('2d');

// Move cursor and draw the outline of the Triangle
ctx.beginPath();
ctx.moveTo(0,100);
ctx.lineTo(50,0);
ctx.lineTo(100,100);
ctx.lineTo(0,100);

// Actually Draw, you could call stroke instead which will draw the outline
ctx.fill();
}

}


You should now see a black triangle on a white background. The code got a drawing context by calling canvas.getContext("2d").

We then use the moveTo command which picks up the cursor and moves to the location without drawing. Notice the coordinate system starts in the upper left with x extending to the right and y extending down.

We start our path with beginPath(). This will clear out any other draw commands and now your ready to trace your path with lineTo. One we have traced our triangle with the lineTo commands we call 'ctx.fill()' Which draws the shape and fills it with a solid color. Alternatively we could of called 'ctx.stroke()' which will draw the outline.

Continue to Part 3 to learn how to Zoom in/out the triangle.

HTML Canvas Element

The canvas html tag element allows web developers to draw graphics in the browser through a scripting language, typically JavaScript.

In this tutorial, we will create a triangle and allow the user to zoom in or zoom out the picture. Before we get started lets set up our environment. All you'll need is your web browser and a text editor.

Open your text editor (notepad will work just fine) and enter the following:
<html>
<head>
<script type="application/x-javascript">

function draw() {
alert("hi");
}


</script>
</head>
<body onload="draw();">
<canvas id="canvas" width="150" height="150"></canvas>
</body>
</html>


This is our template that we will use for the rest of the tutorial. We've added a canvas element and when the HTML body is loaded our draw() function will be called.

If you save the text file and load it in your browser it should print a message box saying 'hi'. If not please re-read the above until you have this working.

Continue to Part 2