Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Survivor II Objectives include: Call and write methods with parameters and retur

ID: 3716676 • Letter: S

Question

Survivor II

Objectives include:

Call and write methods with parameters and return values.

Use while loops.

Use arrays.

this game will have a runner and a chaser. The new element in this game is that the game will include zombies. A zombie moves in a random walk (see Lab 7). The object of the game is for the runner to eliminate all the zombies (by colliding with them) and to avoid being caught by the chaser. The runner wins when all the zombies are eliminated. The runner loses if the chaser catches the runner before all the zombies have been eliminated.

Note that you also need DrawingPanel.java for this project. Also note that the game does not start until the user has entered a move.

The goal of Lab 9 is to implement the game with a user-specifed number of zombies. Lab 9 does not require a chaser. Lab 9 also does not require user-specified values for box size, move size, and sleep time. You may implement these elements in Lab 9 if you wish, but credit for them will be given in your Project 3 score.

Lab 9 should prompt the user for the number of zombies as follows:

Suppose this value is stored in numZombies. Then your program will need to create an array of Points:

Each element of the array needs to initialized to a Point object. If i is an int that is greater or equal to 0, and is less than numZombies, then the following initializes the array at index i to a Point with coordinates X=600 and Y=400:

This needs to be done for every value of i from 0 to numZombies-1.

Rather than putting each zombie at the same location, the coordinates should be random. The X and Y coordinates for each zombie should be random values between 30 and 770.

In the starter code, the variable zombie appears in the while loop and in methods. Because there are numZombies zombies, each of these appearances need to be replaced with a loop over the zombies array:

In Lab 9, a collision between the runner and any zombie should result in setting gameOver to true.

Rubric

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 Lab 9.

General [2 points]

Your submission was a Zip file named lab9.zip containing at least the two files called SurvivorII.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.

Creation of zombies [6 points]

[2 points] The user can enter the desired number of zombies.

[2 points] The correct number of zombies appear in the game. The color of the zombies is different from the runner.

[2 points] The zombies appear in locations that are randomly generated.

Movement of the zombies [6 points]

[4 points] The zombies move in a random walk.

[2 points] The zombies do not move out of the box.

Movement of runner [4 points]

[2 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.

End of the game [2 points]

[2 points] The game ends when the runner collides with any zombie.

After that code is finished:

Added after lab 9

This will finish the game. As in Project 2, the game needs a chaser and user-specified values for box size, move size, and sleep time. Also, all the zombies must be eliminated for the user to win the game.

Chaser

As in Project 2, the chaser should be a Point object starting t a fixed location.

The chaser should be displayed using a different color from the runner and zombies.

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.

User-Specified Values

The starter code currently has fixed values for the size of the box, the size of each move, and amount of sleep time each iteration. The user should be asked for these values as well as the number of zombies using a single prompt.

If the user enters a 0 or negative number, use the default value for that variable. Other magic numbers in the starter code might need to replaced with appropriate expressions to take the user's inputs into account. For the same reason, methods in the starter code might need more parameters.

There needs to be a chaser that always follows the runner. See the Project 2 description for how the chaser should work.

Eliminating Zombies

For each zombie, the program needs to remember whether it is eliminated or not. This can be done using a boolean array.

Java initializes each element of this array to false. When zombies[i] has been eliminated, then element i of the eliminated array needs to be set to true.

If zombies[i] has been eliminated, then that zombie should not be displayed on the window. This can be controlled with an if statement.

End of the Game

The game should end if the chaser collides with the runner. In this case, the program should print YOU LOSE!

The game should also end if the runner eliminates all the zombies. This requires checking that every value in the eliminated array has been set to true. If any value in the eliminated array is false (and if the chaser does not collide with the runner), then the game should continue. If the runner eliminates all the zombies, then the program should print YOU WIN!.

The program satisfies the rubric for Lab 9 [10 points]

See the Lab 9 rubric above.

User-Specified Values [4 points]

[2 points] The speed of the runner and the chaser is determined by the move size and sleep time parameters entered by the user.

[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. Also, all the zombies are in the box.

Movement of the chaser [2 points]

[2 points] The chaser always moves toward the runner. The chaser is a different color from the runner and zombies. The chaser is slightly slower than the runner. If there is a collision between the runner and the chaser, the game immediately ends and results in a YOU LOSE!!! message.

Eliminating zombies [4 points]

[2 points] When the runner collides with a zombie, the zombie is eliminated from the game.

[2 points]When the runner has eliminated all the zombies, the game immediately ends with a YOU WIN!!! message.

Explanation / Answer

SourceCode:

import java.util.*;
import java.awt.*;

/**
* [Lab 9]
* @author <YOUR NAME HERE>
*
*/
public class SurvivorII {
   public static final int PLAYER_SIZE = 10;

   public static void main(String[] args) {
      
       //Getting number of zombies from the user
       Scanner scanner = new Scanner(System.in);
       System.out.print("Enter the number of zombies:");
       int numZombies = scanner.nextInt();
       scanner.close();
      

       // Create DrawingPanel and draw a box in the panel.
       int boxSize = 760;
       DrawingPanel panel = new DrawingPanel(boxSize + 40, boxSize + 40);
       Graphics g = panel.getGraphics();
       g.fillRect(10, 10, 10, boxSize + 20);
       g.fillRect(10, 10, boxSize + 20, 10);
       g.fillRect(boxSize + 20, 10, 10, boxSize + 20);
       g.fillRect(10, boxSize + 20, boxSize + 20, 10);

       // Initialize positions of runner, chasers, and zombies.
       Random random = new Random();
       Point runner = new Point(200, 400);
       Point chaser = new Point(300, 300);
      
       //Array of zombies initialized.
       Point[] zombies = new Point[numZombies];
      
       for (int i = 0; i < numZombies; i++) {
            //do..while loop makes sure that the runner and new zombie do not have the same co-ordinate.
            do {
               zombies[i] = new Point(random.nextInt(730) + 30, random.nextInt(730) + 30);
               displayPlayers(panel, runner, chaser, zombies[i]);
           } while (legal(zombies[i], 0, 0, boxSize) && collision(runner, zombies[i]));
       }
      

       // Need boolean to keep track of whether zombie is caught
       boolean eliminated = false;

       // 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;

       // Wait one second before start of game.
       panel.sleep(1000);

       // Wait until a character is entered
       keyInput = panel.getKeyChar();
       while (keyInput == 0) {
           keyInput = panel.getKeyChar();
       }

       // use a boolean to indicate when the game is lost
       boolean lost = false;
       boolean gameOver = false;

       while (!gameOver) {
           // Get input from user if any.
           char newKeyInput = panel.getKeyChar();
           if (newKeyInput == 'w' || newKeyInput == 'a' || newKeyInput == 's' || newKeyInput == 'd') {
               keyInput = newKeyInput;
           }
           boolean isRunnerMoved = false;
           for(Point zombie : zombies) {
               // Erase players from the panel using Color.WHITE.
               erasePlayers(panel, runner, chaser, zombie, isRunnerMoved);
  
               // Move the players according to parameters.
               movePlayers(runner, chaser, zombie, eliminated, keyInput, boxSize, moveSize, isRunnerMoved);
  
               // Display players using Color.GREEN and Color.RED (or whatever colors you
               // want).
               displayPlayers(panel, runner, chaser, zombie);
              
               if (collision(runner, zombie)) {
                   eliminated = true;
                   gameOver = true;
               }
               isRunnerMoved = true;
           }
           // Game is over if the runner collides with chaser or zombie.
          
           if (collision(runner, chaser)) {
               System.out.println("YOU LOST!!!");
               lost = true;
               break;
           }

           if (lost) {
               break;
           }
          
           // Wait sleepTime ms between moves.
           panel.sleep(sleepTime);
       }

       if (!lost) {
           System.out.println("YOU WON!!!");
       }
   }

   /**
   * Displays each {@link Point} argument passed on the drawing panel.
   *
   * @param panel
   * @param runner
   * @param chaser
   * @param zombie
   */
   public static void displayPlayers(DrawingPanel panel, Point runner, Point chaser, Point zombie) {
       Graphics g = panel.getGraphics();
       g.setColor(Color.GREEN);
       g.fillRect((int) runner.getX() - PLAYER_SIZE / 2, (int) runner.getY() - PLAYER_SIZE / 2, PLAYER_SIZE,
               PLAYER_SIZE);

       g.setColor(Color.BLUE);
       g.fillRect((int) zombie.getX() - PLAYER_SIZE / 2, (int) zombie.getY() - PLAYER_SIZE / 2, PLAYER_SIZE,
               PLAYER_SIZE);

   }
  
   /**
   * Erases each of the {@link Point} arguments so as to not create a path of all the Points.
   *
   * @param panel
   * @param runner
   * @param chaser
   * @param zombie
   * @param isRunnerMoved
   */
   public static void erasePlayers(DrawingPanel panel, Point runner, Point chaser, Point zombie, boolean isRunnerMoved) {
       Graphics g = panel.getGraphics();
       g.setColor(Color.WHITE);

       if(!isRunnerMoved){
           // erase runner
           g.fillRect((int) runner.getX() - PLAYER_SIZE / 2, (int) runner.getY() - PLAYER_SIZE / 2, PLAYER_SIZE,
                   PLAYER_SIZE);
       }
       // erase zombie
       g.fillRect((int) zombie.getX() - PLAYER_SIZE / 2, (int) zombie.getY() - PLAYER_SIZE / 2, PLAYER_SIZE,
               PLAYER_SIZE);
   }

   /**
   * Moves the zombies that are not eliminated and moves the runner to a distance
   * corresponding to the moveSize defined earlier.
   *
   * @param runner
   * @param chaser
   * @param zombie
   * @param eliminated
   * @param keyInput
   * @param boxSize
   * @param moveSize
   * @param isRunnerMoved
   */
   public static void movePlayers(Point runner, Point chaser, Point zombie, boolean eliminated, char keyInput,
           int boxSize, int moveSize, boolean isRunnerMoved) {
       moveZombie(zombie, eliminated, boxSize, moveSize);

       if(!isRunnerMoved) {
           processKeyInput(runner, keyInput, boxSize, moveSize);
       }

   }
  
  
   /**
   * Determines whether the move that is to be made is legal or does it
   * takes the point out of the boundary of the Drawing Panel
   *
   * @param p
   * @param dx
   * @param dy
   * @param boxSize
   * @return
   */
   public static boolean legal(Point p, int dx, int dy, int boxSize) {
       return p.getX() + dx + PLAYER_SIZE / 2 < 780 && p.getX() + dx - PLAYER_SIZE / 2 > 20
               && p.getY() + dy + PLAYER_SIZE / 2 < 780 && p.getY() + dy - PLAYER_SIZE / 2 > 20;
   }

   /**
   * Returns distance between two points.
   *
   * @param p1
   * @param p2
   * @return distance between p1 and p2.
   */
   public static double distance(Point p1, Point p2) {
       return Math.sqrt(
               (p1.getX() - p2.getX()) * (p1.getX() - p2.getX()) + (p1.getY() - p2.getY()) * (p1.getY() - p2.getY()));
   }

   /**
   * Returns the distance between two points, taking into consideration the given offset.
   *
   * @param p1
   * @param p2
   * @param dx
   * @param dy
   * @return distance between p1 and p2.
   */
   public static double distance(Point p1, Point p2, int dx, int dy) {
       return Math.sqrt((p1.getX() - p2.getX() - dx) * (p1.getX() - p2.getX() - dx)
               + (p1.getY() - p2.getY() - dy) * (p1.getY() - p2.getY() - dy));
   }

   /**
   * Moves the zombie
   *
   * @param zombie
   * @param eliminated
   * @param boxSize
   * @param moveSize
   */
   public static void moveZombie(Point zombie, boolean eliminated, int boxSize, int moveSize) {
       int[] dxs = { 0, 0, moveSize, -moveSize };
       int[] dys = { moveSize, -moveSize, 0, 0 };
       Random random = new Random();

       if (!eliminated) {
           int di = random.nextInt(4);
           int dx = dxs[di];
           int dy = dys[di];
           if (legal(zombie, dx, dy, boxSize)) {
               zombie.translate(dx, dy);
           }
       }
   }

   /**
   * Moves the chaser.
   *
   * @param runner
   * @param chaser
   * @param zombie
   * @param eliminated
   * @param boxSize
   * @param moveSize
   */
   public static void moveChaser(Point runner, Point chaser, Point zombie, boolean eliminated, int boxSize,
           int moveSize) {

   }

   /**
   * Moves the runner.
   *
   * @param runner
   * @param keyInput
   * @param boxSize
   * @param moveSize
   */
   public static void processKeyInput(Point runner, char keyInput, int boxSize, int moveSize) {
       int[] dxs = { 0, 0, moveSize, -moveSize };
       int[] dys = { moveSize, -moveSize, 0, 0 };
       char[] keys = { 's', 'w', 'd', 'a' };

       for (int i = 0; i < dxs.length; i++) {
           int dx = dxs[i];
           int dy = dys[i];
           char key = keys[i];
           if (keyInput == key && legal(runner, dx, dy, boxSize)) {
               runner.translate(dx, dy);
           }
       }

   }

   /**
   * Detect collision between two points(whether their coordinates overlap or not).
   *
   * @param runner
   * @param chaser
   * @return
   */
   public static boolean collision(Point runner, Point chaser) {
       return Math.max(Math.abs(runner.getX() - chaser.getX()),
               Math.abs(runner.getY() - chaser.getY())) <= PLAYER_SIZE;
   }

}


//---------------------------------------------------------------------------------------------------------------------------------------------------------------------

//[DrawingPanel .java] {no changes}

/*
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<KeyInfo> 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<KeyInfo>();
   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;
   }

}

}