📄 jtetris.java
字号:
// JTetris.java//package Hw2;import java.awt.*;import javax.swing.*;import java.util.*;import java.awt.event.*;import javax.swing.event.*;/** JTetris presents a tetris game in a window. It handles the GUI and the animation. The Piece and Board classes handle the lower-level computations. This code is provided in finished form for the students. See Tetris-Architecture.html for an overview. @author Nick Parlante @version 1.0, March 1, 2001*//* Implementation notes: -The "currentPiece" points to a piece that is currently falling, or is null when there is no piece. -tick() moves the current piece -a timer object calls tick(DOWN) periodically -keystrokes call tick with LEFT, RIGHT, etc. -Board.undo() is used to remove the piece from its old position and then Board.place() is used to install the piece in its new position.*/public class JTetris extends JComponent { // size of the board in blocks public static final int WIDTH = 10; //10 public static final int HEIGHT = 20; //20 // Extra blocks at the top for pieces to start. // If a piece is sticking up into this area // when it has landed -- game over! public static final int TOP_SPACE = 4; // When this is true, plays a fixed sequence of 100 pieces protected boolean testMode = false; public final int TEST_LIMIT = 100; // Is drawing optimized protected boolean DRAW_OPTIMIZE = true; // Board data structures protected Board board; protected Piece[] pieces; // The current piece in play or null protected Piece currentPiece; protected int currentX; protected int currentY; protected boolean moved; // did the player move the piece // The piece we're thinking about playing // -- set by computeNewPosition // (storing this in ivars is slightly questionable style) protected Piece newPiece; protected int newX; protected int newY; // State of the game protected boolean gameOn; // true if we are playing protected int count; // how many pieces played so far protected long startTime; // used to measure elapsed time protected Random random; // the random generator for new pieces // Controls protected JLabel countLabel; protected JLabel timeLabel; protected JButton startButton; protected JButton stopButton; protected javax.swing.Timer timer; protected JSlider speed; public final int DELAY = 400; // milliseconds per tick JTetris(int width, int height) { super(); setPreferredSize(new Dimension(width, height)); gameOn = false; pieces = Piece.getPieces(); board = new Board(WIDTH, HEIGHT + TOP_SPACE); /* Register key handlers that call tick with the appropriate constant. e.g. 'j' and '4' call tick(LEFT) */ // LEFT registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(LEFT); } }, "left", KeyStroke.getKeyStroke('4'), WHEN_IN_FOCUSED_WINDOW ); registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(LEFT); } }, "left", KeyStroke.getKeyStroke('j'), WHEN_IN_FOCUSED_WINDOW ); // RIGHT registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(RIGHT); } }, "right", KeyStroke.getKeyStroke('6'), WHEN_IN_FOCUSED_WINDOW ); registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(RIGHT); } }, "right", KeyStroke.getKeyStroke('l'), WHEN_IN_FOCUSED_WINDOW ); // ROTATE registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(ROTATE); } }, "rotate", KeyStroke.getKeyStroke('5'), WHEN_IN_FOCUSED_WINDOW ); registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(ROTATE); } }, "rotate", KeyStroke.getKeyStroke('k'), WHEN_IN_FOCUSED_WINDOW ); // DROP registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(DROP); } }, "drop", KeyStroke.getKeyStroke('0'), WHEN_IN_FOCUSED_WINDOW ); registerKeyboardAction( new ActionListener() { public void actionPerformed(ActionEvent e) { tick(DROP); } }, "drop", KeyStroke.getKeyStroke('n'), WHEN_IN_FOCUSED_WINDOW ); // Create the Timer object and have it send // tick(DOWN) periodically timer = new javax.swing.Timer(DELAY, new ActionListener() { public void actionPerformed(ActionEvent e) { tick(DOWN); } }); } /** Sets the internal state and starts the timer so the game is happening. */ public void startGame() { // cheap way to reset the board state board = new Board(WIDTH, HEIGHT + TOP_SPACE); // draw the new board state once repaint(); count = 0; gameOn = true; if (testMode) random = new Random(0); // same seq every time else random = new Random(); // diff seq each game enableButtons(); timeLabel.setText(" "); addNewPiece(); timer.start(); startTime = System.currentTimeMillis(); } /** Sets the enabling of the start/stop buttons based on the gameOn state. */ private void enableButtons() { startButton.setEnabled(!gameOn); stopButton.setEnabled(gameOn); } /** Stops the game. */ public void stopGame() { gameOn = false; enableButtons(); timer.stop(); long delta = (System.currentTimeMillis() - startTime)/10; timeLabel.setText(Double.toString(delta/100.0) + " seconds"); } /** Given a piece, tries to install that piece into the board and set it to be the current piece. Does the necessary repaints. If the placement is not possible, then the placement is undone, and the board is not changed. The board should be in the committed state when this is called. Returns the same error code as Board.place(). */ public int setCurrent(Piece piece, int x, int y) { int result = board.place(piece, x, y); if (result <= Board.PLACE_ROW_FILLED) { // SUCESS // repaint the rect where it used to be if (currentPiece != null) repaintPiece(currentPiece, currentX, currentY); currentPiece = piece; currentX = x; currentY = y; // repaint the rect where it is now repaintPiece(currentPiece, currentX, currentY); } else { board.undo(); } return(result); } /** Selects the next piece to use using the random generator set in startGame(). */ public Piece pickNextPiece() { int pieceNum; pieceNum = (int) (pieces.length * random.nextDouble()); Piece piece = pieces[pieceNum]; return(piece); } /** Tries to add a new random piece at the top of the board. Ends the game if it's not possible. */ public void addNewPiece() { count++; if (testMode && count == TEST_LIMIT+1) { stopGame(); return; } // commit things the way they are board.commit(); currentPiece = null; Piece piece = pickNextPiece(); // Center it up at the top int px = (board.getWidth() - piece.getWidth())/2; int py = board.getHeight() - piece.getHeight(); // add the new piece to be in play int result = setCurrent(piece, px, py); // This probably never happens, since // the blocks at the top allow space // for new pieces to at least be added. if (result>Board.PLACE_ROW_FILLED) { stopGame(); } countLabel.setText(Integer.toString(count)); } /** Figures a new position for the current piece based on the given verb (LEFT, RIGHT, ...). The board should be in the committed state -- i.e. the piece should not be in the board at the moment. This is necessary so dropHeight() may be called without the piece "hitting itself" on the way down. Sets the ivars newX, newY, and newPiece to hold what it thinks the new piece position should be. (Storing an intermediate result like that in ivars is a little tacky.) */ public void computeNewPosition(int verb) { // As a starting point, the new position is the same as the old newPiece = currentPiece; newX = currentX; newY = currentY; // Make changes based on the verb switch (verb) { case LEFT: newX--; break; case RIGHT: newX++; break; case ROTATE: newPiece = newPiece.nextRotation(); // tricky: make the piece appear to rotate about its center // can't just leave it at the same lower-left origin as the // previous piece. newX = newX + (currentPiece.getWidth() - newPiece.getWidth())/2; newY = newY + (currentPiece.getHeight() - newPiece.getHeight())/2; break; case DOWN: newY--; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -