Computer Science 252
Problem Solving with Java

Spring 2014, The College of Saint Rose

Lab 5: Frogger
Due: 11:59 PM, Wednesday, March 19, 2014

For your next lab, you will implement a simplified version of the popular 1980's video game called Frogger.

You may work alone or with a partner on this lab. There are no lab questions or practice programs this week, just one (fairly substantial) programming assignment.

In this game, you control a frog that is trying to cross a busy 4-lane highway. Each lane has cars or trucks zooming by. The vehicles in a given lane all travel at the same speed, but vehicles in different lanes may travel at different speeds (and even in different directions if you would like).

Pressing an arrow key causes the frog to "hop" (one hop is the width of a lane of traffic) in the appropriate direction. The goal is for the user to get the frog across the highway without it getting squished by a car or truck.

If the frog does get squished, it should display an "OUCH!" message at the bottom of the screen. The user should be able to restart the frog from its original starting position by pressing a "Play Again" button.

A working solution for this program will appear below. Click inside the applet to interact with it.



A working solution to the program can also be downloaded here.

Getting Started

It is recommended that you begin by downloading this starter BlueJ project. You can also download a BlueJ project with compiled solution code../../examples/Frogger/Frogger.zip (but no Java source) if you find that easier to work with than the embedded demo above. Caution: Be careful not to download these into the same place!

Frogger Overview

There are three important classes of objects involved in the Frogger game beyond the window controller class. There is the frog, there are the lanes of traffic (four of them), and there are the vehicles that go on the road. (There are also some graphical objects on the screen to represent the lane markings on the highway, but we will not discuss these in detail as they are easily constructed. (In fact, the code that draws the highway markings is provided in the starter package.)

The Frog

The frog will be displayed on the screen by creating a VisibleImage using a provided image file. The Frog class will need an instance variable to keep track of this VisibleImage.

The constructor for a Frog should create the VisibleImage and place it just below the lowest lane of the highway, approximately halfway from each end. Your constructor will require several parameters: the Image of the frog, the location where the frog should start, how wide a lane is (so the frog knows how far to hop), and the canvas. Remember, only WindowController objects can call getImage. Thus, you will need to get the image in the Frogger class and pass it to the Frog constructor.

The frog clearly needs to be able to hop in each of the four directions in response to presses of the arrow keys. We suggest writing a single method hopToward that takes an int parameter (i.e., one of the virtual key codes for an arrow key press). Depending on which key code is passed, the frog should move in the appropriate direction.

Unfortunately, the other thing that happens to a frog is that it gets splattered on the road. A vehicle will be responsible for determining whether it has killed a frog. To do so, it will need to ask the frog if any part of the Frog's body overlaps the VisibleImage displayed to represent the vehicle. To make this possible, your Frog class should include the definition of an overlaps method that takes a VisibleImage as a parameter and returns a boolean.

If a vehicle hits the frog, it kills the frog by calling a kill method on the frog. This causes an "OUCH!" message to appear at the bottom of the screen.

Finally, through the miracle of modern amphibian medicine, the squashed frog can come back to life. Add a method reincarnate which moves the frog back to its starting point. Of course, you should not reincarnate a frog unless it is dead. So, your "Play Again" button should be "greyed out" when the frog is alive, and active when it has died. See the setEnabled method to see how to enable and disable a JButton. The Frog class should include an isAlive accessor method that returns a boolean to enable the keyPressed method to determine whether the frog should hop or not (it should only do so when it's alive).

The Vehicles

The constructor for a vehicle will need parameters specifying where the vehicle should be located (two doubles or a single Location parameter), the Image used to display the vehicle on the screen, the velocity with which the vehicle should move, the distance the vehicle should travel before disappearing, and the DrawingCanvas. In order to check if the vehicle runs over the frog, you also need to pass the frog as a parameter to the Vehicle constructor.

Vehicle extends ActiveObject. Thus, you must define the method

public void run() { ... }

The while loop inside run should:

  1. Save the current time. (Get the current time by calling System.currentTimeMillis()).
  2. pause for (at least) 30 milliseconds.
  3. Determine how long it actually paused for (e.g., subtract the time saved earlier from the current time) and move the appropriate distance. (Remember your equation from physics: rate * time = distance.) You need to do this to ensure smooth motion of your vehicles. With so many active objects, the computer cannot ensure that the length of pauses will be very precise.
  4. Find out if the vehicle squished the frog and kill the frog with the kill method if it did.

You may assume that all vehicle velocities will be positive, if you wish. That is, your highway may be a one-way street. You are free to add the ability to handle vehicles with negative velocities so that you can have some lanes where traffic goes from left to right and others where traffic moves from right to left.

The Lane

The purpose of the Lane object is to continuously generate the vehicles that travel in a particular lane on your highway. As such, the lane does not actually correspond to any drawing on the screen. Instead, a Lane will be an ActiveObject that creates Vehicles. This is similar to the way in which the Cloud objects were active objects that created FallingSnow objects in the FallingSnow example from lecture. Refresh your memory by looking at the code for that example while preparing your Lane class.

The constructor for a Lane is quite simple. The lane was already drawn as part of the background in our window controller so we do not need to update the display. One thing we know is that all the traffic in a lane should drive at the same speed so that cars do not run into each other. The Frogger class should pick a random speed for each of the lanes and pass it in to the Lane constructor. We have found speeds in the range .033 to .133 pixels/millisecond to be good (though you may want to start with a slower set of speeds while you debug your program).

A lane's main responsibility is to periodically place a new car on the screen. It will do this inside the run method. In the while loop of the run method, the lane should generate a car, wait a while to allow a gap between cars, generate another car, and so on.

Recall from above that the Vehicle constructor requires a lot of parameters: its starting location, its image, etc. So far all the lane knows is how fast the cars drive. Where will Lane get this other information? The car should be located at one end of the lane initially and should drive until it reaches the other end. If the lane knew where it was located, it could pass this information on to the car. Its location is relative to the entire highway. Our window controller can provide this information to the lane when it constructs it so that the lane can pass the information on to the vehicle.

What about the image? Since the image can only be loaded from the window controller, so this information must also be passed down to the Vehicle by passing it to the Lane constructor. The Lane constructor remembers the image of the cars for its lane and passes this image to the Vehicle constructor. (Because of this limitation, it is simplest for all the cars in a lane to have the same image.)

Finally, the vehicle needs to know about the frog so it can tell if it hit the frog. Since our window controller created the frog, it can pass the frog to the Lane in its constructor. The lane can remember the frog so that it can tell the vehicles about the frog in the Vehicle constructor call.

After generating one vehicle, the lane should pause for some time. The pause should be at least long enough so that there will be a one car-length gap between pairs of vehicles. The pause should never be so long that it leaves more than about four car lengths between vehicles.

For simplicity, you may use a fixed value for the pause time when you first write your program, but eventually the pause time should be selected randomly. That is, the gaps between successive cars should not be the same, but should be distributed randomly with the constraint that there is at least one car length and no more than 4 car lengths between successive cars in the same lane. To do this, your code will have to use the speed with which vehicles travel and their lengths in pixels to compute the minimum and maximum amount of time you should pause between generating new cars.

The Image Files

There is an image file, named froggy.gif, for the frog. We provide 8 images of vehicles. They show 4 different types of vehicles. For each type of vehicle there is an image of that vehicle facing right and another facing left. The image files are included in the starter project and are named:

jeep_left.gif

oldcar_left.gif taxi_left.gif van_left.gif
jeep_right.gif oldcar_right.gif taxi_right.gif van_right.gif

It is fine if you only use a single image file so that all your vehicles look the same and move in the same direction. Using multiple pictures is a feature that we hope you add (it does make the display look better), but it is not required.

The frog is 83 pixels wide and 48 pixels tall. The widest vehicle is 139 pixels wide. The tallest vehicle is 66 pixels tall. This information should help you figure out how to place the vehicles and frog within the lanes. Remember to use constants effectively so that you would not need to change many values if we introduced a much taller vehicle, for example.

The "starter" project contains several files that you will fill in with your Java code. The file Frogger.java should be used to write the extension of the WindowController (which in this case is also an implementation of KeyListener) that will serve as your "main program". You will need to add import and implements directives to be able to process your "Play Again" button. The Frog.java, Lane.java and Vehicle.java hold the code for the appropriate classes. The Frogger.java file contains code that draws the highway background and markings for you and has the needed infrastructure in place to use the KeyListener to react to key presses. All the files contain skeletons of code which you will need to complete.

Suggested Procedure

There are many ways of proceeding with this lab. Here is one suggested ordering:

  1. Read the begin method in Frogger.java to understand how we have drawn the highway background for you.
  2. Write the Frog class except for the kill and reincarnate methods.
  3. Modify the Frogger class to create the frog on the screen, and write keyPressed to control the movements of the frog. Make sure that the frog hops around appropriately.
  4. Add the "Play Again" button, though you will not fully be able to test it until your frog can get hit by a car.
  5. Write the Vehicle class.
  6. Test the Vehicle class by having the begin method in the Frogger class put one car on the road. (You do not want the code here in the end, but for now it lets you test the Vehicle class before you have written the Lane class.) Move the frog into the road to see if it gets killed by the car. Add code to reincarnate the frog and test it.
  7. Note that the starter code in the Frogger class creates white FilledRect objects behind which the cars are hidden as they drive onto and off of the road. You want your Vehicle's VisibleImage to be on top of the road but below these "curtain" objects. So after you create it, you should call its sendToBack method to put it at the bottom of the stacking order (behind everything including the road) then call its sendForward method to move it in front of the road (which was the first graphical object on the canvas).
  8. Write the constructor of Lane. Move the code that creates a car from the Frogger class to the run method of the Lane class so that a lane generates a stream of cars on the lane. Make sure they do not bump into each other (they should not as they are all going the same speed). Make sure that the frog gets killed if hit by any of the cars (though our cars will be hit-and-run - they do not stop!).

Advanced Features

You may notice that the sample version of Frogger we have provided has more features than we have required. Vehicles move in both directions and several different images are used to represent vehicles. Feel free to incorporate these or any other extensions in your program. Only do so, however, after completing the construction of a program that meets the basic requirements.

You may earn as many as 10 bonus points for more advanced game features (additional lanes, keeping score, implementing a time limit, keeping track of wins, etc.)

Submitting Your Work

Before 11:59 PM, Wednesday, March 19, 2014, submit your lab for grading. There are three things you need to do to complete the submission: (i) upload a copy of your Java program (a .7z or .zip file containing your project directory) using Submission Box under assignment "Lab5", (ii) print a copy of your program and hand it to your instructor, and (iii) demonstrate the execution of your program for your instructor (2 business day grace period for demos).

Don't forget to check your programs for compliance with the Style Guide for CSC 252 Programs

Grading

This assignment is worth 60 points, which are distributed as follows:

> FeatureValueScore
Style, Design, and Efficiency
Appropriate comments 5
Good variable names 2
Appropriate variable declarations 3
Good use of constants 4
Appropriate formatting 1
Good overall design (parameters, expressions, etc.) 5
Correctness
At least one car moves across 4
Lanes generate cars 4
Cars are animated smoothly 3
Appropriate car speed and spacing in a lane 4
Cars disappear at the end of the lane 4
Frog movement with arrow keys 4
Frog gets killed when hit by any car 4
"OUCH" message only when frog is dead 3
Frog cannot move when dead 3
"Play Again" button disabled when frog alive 3
Frog can be reincarnated, but only when dead 4
Extra Credit (up to 10 total)

Total

60