Question: The Survivor I Objectives include: Call and write methods with parameters and return values. Use the DrawingPanel, Graphics, and Color classes. Use for loops and
The Survivor I
Objectives include:
Call and write methods with parameters and return values.
Use the DrawingPanel, Graphics, and Color classes.
Use for loops and if statements to control assignments.
Hand-in Requirements
All projects and laboratories will be submitted electronically through Blackboard. Zip up your entire lab directory to submit as the source. (Right click on the lab folder and follow the 7-Zip > Add to "project2.zip" or follow Send To > Compressed (zipped) Folder.) The lab folder should include the following:
SurvivorI.java
DrawingPanel.java
Introduction
In this project you will write a program for a simple game. Project 3 will be a more sophisticated version of this game.
In this game there will be a runner and a chaser. The computer will control the chaser, which should always move toward the runner. The user (you) will control the runner by keyboard input. The goal is to keep away from the chaser for a short amount of time.
This project will involve graphics and animation. Here an example of playing the game. The user is controlling the movement of the runner, the green square.
Main Method
Below is an initial, incomplete class for you to start with. It contains an incomplet main method.
import java.util.*; import java.awt.*; public class SurvivorI { public static void main(String[] args) { // Create DrawingPanel and draw a box in the panel. // The box is a square of this size. int boxSize = 760; DrawingPanel panel = new DrawingPanel(800, 800); Graphics g = panel.getGraphics(); g.fillRect(10, 10, 10, 780); g.fillRect(10, 10, 780, 10); g.fillRect(780, 10, 10, 780); g.fillRect(10, 780, 780, 10); // Initialize positions of runner and chaser. Point runner = new Point(200, 400); Point chaser = new Point(600, 400); // Variable for input from user to move runner. char keyInput = ' '; // The program should wait sleepTime ms between moves. int sleepTime = 100; // The runner should move moveSize (or zero) pixels each time step. // The chaser should move moveSize - 1 pixels each time step. int moveSize = 10; // Display players using Color.GREEN and Color.RED (or whatever colors you want). displayPlayers(panel, runner, chaser); // Wait one second before start of game. panel.sleep(1000); // NEED TO PUT SOME OF THESE STATEMENTS IN A FOR LOOP // Erase players from the panel using Color.WHITE. erasePlayers(panel, runner, chaser); // Get input from user if any. char newKeyInput = panel.getKeyChar(); if (newKeyInput == 'w' || newKeyInput == 'a' || newKeyInput == 's' || newKeyInput == 'd') { keyInput = newKeyInput; } // Move the players according to parameters. movePlayers(runner, chaser, keyInput, boxSize, moveSize); // Display players using Color.GREEN and Color.RED (or whatever colors you want). displayPlayers(panel, runner, chaser); // Game is over if the chaser catches up to the runner. if (collision(runner, chaser)) { System.out.println("YOU LOST!!!"); } // Wait sleepTime ms between moves. panel.sleep(sleepTime); // NEED AN IF STATEMENT TO DETERMINE WHEN TO PRINT THIS. System.out.println("YOU WON!!!"); } } Drawing Panel
The program uses a DrawingPanel to show the runner and chaser and the box that confines them.
Points
A Point is a convenient way to store a pair of values X and Y. For example, runner.getX() is initially equal to 200, and runner.getY() is initially equal to 400. The other method you will need to use is translate, for example, runner.translate(1,-1) would add 1 to the X value and subtract 1 from the Y value. The program also uses a Point to store the coordinates of the chaser.
Input from User
The runner should be controlled using the WASD keys on the keyboard. 'w' means go up. 'a' means go left. 's' means go down. 'd' means go right. The last 'w', 'a', 's', or 'd' character is stored in keyInput.
Animation
To control the rate of animation, the program needs to wait between moves (a time step). The variable sleepTime indicates how long to wait. Waiting 100 milliseconds each time step is not short enough for smooth animation, but should be good for debugging.
Move Size
The moveSize variable indicates how many pixels the runner moves each time step. The chaser needs to move slightly slower, otherwise the chaser can easily corner the runner.
The displayPlayers Method
The displayPlayers method should draw the runner and the chaser on the panel.
public static void displayPlayers(DrawingPanel panel, Point runner, Point chaser)
displayPlayers should use the getGraphics method of DrawingPanel and the setColor and fillRect methods of Graphics. The runner should be a 10x10 filled rectangle using Color.GREEN. The chaser should be a 10x10 filled rectangle using Color.RED. You can choose different colors if you like.
The erasePlayers Method
The erasePlayers method should erase the runner and the chaser on the panel. This is in preparation for drawing the runner and chaser in new positions.
public static void erasePlayers(DrawingPanel panel, Point runner, Point chaser)
displayPlayers should use the getGraphics method of DrawingPanel and the setColor and fillRect methods of Graphics. The runner should be erased with a 10x10 filled rectangle using Color.WHITE. The chaser should be erased with a 10x10 filled rectangle using Color.WHITE. It might be interesting to choose different light colors to show the paths of the runner and chaser.
The movePlayers Method
The movePlayers method is the most important and most involved method of the game.
public static void movePlayers(Point runner, Point chaser, char keyInput, int boxSize, int moveSize)
A move by the runner means using the translate to change either the x or y coordinate of the runner, but not both. A single move of moveSize pixels must be one of:
up: runner.translate(0, -moveSize)
down: runner.translate(0, moveSize)
left: runner.translate(-moveSize, 0)
right: runner.translate(moveSize, 0)
The runner's move is determined by keyInput as described above. The runner should not be allowed to go into the box boundary; in this case, the runner should not move at all. It is recommended that you define two additional methods: a method that determines whether a move is legal and another that performs the runner's move if it is legal.
A move by the chaser means using the translate method to change the x or y coordinate of the chaser, but not both. A single move of moveSize - 1 pixels must be up, down, left, or right. For example, chaser.translate(0, -(moveSize - 1)) would move the chaser up. The move of the chaser is determined by choosing the move (out of the four possible moves) that gets the chaser chosest to the runner. The chaser should not be allowed to go into the box boundary; in this case, the chaser should not move at all. It is recommended that you define two additional methods: one for determining the distance between two points and another for performing the move using the distance method and the legal method described above.
The distance between two Points point1 and point2 is:
the square root of ( ( point1.getX() - point2.getX()) 2 + ( point1.getY() - point2.getY()) 2 )
The collision Method
The collision method determines whether the chaser has caught up to the runner.
public static boolean collision(Point runner, Point chaser)
This method should return true if the two players touch or intersect each other, if runner.getX() is close enough to chaser.getX(), and if runner.getY() is close enough to chaser.getY().
The Loop
The main method need a for loop that runs the game for 300 time steps. However, if a collision occurs, use a break statement to end the loop early.
User Input
The main method currently has fixed values for boxSize, moveSize, and sleepTime. The user should be asked for these values using a single prompt.
Enter the box size, move size, and sleep time: 760 10 100
If the user enters a 0 or negative number, use the default value for that variable. Other magic numbers in the main method might need to replaced with appropriate expressions to take the user's inputs into account.
Suggestions for Proceeding
Add a statement at beginning printing (with appropriate substitutions):
Project 2 written by YOUR NAME
Initially define stubs for the methods you need to code. Compiling and running should show a window with a box that has a 10 pixel boundary
Define the displayPlayers and erasePlayers methods. erasePlayers should be about the same code as displayPlayers expect that erasePlayers uses Color.WHITE. Compiling and running should show a small green box and small red box at the specified positions.
Write code for the main method and movePlayers method so that the user can control the motion of the runner. Leave the code for the chaser for later.
Add this code to movePlayers so the runner moves to the left.
runner.translate(-moveSize, 0)
This should show the small green box making one small hop to the left. You may need to modify erasePlayers if the green box is not erased from the original position.
Modify the main method with a for loop so the runner continues to the move to the left and out of the box. Keeping the runner in the box is addressed later.
Modify and test movePlayers to use keyInput to move the runner in the appropriate direction. This will be an if statement to call runner.translate with the appropriate parameters.
Modify and test movePlayers to keep the runner in the box. You should create a boolean method that will test whether the runner is in the box. If the runner is not in the box, the change should be undone, so that the runner does not move.
At this point, the user should have full control over the movement of the runner in the box.
Write the code for the collision method so it returns true if the runner collides with the chaser. This method should also return true if the runner "sideswipes" the chaser. Add a break statement to the if block so that the loop ends. Add a boolean variable and an if statement to ensure that YOU WON!!! is not printed out after YOU LOST!!!.
Write code in the movePlayers method to control the movement of the chaser. It will be better to make this a separate method called by movePlayers.
Write and test a method that calculates the distance between the runner and the chaser.
For each legal move by the chaser, determine the distance between the runner and the chaser if the chaser makes that move.
Select and execute the move that minimizes the distance between the runner and the chaser.
At this point, the game should fully functional for the fixed values of boxSize, moveSize and sleepTime.
Modify the main method so that the user can enter the values of boxSize, moveSize and sleepTime on a single line. If a zero or negative number is entered, set the corresponding variable to its default value, that is, the ones shown in the main method above. Obviously, the size of the box should depend on boxSize, but the size of the panel and the initial positions of the runner and chaser should also depend on boxSize.
Rubric for Project 2
Your program should compile without any errors. A program with more than one or two compile errors will likely get a zero for the whole assignment.
The following criteria will also be used to determine the grade for Project 2.
General [2 points]
Your submission was a Zip file named project2.zip containing at least the two files called SurvivorI.java and DrawingPanel.java.
Your program contains a comment that describes what the program does and contains a descriptive comment for each method.
Your program is indented properly.
Your program displays your name appropriately.
Movement of the runner [8 points]
[4 points] The user can control the runner using the WASD keys.
[2 points] The runner cannot move into the box boundary or move outside the box. This should remain true for any box size and move size values entered by the user.
[2 points] The speed of the runner is determined by the move size and sleep time parameters entered by the user.
Movement of the chaser [6 points]
[2 points] The chaser always moves toward the runner.
[2 points] The speed of the chaser is determined by the move size and sleep time parameters entered by the user.
[2 points] The chaser is slightly slower than the runner.
Size of the box [2 points]
[2 points] The size of the panel and the box and the initial positions of the runner and chaser are determined by the box size entered by the user.
End of the game [2 points]
[1 point] If there is no collision between the runner and the chaser, the game ends after 300 time steps with a YOU WIN!!! message.
[1 point] If there is a collision, the game immediately ends and results in a YOU LOSE!!! message.
DrawingPanel.java-code
/* Stuart Reges and Marty Stepp February 24, 2007 Changes by Tom Bylander in 2010 (no anti-alias, repaint on sleep) Changes by Tom Bylander in 2012 (track mouse clicks and movement) Changes by Tom Bylander in 2013 (fix bug in tracking mouse clicks) Changes by S. Robbins in 2014 (getters for width and height) Changes by S. Robbins in 2014 (addKeyListener added) Changes by S. Robbins in 2014 (catch exception on default close so that it works in an applet) Changes by S. Robbins in 2015 (buffer key events) Changes by S. Robbins in 2015 (show mouse status by default is off) The DrawingPanel class provides a simple interface for drawing persistent images using a Graphics object. An internal BufferedImage object is used to keep track of what has been drawn. A client of the class simply constructs a DrawingPanel of a particular size and then draws on it with the Graphics object, setting the background color if they so choose. To ensure that the image is always displayed, a timer calls repaint at regular intervals. */ import java.awt.*; import java.awt.event.*; import java.awt.image.*; import javax.swing.*; import javax.swing.event.*; import java.util.ArrayList; public class DrawingPanel implements ActionListener { private static final String versionMessage = "Drawing Panel version 1.1, January 25, 2015"; private static final int DELAY = 100; // delay between repaints in millis private static final boolean PRETTY = false; // true to anti-alias private static boolean showStatus = false; private static final int MAX_KEY_BUF_SIZE = 10; private int width, height; // dimensions of window frame private JFrame frame; // overall window frame private JPanel panel; // overall drawing surface private BufferedImage image; // remembers drawing commands private Graphics2D g2; // graphics context for painting private JLabel statusBar; // status bar showing mouse position private volatile MouseEvent click; // stores the last mouse click private volatile boolean pressed; // true if the mouse is pressed private volatile MouseEvent move; // stores the position of the mouse private ArrayList keys; // construct a drawing panel of given width and height enclosed in a window public DrawingPanel(int width, int height) { this.width = width; this.height = height; keys = new ArrayList(); image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); statusBar = new JLabel(" "); statusBar.setBorder(BorderFactory.createLineBorder(Color.BLACK)); statusBar.setText(versionMessage); panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); panel.setBackground(Color.WHITE); panel.setPreferredSize(new Dimension(width, height)); panel.add(new JLabel(new ImageIcon(image))); click = null; move = null; pressed = false; // listen to mouse movement MouseInputAdapter listener = new MouseInputAdapter() { public void mouseMoved(MouseEvent e) { pressed = false; move = e; if (showStatus) statusBar.setText("moved (" + e.getX() + ", " + e.getY() + ")"); } public void mousePressed(MouseEvent e) { pressed = true; move = e; if (showStatus) statusBar.setText("pressed (" + e.getX() + ", " + e.getY() + ")"); } public void mouseDragged(MouseEvent e) { pressed = true; move = e; if (showStatus) statusBar.setText("dragged (" + e.getX() + ", " + e.getY() + ")"); } public void mouseReleased(MouseEvent e) { click = e; pressed = false; if (showStatus) statusBar.setText("released (" + e.getX() + ", " + e.getY() + ")"); } public void mouseEntered(MouseEvent e) { // System.out.println("mouse entered"); panel.requestFocus(); } }; panel.addMouseListener(listener); panel.addMouseMotionListener(listener); new DrawingPanelKeyListener(); g2 = (Graphics2D)image.getGraphics(); g2.setColor(Color.BLACK); if (PRETTY) { g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke(1.1f)); } frame = new JFrame("Drawing Panel"); frame.setResizable(false); try { frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // so that this works in an applet } catch (Exception e) {} frame.getContentPane().add(panel); frame.getContentPane().add(statusBar, "South"); frame.pack(); frame.setVisible(true); toFront(); frame.requestFocus(); // repaint timer so that the screen will update new Timer(DELAY, this).start(); } public void showMouseStatus(boolean f) { showStatus = f; } public void addKeyListener(KeyListener listener) { panel.addKeyListener(listener); panel.requestFocus(); } // used for an internal timer that keeps repainting public void actionPerformed(ActionEvent e) { panel.repaint(); } // obtain the Graphics object to draw on the panel public Graphics2D getGraphics() { return g2; } // set the background color of the drawing panel public void setBackground(Color c) { panel.setBackground(c); } // show or hide the drawing panel on the screen public void setVisible(boolean visible) { frame.setVisible(visible); } // makes the program pause for the given amount of time, // allowing for animation public void sleep(int millis) { panel.repaint(); try { Thread.sleep(millis); } catch (InterruptedException e) {} } // close the drawing panel public void close() { frame.dispose(); } // makes drawing panel become the frontmost window on the screen public void toFront() { frame.toFront(); } // return panel width public int getWidth() { return width; } // return panel height public int getHeight() { return height; } // return the X position of the mouse or -1 public int getMouseX() { if (move == null) { return -1; } else { return move.getX(); } } // return the Y position of the mouse or -1 public int getMouseY() { if (move == null) { return -1; } else { return move.getY(); } } // return the X position of the last click or -1 public int getClickX() { if (click == null) { return -1; } else { return click.getX(); } } // return the Y position of the last click or -1 public int getClickY() { if (click == null) { return -1; } else { return click.getY(); } } // return true if a mouse button is pressed public boolean mousePressed() { return pressed; } public synchronized int getKeyCode() { if (keys.size() == 0) return 0; return keys.remove(0).keyCode; } public synchronized char getKeyChar() { if (keys.size() == 0) return 0; return keys.remove(0).keyChar; } public synchronized int getKeysSize() { return keys.size(); } private synchronized void insertKeyData(char c, int code) { keys.add(new KeyInfo(c,code)); if (keys.size() > MAX_KEY_BUF_SIZE) { keys.remove(0); // System.out.println("Dropped key"); } } private class KeyInfo { public int keyCode; public char keyChar; public KeyInfo(char keyChar, int keyCode) { this.keyCode = keyCode; this.keyChar = keyChar; } } private class DrawingPanelKeyListener implements KeyListener { int repeatCount = 0; public DrawingPanelKeyListener() { panel.addKeyListener(this); panel.requestFocus(); } public void keyPressed(KeyEvent event) { // System.out.println("key pressed"); repeatCount++; if ((repeatCount == 1) || (getKeysSize() < 2)) insertKeyData(event.getKeyChar(),event.getKeyCode()); } public void keyTyped(KeyEvent event) { } public void keyReleased(KeyEvent event) { repeatCount = 0; } } } Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
