Lab 6: Whack a Mole!

Mon Nov 10 16:22:24 EST 2014

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 more graphical and interactive, and less cerebral (if that's the right word in this context). 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. The player tries to hit the image with the mouse as fast as possible; after three hits, the elapsed time is reported, and the player gets a chance to play again.

Your job is to write this program.

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

Free Advice:


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.

The browser provides a library of user interface components like buttons, check boxes, option selectors, and text, and useful functions that make it possible to control what the user sees on the page. It's also possible to generate HTML on the fly and thus create and modify web page contents under program control. In this lab, we'll investigate a few 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, after html and title and before body.

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. 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 as in Lab 3. Here's how the latter possibility might be written:

	<form>
	Speed <input id="speed" type="text" value="1000" size="5"> msec
	</form>
This will look like this on the web page:
Speed 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 speed text field into variable v
	var v = document.getElementById("speed").value;
	
	// do some computation...

	// store a new speed back into the text field
	document.getElementById("speed").value = v;
Keep the names straight here: v is a Javascript variable; speed 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, politicians and professors are popular -- but choose one that is not too big, perhaps using Photoshop or GIMP 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, 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 the literal positions like "300px" are replaced by computed positions, the image will move each time these lines are executed with new values; this is illustrated below.

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 a statement like this:

	setint_val = setInterval('moveit()', document.getElementById("speed").value);
You'll write a function newgame that sets everything up for each new game just before it starts. If you include this statement in newgame, it will cause the image to move once per second. (The quotes around moveit() are required; 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 repeated 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 3 times.


Part 2: Writing Your Program

Your assignment is to implement a version of WhaM. My 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. But don't do that until you have the basic program working.

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 speed before a new game begins. The default speed 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 everything 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).
  • When the user has hit the image 3 times, the program must display a confirm dialog box that reports the elapsed time in seconds and that also says something like "Another game?" If the user pushes OK, that starts a new game immediately (no need to push Start again). If Cancel is pushed, the program stops.
  • The items are listed in this 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.

    Template

    It can be hard to keep all the pieces straight, especially when you're new to programming, so we're giving you a template for organizing your program. Your job is to figure out the proper statements to replace the comments in the template. Try to think clearly about what operation or operations each part must do, as implied by the spec above.

    This link points to the template lab6.html. Create your own HTML file lab6.html by downloading the template directly (right click in Windows, Option click in Mac) 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. Follow this template to organize your page! We've tried to make this orderly and easy to follow. Do not ignore it.

    <html>
    <title> Your title goes here </title>
    <body>
    <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=speed value="1000" size=5> msec
    </form>
    
    <script>
    // declare your variables here: hitcount, setint_val, starttime, ...
    
    function newgame() {
        // your code to set up for each new game goes here:
    	// clearInterval(setint_val) to reset the speed set by a previous game
    	// set hitcount to 0
    	// call setInterval() to set the speed 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 below
    }
    
    function hit() {
        // your code to handle each successful hit goes here:
    	// move the image with moveit()
    	// add 1 to hitcount
    	if (hitcount >= 3) {
    	   // clearInterval() to stop the image from moving
    	   // compute the elapsed time (make another call to new Date())
    	   // confirm() to display time and ask about another game
    	   // if another game is to be played
    	   // 	newgame()
    	}
    }
    </script>
    </body>
    </html>
    
    For calibration, my version inserts fewer than 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 your code is much bigger, you are off on the wrong track. Follow the template. The logic in this program is simpler than in the previous lab, but there are more other details to get right.

    Draw the Interface

    Lay out the components: Start button, Stop button, initial image, and a way to set a new speed (e.g., a form or another button). You can include a background image if you like.

    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, speed 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 number 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 add it to moveit(). You can 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 3. If not, there's nothing more to do and it can return. If the count is 3, 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 3, 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 start, 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.

    Good Programming Habits

    Use the Javascript Console to warn about syntax errors. Really. We mean it. Use the Javascript Console to warn about syntax errors. Really.

    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. You can also use console.log statements in your program and see the results on the Web Console.

    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

    Make sure that you have implemented what we asked for, listed above. When we grade, we will be looking to see that your program works, that it's reasonably cleanly written (properly indented, for instance), and whether you did anything special to make it more than the bare minimum.

    When everything is working, then

    Upload lab6.html and your image file(s) to the CS dropbox for Lab 6 at
          https://dropbox.cs.princeton.edu/COS109_F2014/Lab6.
    Optional: If you wish, you can copy your lab6.html file to your cPanel account so others can play your amazing game.