For this lab, we would like you to implement a game called Boxball. This is a simple game in which the player attempts to drop a ball into a box. Boxball has 3 levels of difficulty. With each increasing level, the box gets smaller, and the player is required to drop the ball from a greater height.
When the game begins, the playing area is displayed along with three buttons that allow the player to select a level of difficulty. Selecting a level of difficulty affects the size of the box and the position of the line indicating the minimum height from which the ball must be dropped. The player drops a ball by clicking the mouse in the region of the playing area above the minimum height line. If the ball falls completely within the box, the box is moved to a random location. Otherwise, it remains where it is. In either case, the player may go again, dropping another ball.
A working applet version follows.
The applet dimensions are about 500 by 600. Since the FrameWindowController frames initially have canvas dimensions of a bit less than 400 by 400, you will need to change the frame size. To do so, use the following two commands:
getAppletFrame().setSize(width, height); getAppletFrame().validate();
where width and height are, in this case, 500 and 600. (The actual canvas width and height are a bit less due to the frame border and title bar, but this difference is not critical in this case.)
For this lab you will need to define three classes: a Box class, a Ball class, and a Boxball class that extends FrameWindowController. These will allow you to create the major components of the game, i.e., the box, the balls, and the playing area, respectively. You are expected to come to lab with a design for each class that corresponds to the functionality described in parts 1 through 4 below. To give you a better sense of what is expected for a design, we provide you with a sample magnet game design for your earlier lab..
The Boxball class should be responsible for drawing the playing area when the program starts. It should also handle the player's mouse clicks. If the player clicks on an easy, medium, or hard button, the starting line should move to the appropriate height. If the player clicks within the playing area above the starting line, a new ball should be created and dropped from that height.
The Box class will allow you to create and manipulate the box at the bottom of the playing area. A box is responsible for knowing how to move to a new random location when the ball lands in the box. It also is responsible for changing size if the player changes the difficulty level.
The Ball class should allow you to create a ball that falls at a constant rate. When the ball reaches the bottom of the playing area, the player should be told whether the ball landed in the box. The ball should then disappear. If the ball lands in the box, the box should move to a new location.
A starter.jar file is provided with code skeletons for these classes. After downloading the file to your directory for this assignment, use the command jar -xf starter.jar to eXtract the files from the jar File.
Test your design "on paper" before trying to program it.
A common way to test designs is called the Use Case Scenario. A use case is a patterns of usage the program could encounter. A use case scenario is a list, in order, of each significant action that is taken by the program in handling a use case. Just what is considered significant depends on context, but generally includes all calls to methods in the program, including indications of the objects of the call, and any arguments that seem important to the scenario. Other program actions, such as calls to library methods and variable assignments may be included if they are especially important. In a complex program there may be far more possible use cases than it is practical to construct scenarios for, but a representative selection intended to be sufficient to reveal design problems is chosen (this is an art that you get better at with practice).
For this lab, the following use cases are suggested:
Pay special attention to how object references are passed around to be sure that every the data will be available for every operation that needs to be performed.
A sample use case scenario is appended to the magnet game design. (A reasonable test of this design would require several more scenarios.) Because the most common problem in simple designs of this sort is failure for provide appropriate fields and arguments so the necessary data for each operation is available, that is the focus of the scenario. A similar focus is suggested for the current assignment. In the design of other programs, scenarios might need to be much more detailed or have a different focus to catch other sorts of design errors.
Do not be overly concerned with the exact format of your design and scenarios. Just make them detailed enough to make it likely that you will catch design errors before you invest time in writing code. Skimping on design time leads to wasted time later when you discover that you have to scrap existing code before you have completed it and have a hard time with debugging.
If you have time after completing and testing your design, you may begin coding in lab.
Complete the program, developing and testing it in stages indicated by the following parts of the assignment.
Start by setting the layout of your playing area, using the familiar ObjectDraw shapes. The code for building the playing area should go in Boxball.java.
Once you have set up the playing area, add the Easy, Medium, and Hard buttons to your layout. The buttons are just rectangles that will respond to mouse clicks. When you click on a button, the location of the starting line should change. After you've displayed the three buttons, add code to the onMouseClick method that will adjust the level of the starting line, depending on the button clicked. If the player selects the "Easy" buttton, the line should be relatively low. If the player selects the "Hard" button, the line should be quite high.
Next, you should add a box to your layout. To do this, you will need to write the Box class that will allow you to create and display the box object at the bottom of the playing area.
A box is really just a rectangle, but there is some important information you will need to pass to the Box constructor in order to construct it properly. First, you need to tell the box where it should appear on the display. Remember that its horizontal position will change over time, but its vertical position will always be the same. What are the extreme left and right values for its horizontal position?
In order for the rectangle to be drawn, you will also need to tell the box what canvas it should be drawn on. This information will be passed on to the constructor for the rectangle.
The box needs one more piece of information for it to be drawn correctly. It needs to know how wide it should be. Of course, even in its hard setting, the box should still be a little wider than the ball. Since the Boxball class will create both the ball and the box, it knows their relative sizes. It must therefore tell the box how big it should be when the box is created.
Once you have written the constructor for the Box class, you should go back to the begin method of the Boxball controller class and create a new Box.
The default setting for the game is "Easy". If the player clicks on the "Medium" or "Hard" button, the box should get smaller (or much smaller). The box needs a method, setSize, to allow its size to change when the player clicks on Easy, Medium, or Hard. Think carefully about what parameters you need to pass to setSize to accomplish this command.
After writing the setSize method, test it by modifying the onMouseClick method in the Boxball controller. Clicking on one of the level selection buttons should now not only raise or lower the bar, but it should also adjust the size of the box.
The Ball class is different from other classes with which we have been working. Objects of this class will be active.
The player will create a ball by clicking with the mouse in the playing area above the starting line. When the click is detected, a new Ball should be constructed. The constructor for the Ball class should draw a ball centered on the given mouse point. It should also start it moving down the screen. To do so, it will call a start method, which will cause the code in run to execute.
You will notice that the skeleton of the Ball constructor we have provided for you contains the call to start. You will need to add more statements to the constructor, but you should be sure that the start method call is the last statement in your constructor.
You need to think carefully about what information a ball needs to know to construct itself properly. Recall that Boxball knows how big the ball should be (so that the ball and the box can be sized appropriately). Boxball also knows where the mouse was clicked. This should be the starting location for the ball. You need to pass this information to the Ball constructor so that it can draw itself and fall.
To get the ball to fall, you will need to do some work. This will be done in the run method. We have provided a skeletal run method for you.
We will use a bit of video game magic to make the ball appear to fall. The ball will appear to move smoothly down the screen, but in fact, it will be implemented by a series of movements. Each movement should move the ball a short distance, wait a short time, and then move again. The run method contains a while loop to allow this. On each iteration of the while loop, the ball should move a small distance, say 10 units. Then it should wait a short time. The pause method call that we provided tells the ball to wait 50 milliseconds. There are 1000 milliseconds in a second. Moving short distances that rapidly will appear to be continuous movement to the human eye. This is the same technique that television and movies use to provide continuous motion. To complete the while statement, you need to provide the condition that determines when to exit the while loop. Specifically, the ball should stop moving when it reaches the bottom of the playing area.
Once you have written the Ball constructor and the run method, you should test them. Return to your Boxball controller class, and add code to the onMouseClick method that will construct a ball if the player clicks above the starting line in the playing area. At this point, do not worry about whether the ball falls in the box. Just check that it is drawn at the right starting location and that it makes its way to the bottom of the playing area.
Now you are ready to determine whether the ball fell in the box. As the ball reaches the bottom of the playing area, it should compare its location to the box's location. Of course, the ball will need to find out the box's location. The Box class needs to provide methods getLeft and getRight that give the positions of the edges of the box. To call those methods, the Ball class must know about the box. Go back and modify your Ball constructor to pass in the Box as an additional parameter.
If the ball lands in the box, you should display the message "You got it in!". If the ball misses, you should display "Try again!". Since the Boxball controller is responsible for the layout of the game, it should construct a Text object that displays a greeting message. The Text object should be passed to the Ball constructor as a parameter so that the ball can change the message appropriately when it hits or misses the box.
Test the additions that take care of checking whether the ball fell in the box.
Finally, use the random number generator (i.e., RandomIntGenerator) to pick a new location for the box when the player gets the ball in the box. The box should be responsible for picking the new location and moving itself. Therefore, you will need to add a method to the Box class called moveBox.
Make the game more challenging by having the box move back and forth. Both the box and the ball then need to be active objects.
This lab was adapted with permission from Williams College Computer Science 134 Lab #4