Download Tetris Game Project - - - - GridWorld Case Study

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
- - Tetris Game Project - - - GridWorld Case Study - - Dave Ruth - - AP Computer Science - - - Niles North High School - - -
This is a project that will allow students to clone the classic Tetris Game. Students should have
successfully completed at least parts 1, 2 and 3 of the GridWorld Case Study Manual and the
respective question sets. They should also be familiar with using ArrayList<E>. A TetrisGame class
with a complete main method and a TetrisBlock class are provided and will compile and execute
(after the TetrisBug class is written … see Question 0). This will allow students to begin with a
working GUI simulation that is keyboard controlled.
Each student will have to write a small TetrisBug class which will extend Bug and will write code in
two methods in class TetrisGame. There are seven unique four-block Tetris pieces and each has a
different configuration and require their own implementations for controlling movement and rotation
inside the Grid. Each student will pick one piece and write a class that extends class TetrisBlock
(code provided) and implements the movement and rotation behavior for that particular piece (… see
Question 2). This will allow students to experience a collaborative software development effort.
Although some of the pieces require less code than others (the square for example, needs no rotation
implementation), all the programmers will gain a similar experience writing their specific TetrisBlock. .
It is recommended that students work on the questions in the order they appear.
Question 0. class TetrisBug
• Create a class called TetrisBug that extends class Bug in a new source file. It should have the same
imports as TetrisGame
• Next, write a constructor that takes a Color parameter and calls the superclass constructor with that
color and set the direction of the TetrisBug to 180 (i.e. South or down).
• Now, override the move method. A TetrisBug should move just like a Bug but without creating a
Flower behind it as it moves. (You may look at the code in Bug.java)
• Finally, override the act method and leave it empty. A TetrisBug does not act on its own… its host
TetrisBlock asks it to move when necessary. Run TetrisGame.
Question 1. complete TetrisBlock methods
• Write the moveLeft method in class TetrisBlock as an exercise. Use the code from the
moveRight method and modify it so the TetrisBlock moves left on a left arrow key press.
• Complete the rotate method in class TetrisBlock as an exercise. Currently, the TetrisBlock will
only rotate if it is in rotationPos == 0. Complete the if-statement so the TetrisBlock will rotate
back if rotationPos == 1.
Question 2. removeCompleteRows method of class TetrisGame
•
•
This void method takes no parameters. Write a loop to check rows 1 to 18 (skip row 0) in that order. If a
row is full, remove each Actor in that row from the Grid, and increment score by one. Also, write
nested for loops to call the act method on each TetrisBug in the Grid increment above the just
deleted row. CAREFUL! The order in which you loop through the cells is critical. Some TetrisBug
objects must act before others. Everyone should complete and test this method.
You may write and use the following helper method:
//returns true if the ith row contains no empty cells, false otherwise
//note: loop through columns 1 through 10 of Grid
private static boolean isFullRow(int i)
Question 3. create a specific TetrisBlock
•
Choose one of the 7 TetrisBlocks to create:
TetrisBlockO, TetrisBlockI, TetrisBlockT,
TetrisBlockL, TetrisBlock_L, TetrisBlockZ, TetrisBlock_Z
•
•
•
Note: some of the above shapes will require more coding than others.
For example, TetrisBlockO has only one rotationPos, since its square shape does not change
when it rotates so its rotate method is essentially empty, or that TetrisBlockL requires more
challenging cell checking when moving and rotating.
This class you choose will extend class TetrisBlock and must override the default constructor as
well as act(),moveDown(),canMoveDown(),moveRight(),moveLeft() and rotate()
Use the code given in TetrisBlock as a guide and modify it to your specific piece. You should draw
several diagrams of your piece in every rotationPos to help you with writing your code.
Test your specific TetrisBlock by modifying method nextTetrisBlock() in TetrisGame.
After your specific TetrisBlock is completed and tested, share it with your classmates and they will
share the pieces they have created. Essentially you have all done similar work, but you will have seven
different TetrisBlock Objects to use in your program.
//TetrisGame.java
import info.gridworld.actor.*;
import info.gridworld.grid.*;
import java.util.ArrayList;
import java.awt.Color;
/**
* This is a clone of the classic Tetris game.
* The GUI is the standard for GridWorld.
* It will compile and execute after class TetrisBug is written
* ...see Question 0
*/
public class TetrisGame {
/**
* World variable used for GUI...
* Initialized to 19x17 Grid for aesthetic viewing.
* ..leaves some columns at the right for extra game elements
* like 'upcoming piece' and 'score' information
*/
public static ActorWorld world = new ActorWorld(new BoundedGrid(19, 17));
/**
* A reference to the currently controlled TetrisBlock in the game.
* Its direction and rotation is controlled by the keyboard arrow keys.
*/
public static TetrisBlock currentBlock;
/**
* The number of lines cleared during a the game
*/
public static int score;
/**
* Handles game simulation and KeyEvent handling
* NOTE: YOU DO NOT NEED TO WRITE ANY CODE IN THE main
*/
public static void main(String[] args) {
//set up world
for (int i = 0; i < 19; i++) {
world.add(new Location(i,11),new Rock());
world.add(new Location(i,0),new Rock());
}
nextTetrisBlock();
//needed code for keyboard event handling
java.awt.KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(new java.awt.KeyEventDispatcher() {
public boolean dispatchKeyEvent(java.awt.event.KeyEvent event) {
String key = javax.swing.KeyStroke.getKeyStrokeForEvent(event).toString();
if (key.equals("pressed UP"))
currentBlock.rotate();
if (key.equals("pressed RIGHT"))
currentBlock.moveRight();
if (key.equals("pressed DOWN"))
currentBlock.act();
if (key.equals("pressed LEFT"))
currentBlock.moveLeft();
world.show();
return true;
}
});
world.show();
}
/**
* Calls removeCompleteRows and chooses a new TetrisBlock at random
*/
public static void nextTetrisBlock() {
removeCompleteRows();
TetrisBlock randomBlock = new TetrisBlock();//default 2block piece
//choose random block
int randNum = (int)(Math.random()*7)+1;//random number between 1 and 7
//if(randNum == 1)
// randomBlock = new TetrisBlockO();
//if(randNum == 2)
// randomBlock = new TetrisBlockI();
//if(randNum == 3)
// randomBlock = new TetrisBlockT();
//if(randNum == 4)
// randomBlock = new TetrisBlockL();
//if(randNum == 5)
// randomBlock = new TetrisBlock_L();
//if(randNum == 6)
// randomBlock = new TetrisBlockZ();
//if(randNum == 7)
// randomBlock = new TetrisBlock_Z();
currentBlock = randomBlock;
}
/**
* checks each row 1 through 18 (skip row 0) for full rows
* if a row is full, then remove the actor from each cell in that row
* and ask each actor located above the just deleted row to act and
* update the score++
*/
public static void removeCompleteRows() {
Grid<Actor> gr = world.getGrid();
//Your code goes here ... see Question 2
}
}
//TetrisBlock.java
import info.gridworld.actor.*;
import info.gridworld.grid.*;
import java.util.ArrayList;
import java.awt.Color;
/**
* TetrisBlock is a type of Bug. It will act in GridWorld by moving down
* (direction 180) if it can, otherwise it will ask TetrisGame to make a new
* TetrisBlock for the game.
*/
public class TetrisBlock extends TetrisBug {
/**
* value of the current rotation position {0,1,2 or 3}
*/
protected int rotationPos;
/**
* blocks will have three TetrisBug objects in it... they will be added in the
* constructor
*/
protected ArrayList<TetrisBug> blocks;
/**
* used as a convenient reference to the Grid
*/
protected Grid<Actor> gr;
/**
* default constructor
*/
public TetrisBlock() {
super(Color.blue);
rotationPos = 0;
gr = TetrisGame.world.getGrid();
// ==> LAMEST GAME OVER EVER !!! <==
// if the Grid does not have room for the TetrisBlock.. GameOver
if (gr.get(new Location(0, 5)) != null
|| gr.get(new Location(1, 5)) != null) {
javax.swing.JOptionPane.showMessageDialog(null, "Score: "
+ TetrisGame.score, "GAME OVER!", 0);
System.exit(0);
}
putSelfInGrid(gr, new Location(1, 5));
blocks = new ArrayList<TetrisBug>();
TetrisBug a;
// create TetrisBugs for ArrayList blocks and put them in Grid gr
a = new TetrisBug(Color.blue);
a.putSelfInGrid(gr, new Location(0, 5));
blocks.add(a);
// TetrisBlock subclasses will add two more TetrisBug objects to blocks
}
/**
* TetrisBlock and its TetrisBugs must face down (direction 180) If they can
* move down, they will. Otherwise, it will ask TetrisGame to create a new
* TetrisBlock since this one is stuck at the bottom.
*/
public void act() {
setDirection(180);
for (TetrisBug tb : blocks)
tb.setDirection(180);
if (canMoveDown())
moveDown();
else {
if (!TetrisGame.currentBlock.canMoveDown())
TetrisGame.nextTetrisBlock();
}
}
/**
* Move the TetrisBlock and its TetrisBugs one cell. (they should already be
* facing down) Note: The order in which all the TetrisBugs move is important
* and depends on the current rotationPos.
*/
public void moveDown() {
if (rotationPos == 0) {
move();
blocks.get(0).move();
} else if (rotationPos == 1) {
blocks.get(0).move();
move();
}
}
/**
* Returns true if the TetrisBlock and its TetrisBugs can move (they should
* already be facing down) Otherwise, returns false.
*/
public boolean canMoveDown() {
if (rotationPos == 0)
return canMove();
else if (rotationPos == 1)
return canMove() && blocks.get(0).canMove();
else
return true;
}
/**
* Sets the direction of the TetrisBlock and its TetrisBugs to 90 (right) If
* they can move, they will move one cell (to the right)
*/
public void moveRight() {
setDirection(90);
for (TetrisBug tb : blocks)
tb.setDirection(90);
if (rotationPos == 0) {
if (canMove() && blocks.get(0).canMove()) {
blocks.get(0).move();
move();
}
} else if (rotationPos == 1) {
if (canMove()) {
move();
blocks.get(0).move();
}
}
}
/**
* Sets the direction of the TetrisBlock and its TetrisBugs to 90 (right) If
* they can move, they will move one cell (to the right)
*/
public void moveLeft() {
// Your code goes here ... see Question 1
}
/**
* If the TetrisBlock and its TetrisBugs can rotate, then they will all move
* to their proper location for the given rotation designated by
* rotationPos... Update rotationPos.
*/
public void rotate() {
Location nextLoc;
if (rotationPos == 0) {
// only one block must move
nextLoc = new Location(getLocation().getRow() - 1,
getLocation().getCol() + 1);
if (gr.isValid(nextLoc) && gr.get(nextLoc) == null) {
moveTo(nextLoc);
rotationPos = (rotationPos + 1) % 2;// will be % 4 with 4 blocks
}
} else if (rotationPos == 1) {
// Your code goes here ... see Question 1
}
}
}
Some possible additions to the game (perhaps extra credit).
1. Show the upcoming TetrisBlock at the right of the window.
2. Display the current score … look at world.setMessage()