Lab 6: Whack a Mole!

Fri Nov 17 12:34:44 EST 2006

The game you wrote in the previous lab was quite static and purely textual: nothing happened until the user typed a number into a dialog box, and the only reward was the dubious intellectual satisfaction of using binary search. This lab will build a game that is much less cerebral (if that's the right word in this context), and a bit more graphical and interactive. It's a rudimentary version of "shoot 'em up" games like Doom or Quake, though the real inspiration is my favorite arcade game, Whack a Mole. In honor of that, let's call the game WhaM.

In WhaM, an image (in my case, of a prairie dog like the ones here) jumps randomly around the screen. Your job is to hit the image with the mouse as fast as you can; after ten hits, your elapsed time is reported, and you get a chance to play again.

No prairie dogs were harmed in the creation of this lab.
Image from www.animalinfo.org/species/rodent/cynomexi.htm.

Free Advice:

Please heed this advice; the lab will be much easier if you do. (Either way, this is the last Javascript in the labs.)
 


Part 1: Interacting with a Browser

In this lab, you will write Javascript code that interacts much more closely with the browser than in the previous lab.

In Javascript's normal environment, the browser that is running the Javascript interpreter provides a library of useful functions that make it possible to control what the user sees on the page, and to provide interactive processing of user interface components like buttons, check boxes, option selectors, and text. It's also possible to generate HTML on the fly and and thus create and modify web page contents under program control. In this lab, we'll investigate only a small number of these features:

The browser lets a Javascript program manipulate a handful of objects, of which two matter here: the window that is currently being displayed, and the document that it contains. These objects, and their sub-components, have properties like position, color, text, images, etc., that can be examined and manipulated by Javascript code. In addition, the objects can respond to external events like mouse motion and clicking, and to internally-generated events like the passage of time. By manipulating these features, it's not too hard to make a plausible game or achieve other interesting effects.

Javascript code itself is included in the web page in a couple of ways. First, it may appear anywhere between <script> and </script> tags, as in previous labs. Normally you would put all variables and functions inside a pair of script tags at the top of your page.

Second, code can be included as an "event handler" for any object on the web page. The simplest example of this is a button in a form, as seen in an earlier lab. That example used the onClick event to do an operation when the button is pressed, but you can also use onMouseover and onMouseout to perform some action when the mouse enters a region, like an image, and when it leaves. (This is often how "rollovers" are done on web pages.) There are other mouse events as well, but these are sufficient for this lab.

Getting values from Forms

If you want to ask the user to provide a value for your program to use -- such as the speed at which the prairie dog moves -- you can use a prompt dialog box, or you can use a text field in a form. Here's how the latter possibility might be written:

	<form>
	Interval <input type="text" id="interval" value="1000" size="5"> msec
	</form
This will look like this on the web page:
Interval msec
We give the text field an id, that is, an identification that other components of the web page can use to refer to it; it's like the name of a variable.

The text field can subsequently be accessed through a rather long name that queries the document about an element with a specified id. You can load the value from the text field into a Javascript variable, or store a new value into the text field, as illustrated in these statements:

	// get the value of interval text field into variable v
	var v = document.getElementById("interval").value
	
	// do some computation...

	// store a new interval back into the text field
	document.getElementById("interval").value = v
Keep the names straight here: v is a Javascript variable; interval is the id of an object on the web page.

Images

Your image is placed on the page with an img tag. The img tag will handle a variety of image encodings, most often a GIF or a JPG. You can use any image that you like -- pop stars and politicians and professors are popular -- but choose one that is not too big, perhaps using PaintShop or a similar program to crop or resize a big image into something smaller.

Moving an Image

Once you have an image you like, you can position it anywhere on a web page with the style attribute. Here's an example that places an image dog.jpg with its left side 200 pixels ("200px") from the left side of the page and its top 100 pixels from the top of the page. It also attaches the identifier dog to the object so it can be referred to by Javascript code.
    <img id="dog" src="dog.jpg" style="position:absolute; left:200px; top:100px">
The style attribute is syntactically finicky, so when you make your own version of this kind of HTML, be sure to use exactly the same capitalization and spelling and punctuation that you see here.

Once the image has been given an id, you can use Javascript code to manipulate it, particularly to move it to some other position. For example, to move it to position (300, 200), you can set its left and top positions to new pixel values, using almost the same klunky syntax as in the example above:

	document.getElementById("dog").style.left = "300px"
	document.getElementById("dog").style.top = "200px"
If you replace the literal positions like "300px" with computed positions, the image will move each time these lines are executed with new values.

Repetitive Actions: setInterval and clearInterval

The Javascript library function setInterval() causes a computation to be repeated over and over at a specified time interval. You will use setInterval() in WhaM to cause the image to move to a new position every second or so.

The statement setInterval('code', msec) sets up a timer that will execute the code every msec milliseconds. Normally the code is just a function call, and the function itself contains all the operations to be repeated; those operations, which you will put into a function called moveit(), move the image to a new random place. So your code will include statements like

	setint_val = setInterval('moveit()', 1000)
You'll write a function newgame that sets everything up for each new game just before it starts. If you include this assignment statement in newgame, it will cause the image to move once per second. (The quotes are important; without them, the program may not work.)

The library function clearInterval() gives you a way to stop the repeating operation (otherwise it would go on forever). The value returned by a call to setInterval is used in a call to clearInterval, like this:

	clearInterval(setint_val)  // stop the calls to moveit
You will have to call clearInterval to make the image stop moving, when the Stop button is pushed and when the user has whacked the mole 10 times.


Part 2: Writing Your Program

Your assignment is to implement a version of WhaM. Our minimalist version looks like this before it starts:

and this shows what it says after the game is played:

You can make yours look more professional if you wish, by laying out the components anywhere and using any sizes, fonts, and colors that you like. For example, you could use Imagemask buttons instead of Form buttons, as you learned how to do in the graphics lab. You could add an image background with <body background="something.jpg">, and you could make the dialog at the end more expansive as well.

This is the specification of what your program must do:

  • When your program starts up it must display the image that will move around, a Start button, a Stop button, and a way for the user to specify an interval before a new game begins. The default interval must be 1000 msec.
  • When the user presses Start, a new game starts and the selected image is displayed at a random place.
  • The image must move to a new random place once per interval.
  • If the user presses the Stop button, the image must stop moving, and a subsequent Start must start things over from the beginning.
  • Each time the user successfully hits the image, the program must move the image to a new random place immediately (i.e., not wait for the current interval to end).
  • The program must keep track of the number of hits and the elapsed time. The current number of hits and the elapsed time must be displayed in the window status bar every interval.
  • When the user has hit the image 10 times, the program must display a confirm dialog box that reports the elapsed time and that also says something like "Another game?" If the user pushes OK, that starts a new game. If Cancel is pushed, the program stops.
  • The items are listed in the specification in the order in which it seems easiest to write the program. Do each piece and make it work before worrying about the next one.

    Each component of the user interface has a name in the Javascript program; your interface doesn't have to look like the one above, but you must use the specified names for variables and functions ("hit" and "hitcount" are different!). Don't use the name "int" for a variable; it's a reserved word in some versions of Javascript. Indent your code so its structure is clear.

    Template

    It can be hard to keep all the pieces straight, especially when you're new to programming. Here's a template for how things will look at the end; your job is mostly to figure out what replaces the comments in the template. Try to think clearly about what operation or operations each part must do, as implied by the spec above.

    Follow this template to organize your page! We've tried to make this orderly and easy to follow. Do not ignore it. Copy this part of the instructions into your HTML file and then start replacing the commented parts by your own code, in the order suggested above. Copy and paste example code from the instructions, then modify it appropriately.

    <script>
    // declare your variables here: hitcount, setint_val, starttime, ...
    
    function newgame() {
        // your code to set up for each new game goes here:
    	// call clearInterval() to reset the interval set by a previous game
    	// initialize hitcount, the number of hits, to 0
    	// call setInterval() to set the interval from the value in the form
    	// initialize starttime, the starting time, using new Date(...)
    }
    
    function moveit() {
        // your code to move your image goes here:
    	// move the image, using the code given above
    	// update the status bar by window.status = hitcount (or something nicer)
    }
    
    function hit() {
        // your code to handle each successful hit goes here:
    	// move the image by calling moveit()
    	// update hitcount, the number of hits
    	// if hitcount is 10 or more
    	//	call clearInterval() to stop the image from moving
    	//	compute the elapsed time (make another call to new Date())
    	// 	use confirm() to display statistics and ask about another game
    	//	if another game is to be played
    	//		call newgame()
    }
    </script>
    
    <img id="dog" src="yourimage.jpg" 
    	style="position:absolute; left:100px; top:60px" onClick='hit()'>
    
    <form>
    <input type=button value="Start" onClick='newgame()'>
    <input type=button value="Stop" onClick='clearInterval(setint_val); return true;'>
    <input type=text id=interval value="1000" size=5> msec
    </form>
    
    For calibration, my version inserts 20 lines of code into this template; each one of those lines is a simple variant of code given in these instructions and the class notes. If yours is much bigger, you are off on the wrong track.

    Draw the Interface

    Lay out the components: Start button, Stop button, initial image, and a way to set a new interval (e.g., a form or another button).

    Declare Variables

    You will need variables for several values used by your program, including hitcount for the number of times the image has been hit so far, interval for how long the image stays in one place, and starttime for the time at which the current game started. These are used in several places in your program, so declare them at the beginning of your program, before the function definitions:

    	var hitcount
    	// etc.
    

    New Random Positions

    You have to move the image every time the user successfully hits it with the mouse, and also each time the setInterval mechanism operates. So it's best to write a function that does the move operation and call it from those two places. Write a function called moveit() that will move the image to a new random place each time the function is called. The function will look like this:

    function moveit() {
    	document.getElementById("dog").style.left = 500 * Math.random() + "px"
    	// other statements go here
    }
    
    The built-in function Math.random() produces a different random number between 0 and 1 each time it is called; multiplying that by 500 scales it up to a number between 0 and 499. So this line creates a new random x value, and sets the left coordinate of the image to that many pixels. Thus this line will move the image to a new random horizontal position each time the function moveit() is called.

    You have to write the analogous line for the vertical position, and put it into moveit() properly. You should also use different values than 500 to make better use of the screen area.

    Dealing with Hits

    You need a way to react to the event that occurs when the user manages to hit the image. That means that you have to attach an onClick event to the image (within the img tag that includes the image), and that event has to call function hit() to record the hit.

    The function hit() has to increment the number of hits and test whether it has reached 10; if not, there's nothing more to do and it can return. If the count is 10, however, hit() should display a dialog box with the elapsed time and ask the user about another game. If the user wants to play again, then everything has to be re-initialized and the game reset to start over. Otherwise, the program is done.

    This will require an if statement to compare hitcount to 10, and another if to check the response. Use confirm(), which will pop up a dialog box, then return true if the OK button is pushed and false if the Cancel button is pushed. This lets you write the if statement that will decide whether to play another game or quit, depending on the user's response; for example, it might be some variation on

    	if (confirm("Another game?")) {
    		// code to play another game
    	}
    

    Computing Elapsed Time

    To compute the elapsed time, you need to record the time when the game is about to begin, then record it when the game has just ended, and display the difference between these two times. Javascript has a huge number of functions for manipulating dates and times, but only an awkward way to compute something as simple as elapsed time. Basically, you have to say
      starttime = (new Date()).getTime() // the time right now, in milliseconds
    
    and something analogous later to get the stop time. The difference between those two values is the elapsed time, still in milliseconds. You have to convert that to seconds and display it.

    Status Bar

    You can put any text you want into the status bar by assigning to the variable window.status. So keeping this up to date is pretty easy; just use an assignment statement like
         window.status = whatever
    
    wherever you intend to update it. If you want to be fancier, update the status bar every second as well, with a separate setInterval.

    (Privacy settings may prevent your code from changing the status bar. Check Tools / Options / Contents / Advanced and check the box "Change status bar text." In IE, there's a similar setting under Tools / Options / Web features / Enable Javascript / Advanced.)

    Good Programming Habits

    Use the Javascript Console to warn you about syntax errors.

    Write small sections at a time, and test as you go, as we have been suggesting above.

    Use alert statements to display results as computation proceeds, or just to verify that your program is going where you think it is. These are easy to add and help narrow down problems quickly.

    Add comments to your code to remind yourself of what some statement is doing, and perhaps to help the grader figure out what you had in mind as well. You can also "comment out" alert statements by sticking // at the beginning of the line; this leaves the code there for future use but it doesn't affect the program until you uncomment it.

    Indent your code the way it has been shown in class, and the way it appears in the instructions. Indenting the statements helps you see quickly what's included in a function or a condition or a loop; you should always maintain consistent indentation.


    Part 3: Finishing up

    When you're done, send us a mail message with the subject "Lab 6" and your name.

    It is a good idea to make sure that one of the lab assistants has seen your project in its working state, and that your files have been properly saved in your Unix account. If you're working on a cluster machine, mailing the file to yourself is a good way to preserve a copy. Do all of these before you quit.