Java版俄罗斯方块

参考:Java项目开发实训教程(朱神喜 黄方胜著)

环境:linux+java;

工具:vim

相关代码:

UML图:未完成品:

(UML还没有完成的,后续会更新)

ErsBox.java

 1 package Mypackage;
 2 
 3 /*
 4  * 方格的抽象,需要这个是可以复制的
 5  * */
 6 
 7 public class ErsBox implements Cloneable {
 8     //4个方格形成一个方块
 9     public final static int BOXES_ROWS = 4;
10     public final static int BOXES_COLS = 4;
11 
12     private boolean isColor;
13     
14     public ErsBox(boolean isColor) {
15         this.isColor = isColor;
16     }
17 
18     public boolean isColorBox() {
19         return this.isColor;
20     }
21 
22     public void setColor(boolean isColor) {
23         this.isColor = isColor;
24     }
25 
26     public Object clone() {
27         Object cloned = null;
28         try {
29             cloned = super.clone();
30         }
31         catch (Exception ex) {
32             ex.printStackTrace();
33         }
34         return cloned;
35     }
36 }
View Code

ControlPanel.java

  1 package Mypackage;
  2 
  3 import Mypackage.ErsBox;
  4 
  5 import javax.swing.*;
  6 import javax.swing.border.Border;
  7 import javax.swing.border.EtchedBorder;
  8 import java.awt.*;
  9 import java.awt.event.*;
 10 
 11 public class ControlPanel extends JPanel {
 12     //两个存放游戏信息的文本域
 13     public final static int DEFAULT_LEVEL = 5;
 14     private JTextField tfLevel = new JTextField("" + DEFAULT_LEVEL), tfScore = new JTextField("0");
 15 
 16     /*
 17     //游戏控制的按键
 18     private JButton
 19     btPlay = new JButton("开始"),
 20         btPause = new JButton("暂停"),
 21         btStop = new JButton("停止"),
 22         btTurnLevelUp = new JButton("增加难度"),
 23         btTurnLevelDown = new JButton("降低难度");
 24     */
 25     //存放提示面板
 26     private JPanel plTip = new JPanel(new BorderLayout());
 27     //方块提示面板
 28     private TipPanel plTipBlock = new TipPanel();
 29     //信息存放的面板
 30     private JPanel plInfo = new JPanel(new GridLayout(4, 1));
 31     //按钮存放的面板
 32     private JPanel plButton = new JPanel(new GridLayout(5, 1));
 33     //计时器,用于定时更新面板信息
 34    // private Timer timer;
 35     //当前的游戏局
 36     //private ErsBlocksGame game;
 37     //面板的边框
 38     private Border border = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140));
 39 
 40 
 41    // public ControlPanel(final ErsBlocksGame game) {
 42        public ControlPanel() {
 43         setLayout(new GridLayout(2, 1, 0, 4));
 44        // this.game = game;
 45 
 46         plTip.add(new JLabel("下一个方块"), BorderLayout.NORTH);
 47         plTip.add(plTipBlock,BorderLayout.CENTER);
 48         plTip.setBorder(border);
 49 
 50         plInfo.add(new JLabel("难度级别"));
 51         plInfo.add(tfLevel);
 52         plInfo.add(new JLabel("得分"));
 53         plInfo.add(tfScore);
 54         plInfo.setBorder(border);
 55         //两个文本域设置为不可编辑
 56     /*    
 57         plButton.add(btPlay);
 58         plButton.add(btPause);
 59         plButton.add(btStop);
 60         plButton.add(btTurnLevelUp);
 61         plButton.add(btTurnLevelDown);
 62         plButton.setBorder(border);
 63     */
 64         //将三个面板加放到控制面板中
 65         add(plTip);
 66         add(plInfo);
 67     //    add(plButton);
 68     
 69     /*
 70         //增加键盘监听器
 71         addKeyListener(new ControlKeyListener());
 72         //设置各种按钮的监听器行为
 73         btPlay.addActionListener(new ActionListener() {
 74             public void actionPerformed(ActionEvent ae) {
 75                 game.playGame();
 76             }
 77         });
 78 
 79         btPause.addActionListener(new ActionListener() {
 80             public void actionPerformed(ActionEvent ae) {
 81                 if (btPause.getText().equals(new String("暂停"))) {
 82                     game.pauseGame();
 83                 } else {
 84                     game.resumeGame();
 85                 }
 86             }
 87         });
 88 
 89         btStop.addActionListener(new ActionListener() {
 90             public void actionPerformed(ActionEvent ae) {
 91                 game.stopGame();
 92             }
 93         });
 94 
 95         btTurnLevelUp.addActionListener(new ActionListener() {
 96             public void actionPerformed(ActionEvent ae) {
 97                 try {
 98                     int level = Integer.parseInt(tfLevel.getText());
 99                     if (level < ErsBlocksGame.MAX_LEVEL)
100                         tfLevel.setText("" + (level + 1));
101                 } catch (NumberFormatException e) {}
102                 requestFocus();
103             }
104         });
105 
106         btTurnLevelDown.addActionListener(new ActionListener() {
107             public void actionPerformed(ActionEvent ae) {
108                 try {
109                     int level = Integer.parseInt(tfLevel.getText());
110                     if (level > 1)
111                         tfLevel.setText("" + (level - 1));
112                 } catch (NumberFormatException e) {}
113                 requestFocus();
114             }
115         });
116     
117     */
118     //组件适配器调整
119         addComponentListener(new ComponentAdapter() {
120             public void componentResized(ComponentEvent ce) {
121                 plTipBlock.fanning();
122             }
123         });
124 
125         
126     /*    
127         //定时器
128         timer = new Timer(500, new ActionListener() {
129             public void actionPerformed(ActionEvent ae) {
130                 tfScore.seText("" + game.getScore());
131                 int scoreForLevelUpdate = game.getScoreForLevelUpdate();
132                 if(scoreForLevelUpdate >= ErsBlocksGame.PRE_LEVEL_SCORE && scoreForLevelUpdate >0)
133                     game.levelUpdate();
134             }
135         });
136         timer.start();
137     */
138     }
139         
140     //相关的设置函数与返回函数
141     public int getLevel() {
142         return Integer.parseInt(tfLevel.getText());
143     }
144 
145     public void setLevel(int level) {
146         tfLevel.setText("" + level);
147     }
148     
149     public int getScore() {
150         return Integer.parseInt(tfScore.getText());
151     }
152 
153     public void setScore(int score) {
154         tfScore.setText("" + score);
155     }
156     
157     /*
158     public void setPlayButtonEnable(boolean enable) {
159         btPlay.setEnabled(enabel);
160     }
161 
162     public void setPauseButtonEnable(boolean enable) {
163         btPause.setEnabled(enable);
164     }
165     */
166     public void setTipStyle(int style) {
167         plTipBlock.setStyle(style);
168     }
169 
170     public void reset() {
171         setScore(0);
172         setLevel(DEFAULT_LEVEL);
173     }
174 
175 
176 
177     /*TipPanel提示面板内部类*/
178     private class TipPanel extends JPanel {
179         private Color backcolor = Color.darkGray, frontColor = Color.lightGray;
180         private ErsBox[][] boxes = new ErsBox[ErsBox.BOXES_ROWS][ErsBox.BOXES_COLS];
181         private int style = 0x0f00, boxWidth, boxHeight;
182         private boolean isTiled = false; //用于判断是否已经获得了长度与宽度;
183 
184         //预设置面板的前背景和后背景
185         public TipPanel() {
186             int i, j;
187             for (i = 0; i < ErsBox.BOXES_ROWS; i++) {
188                 for (j = 0; j < ErsBox.BOXES_COLS; j++) {
189                     boxes[i][j] = new ErsBox(false);
190                 }
191             }
192         }
193 
194         public TipPanel(Color backcolor, Color frontColor) {
195             this(); //调用无参的构造函数;
196             this.backcolor = backcolor;
197             this.frontColor = frontColor;
198         }
199 
200         public void setStyle(int style) {
201             this.style = style;
202             repaint();
203         }
204 
205         public void paintComponent(Graphics g) {
206             super.paintComponent(g);
207            // 根据窗口的大小重新调整方格的大小
208             if (!isTiled)
209                 fanning();
210             int key = 0x8000, i, j;
211             for (i = 0; i < ErsBox.BOXES_COLS; i++) {
212                 for (j = 0; j < ErsBox.BOXES_ROWS; j++) {
213                     Color color = (((key & style) == 0) ? backcolor : frontColor);
214                     g.setColor(color);
215                     g.fill3DRect(j * boxWidth, i * boxHeight, boxWidth, boxHeight, true);
216                     key >>= 1;
217                 }
218             }
219         }
220 
221         public void fanning() {
222             boxWidth = getSize().width / ErsBox.BOXES_COLS;
223             boxHeight = getSize().height / ErsBox.BOXES_ROWS;
224             isTiled = true;
225         }
226 
227         //用于测试代码的 //
228         public ErsBox getBox(int x, int y) {
229             if (0 <= x && x <= 3 && 0 <= y && y <= 3)
230                 return boxes[x][y];
231             return null;
232         }
233     }
234 
235 
236     /*方向键的设置*/
237     /*
238     private  class ControlKeyListener extends KeyAdapter {
239         public void keyPressed(KeyEvent ke) {
240             if (!game.isPlaying())
241                 return;
242             ErsBlock block = game.getCurBlock();
243             switch (ke.getKeyCode()) {
244                 case KeyEvent.VK_DOWN:
245                     block.moveDown();
246                     break;
247                 case KeyEvent.VK_LEFT:
248                     block.moveLeft();
249                     break;
250                 case KeyEvent.VK_RIGHT:
251                     block.moveRight();
252                     break;
253                 case KeyEvent.VK_UP:
254                     block.turnNext();
255                     break;
256                 default:
257                     break;
258             }
259         }
260     }
261     */
262 }
View Code

GameCanvas.java

  1 package Mypackage;
  2 
  3 import Mypackage.ErsBox;
  4 import javax.swing.*;
  5 import javax.swing.border.EtchedBorder; //用于设置边框
  6 import java.awt.*;
  7 
  8 public class GameCanvas extends JPanel {
  9     private int rows, cols, score, scoreForLevelUpdate;          //游戏面板的行与列,分数,到下一级别的分数的差距
 10     private int boxWidth, boxHeight; //方格的宽度与高度
 11     private Color frontColor = Color.orange, backColor = Color.black;
 12     private ErsBox[][] boxes;
 13     
 14     public GameCanvas(int rows, int cols) {
 15         this.rows = rows;
 16         this.cols = cols;
 17         int i, j;
 18         boxes = new ErsBox[rows][cols];
 19         //设置方格数rows*cols
 20         for(i = 0; i < rows; i++) {
 21             for(j = 0;j < cols; j++) {
 22                 boxes[i][j] = new ErsBox(false);
 23             }
 24         }
 25         setBorder(new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140)));
 26     }
 27 
 28     /*GameCanvas的第二个构造函数,主要是在第一个的基础上加上背景颜色
 29      * @param frontColor Color, 前景色
 30      * @param backColor Color, 背景色
 31      */
 32     public GameCanvas(int rows, int cols, Color frontColor, Color backColor) {
 33         this(rows, cols);
 34         this.frontColor = frontColor;
 35         this.backColor = backColor;
 36     }
 37 
 38     public int getCols() {
 39         return cols;
 40     }
 41 
 42     public int getRows() {
 43         return rows;
 44     }
 45 
 46     public Color getBlockColor() {
 47         return this.frontColor;
 48     }
 49 
 50     public void setBlockColor(Color frontColor) {
 51         this.frontColor = frontColor;
 52     }
 53 
 54     public Color getBackgroundColor() {
 55         return this.backColor;
 56     }
 57 
 58     public void setBackgroundColor(Color backColor) {
 59         this.backColor = backColor;
 60     }
 61     
 62     public int getScore() {
 63         return score;
 64     }
 65 
 66     public void setScore(int socre) {
 67         this.score = score;
 68     }
 69 
 70     public int getScoreForLevelUpdate() {
 71         return     scoreForLevelUpdate;
 72     }
 73 
 74     public void removeLine(int row) {
 75         int i, j;
 76         boolean isColor;
 77         for(i = row; i > 0; i--) {
 78             for(j = 0; j < cols; ++j) {
 79                 boxes[i][j] = (ErsBox) boxes[i-1][j].clone();
 80             }
 81         }
 82         score += 100;
 83         scoreForLevelUpdate += 100;
 84         repaint();
 85         //首行要清空
 86     //    for(j = 0; j < cols; ++j)
 87     //        boxes[0][j].setColor(false);
 88     }
 89 
 90     /*得到指定行,列的方格引用
 91      */
 92     public ErsBox getBox(int row, int col) {
 93         if(row < 0 || row >= rows  || col < 0 || col >= cols)
 94             return null;
 95         return boxes[row][col];
 96     }
 97 
 98     /*覆盖JComponent类的方法,绘制当前容器的所有的组件
 99      */
100     public void paintComponent(Graphics g) {
101         super.paintComponent(g);
102         g.setColor(frontColor);
103         int i, j;
104         for(i = 0; i < rows; ++i) {
105             for(j = 0; j < cols; ++j) {
106                 g.setColor(boxes[i][j].isColorBox() ? frontColor : backColor);
107                 g.fill3DRect(j*boxWidth, i*boxHeight, boxWidth, boxHeight, true);
108             }
109         }
110     }
111 
112     public void resetScoreForLevelUpdate() {
113         this.scoreForLevelUpdate = 0;
114         this.score = 0;
115         repaint();
116     }
117 
118     //根据窗口的大小调整方块的大小
119     public void fanning() {
120         boxWidth = getSize().width / cols;
121         boxHeight = getSize().height / rows;
122     }
123 
124     //重置画布
125     public void reset() {
126         score = 0;
127         scoreForLevelUpdate = 0;
128         int i, j;
129         for(i= 0; i < rows; ++i) {
130             for(j = 0; j < cols; ++j) {
131                 boxes[i][j].setColor(false);
132             }
133         }
134         repaint();
135     }
136 }
View Code

ErsBlock.java

  1 package Mypackage;
  2 
  3 import Mypackage.ErsBox;
  4 import Mypackage.GameCanvas;
  5 
  6 public class ErsBlock extends Thread {
  7 
  8     public final static int BOXES_ROWS = 4;
  9     public final static int BOXES_COLS = 4;
 10     public final static int MAX_LEVEL = 10;
 11     //下落的平滑因子
 12     public final static int LEVEL_FLATNESS_GENE = 3;
 13     //相近的两级之间的速度之差,这个主要与游戏难度相关
 14     public final static int BETWEEN_LEVELS_DEGRESS_TIME = 50;
 15     //方块的种类
 16     private final static int BLOCK_KIND_NUMBER = 7;
 17     //每种方块变形的数目
 18     private final static int BLOCK_STATUS_NUMBER = 4;
 19     public final static int[][] STYLES = {
 20         { 0x0f00, 0x4444, 0x0f00, 0x4444 }, //长条型的4种状态;
 21         { 0x04e0, 0x0464, 0x00e4, 0x04c4 }, //'T'型的4种状态;
 22         { 0x4620, 0x6c00, 0x4620, 0x6c00 }, //反'Z'的4种状态;
 23         { 0x2640, 0xc600, 0x2640, 0xc600 }, //'Z'的4种状态;
 24         { 0x6220, 0x1700, 0x2230, 0x0740 }, //'7'的4种状态;
 25         { 0x6440, 0x0e20, 0x44c0, 0x8e00 }, //反'7'的4种状态;
 26         { 0x0660, 0x0660, 0x0660, 0x0660 }, //正方形的4种状态;
 27     };
 28     //private GameGanvas canvas; //游戏面板,这个方块在这个面板上显示
 29     private GameCanvas canvas; //先用于替代GameGanvas进行测试
 30     private ErsBox[][] boxes = new ErsBox[BOXES_ROWS][BOXES_COLS];
 31     //用于构造函数中的参数
 32     int style, x, y, level;
 33     //用于控制方块的运行
 34     boolean pausing = false, moving = true; 
 35     
 36     /*debug*/
 37     public void printNum() {
 38         System.out.println("y:" + y + "  " + "x" + x);
 39     }
 40 
 41     /**
 42      * 构造方法,产生一个特定的块,需要把其ErsBox也弄出来
 43      * @param style 块的样式,对应于STYLES中的一值
 44      * @param x 起始位置,对应于canvas中左上角的位置
 45      * @param y 起始位置, 对应于canvas中左上角的位置
 46      * @param level 游戏的难度,用于控制方块的下落速度
 47      * @param canvas 方块出现的画板
 48      **/
 49     public ErsBlock(int style, int y, int x, int level, GameCanvas canvas) {
 50         this.style = style;
 51         this.x = x;
 52         this.y = y;
 53         //printNum();
 54         this.level = level;
 55         this.canvas = canvas;
 56         int key = 0x8000, i, j;
 57         for(i = 0; i < BOXES_ROWS; ++i) {
 58             for(j = 0; j < BOXES_COLS; ++j) {
 59                 boolean isColor = ((style & key) != 0);
 60                 boxes[i][j] = new ErsBox(isColor);
 61                 key >>= 1;
 62             }
 63         }
 64         //display();
 65     }
 66     
 67     //线程类的run函数,下落到不能下落为止
 68     
 69     public void run() {
 70         while(moving) {
 71             try {
 72                 sleep(BETWEEN_LEVELS_DEGRESS_TIME * (MAX_LEVEL - level + LEVEL_FLATNESS_GENE));
 73             }
 74             catch (InterruptedException ie) {
 75                 ie.printStackTrace();
 76             }
 77             display();    
 78             if(!pausing) {
 79                 moving = (moveTo(y+1, x) && moving);
 80             }
 81         }
 82         /*debug*/
 83         //System.out.println("ErsBlockgame run end");
 84     }
 85 
 86     //向左移动
 87     public void moveLeft() {
 88         moveTo(y, x-1);
 89     }
 90     
 91     //向右移动
 92     public void moveRight() {
 93         moveTo(y, x+1);
 94     }
 95 
 96     //向下移动
 97     public void moveDown() {
 98         moveTo(y+1, x);
 99     }
100 
101     //块变形(用于测试的)
102     public void turnNext() {
103 
104         int i, j, newStyle;
105         for(i = 0; i < BLOCK_KIND_NUMBER; ++i) {
106             for(j = 0; j < BLOCK_STATUS_NUMBER; ++j) {
107                 if(STYLES[i][j] == style) {
108                     newStyle = STYLES[i][(j+1) % BLOCK_STATUS_NUMBER];
109                     /*dubug*/
110                 //    System.out.println("trunNext:" + Integer.toHexString(newStyle));
111                     turnTo(newStyle);
112                     return;
113                 }
114             }
115         }
116     }
117 
118     //暂停块的下落, 对应游戏暂停;
119     public void pauseMove() {
120         pausing = true;
121     }
122     
123     public void resumeMove() {
124         pausing = false;
125     }
126 
127     //停止块的下落,对应游戏中止;
128     public void stopMove() {
129         moving = false;
130     }
131 
132     //将当前的块从画板中抹去,只有当重新display才会显示
133     private void earse() {
134         int i, j;
135         for(i = 0; i < BOXES_ROWS; i++) {
136             for(j = 0; j < BOXES_COLS; j++) {
137                 if(boxes[i][j].isColorBox()) {
138                     ErsBox box = canvas.getBox(y+i, x+j);
139                     box.setColor(false);
140                 }
141                 /*debug*/
142                 if(boxes[i][j] == null)
143                     System.out.println("box is null");
144             }
145         }
146     }
147 
148     //设置当前块从画布中可显示,当再次进行画布的重画时才可以看见
149     private void display() {
150         int i, j;
151         for(i = 0; i < BOXES_ROWS; i++){
152             for(j = 0; j < BOXES_COLS; j++) {
153                 if(boxes[i][j].isColorBox()) {
154                     ErsBox box = canvas.getBox(y+i, x+j);
155                     if(box == null)
156                         continue;
157                     box.setColor(true);
158                 }
159             }
160         }
161     }
162 
163     //用于判断是否可以移动到某个坐标
164     private boolean isMoveAble(int newRow, int newCol) {
165         earse();
166         int i, j;
167         for(i = 0; i < BOXES_ROWS; ++i) {
168             for(j = 0; j < BOXES_COLS; ++j) {
169                 if(boxes[i][j].isColorBox()) { //只对于有颜色有有限制
170                     ErsBox box = canvas.getBox(i+newRow, j+newCol);
171                     if(box == null || box.isColorBox()) {
172                         display();
173                         return false;
174                     }
175                 }
176             }
177         }
178         display();
179         return true;
180     }
181 
182     /*用于进行移动,考虑到不能由多个线程同时控制方块,所以要声明为synchronized
183      * @param newRow int, 目的地所在行
184      * @param newCol int, 目的地所在列
185      * return boolean, true-移动成功,false-移动失败
186      */
187     private synchronized boolean moveTo(int newRow, int newCol) {
188         if(!isMoveAble(newRow, newCol) || !moving) {
189             /*debug*/
190             //System.out.println("x:" + newCol + "y:" + newRow);
191             return false;
192         }
193         earse();
194         y = newRow;
195         x = newCol;
196         display();
197         canvas.repaint();
198         return true;
199     }
200 
201     //当前块能否变形为newStyle,主要是考虑边界问题;
202     private boolean isTurnAble(int newStyle) {
203         int i, j;
204         int key = 0x8000;
205         earse();
206         for(i = 0; i < BOXES_ROWS; ++i) {
207             for(j = 0; j < BOXES_COLS; ++j) {
208                 if((newStyle & key) != 0) {
209                     ErsBox box = canvas.getBox(y+i, x+j);
210                     if(box.isColorBox() || box == null) {
211                         display();
212                         return false;
213                     }
214                 }
215                 key >>= 1;
216             }
217         }
218         display();
219         return true;
220     }
221 
222     //将当前块变形为newStyle
223     private boolean turnTo(int newStyle) {
224         if(!isTurnAble(newStyle) || !moving)
225             return false;
226         int i, j, key=0x8000;
227         earse();
228         for(i = 0; i < BOXES_ROWS; ++i) {
229             for(j = 0; j < BOXES_COLS; ++j) {
230                 boolean isColor = ((newStyle & key) != 0);
231                 boxes[i][j].setColor(isColor);
232                 key >>= 1;
233             }
234         }
235         style = newStyle;
236         display();
237         canvas.repaint();
238         return true;
239     }
240 
241 }
View Code

ErsBlocksGame.java

  1 import Mypackage.ErsBox;
  2 import Mypackage.ErsBlock;
  3 import Mypackage.GameCanvas;
  4 import Mypackage.ControlPanel;
  5 
  6 import javax.swing.*;
  7 import java.awt.*;
  8 import java.awt.event.*;
  9 
 10 public class ErsBlocksGame extends JFrame {
 11     //定义各种参数
 12     private GameCanvas canvas;
 13     private ControlPanel ctrlPanel;    
 14     private JPanel plButton;
 15     private JPanel ctrlPanelwithButton;
 16     private ErsBlock block; //当前活动的块
 17     private boolean playing; //当前游戏的状态
 18     private final static int PER_LINE_SCORE = 100; //填满一行得100;
 19     public final static int PER_LEVEL_SCORE = PER_LINE_SCORE * 20; //升级所需的得分
 20     public final static int MAX_LEVEL = 10;
 21     public final static int DEFAULT_LEVEL = 5;
 22 
 23     //控制面板的按钮
 24     private JButton
 25         btPlay = new JButton("开始"),
 26         btPause = new JButton("暂停"),
 27         btStop = new JButton("停止"),
 28         btTurnLevelUp = new JButton("增加难度"),
 29         btTurnLevelDown = new JButton("降低难度");
 30 
 31     //定时器(用于定时更新信息面板信息)
 32     Timer timer;
 33 
 34     //相关菜单(项)声明
 35     private JMenuBar bar =new JMenuBar();
 36     private JMenu
 37         mGame = new JMenu("游戏"),
 38         mControl = new JMenu("控制"),
 39         mInfo = new JMenu("帮助");
 40     private JMenuItem
 41         //游戏
 42         miNewGame = new JMenuItem("新游戏"),
 43         miSetBlockColor = new JMenuItem("设置方块颜色"),
 44         miSetBackColor = new JMenuItem("设置背景颜色"),
 45         miTurnHarder = new JMenuItem("增加难度"),
 46         miTurnEasier = new JMenuItem("降低难度"),
 47         miExit = new JMenuItem("退出"),
 48         //控制
 49         miPlay = new JMenuItem("开始"),
 50         miPause = new JMenuItem("暂停"),
 51         miResume = new JMenuItem("继续"),
 52         miStop = new JMenuItem("停止"),
 53         //菜单
 54         miAuthor = new JMenuItem("作者: Java游戏设计组"),
 55         miSourceInfo = new JMenuItem("版本: 1.0");
 56 
 57     public ErsBlocksGame(String title) {
 58         super(title);
 59         setSize(315, 392);
 60         Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize();
 61         setLocation((scrSize.width - getSize().width)/2, (scrSize.height - getSize().height)/2);
 62         ctrlPanel = new ControlPanel();
 63         plButton = new JPanel(new GridLayout(5,1));
 64         ctrlPanelwithButton = new JPanel(new BorderLayout());
 65 
 66         //创建菜单
 67         createMenu();
 68         //为控制按钮设置监听器
 69         createButton();
 70         //设置键盘监听器
 71         ctrlPanel.addKeyListener(new ControlKeyListener());//addKeyListener not for JFrame;
 72 
 73         Container container = getContentPane();
 74         container.setLayout(new BorderLayout(6, 0));
 75         canvas = new GameCanvas(20, 12);
 76         //放置
 77         ctrlPanelwithButton.add(ctrlPanel,BorderLayout.NORTH);
 78         ctrlPanelwithButton.add(plButton, BorderLayout.SOUTH);
 79         container.add(canvas, BorderLayout.CENTER);
 80         container.add(ctrlPanelwithButton, BorderLayout.EAST);
 81         //增加监听器
 82         addWindowListener(new WindowAdapter() {
 83             public void windowClosing(WindowEvent we) {
 84                 stopGame();
 85                 System.exit(0);
 86             }
 87         });
 88         addComponentListener(new ComponentAdapter() {
 89             public void componentResized(ComponentEvent ce) {
 90                 canvas.fanning();
 91             }
 92         });
 93 
 94         //设置定时器
 95         timer = new Timer(500, new ActionListener() {
 96             public void actionPerformed(ActionEvent ae) {
 97                 ctrlPanel.setScore(getScore());
 98                 int scoreForLevelUpdate = getScoreForLevelUpdate();
 99                 if(scoreForLevelUpdate >= PER_LEVEL_SCORE && scoreForLevelUpdate > 0)
100                     levelUpdate();
101             }
102         });
103         timer.start();//启动
104 
105         setVisible(true);
106         canvas.fanning();
107     }
108     
109     private void createButton() {
110         plButton.add(btPlay);
111         plButton.add(btPause);
112         plButton.add(btStop);
113         plButton.add(btTurnLevelUp);
114         plButton.add(btTurnLevelDown);
115        // plButton.setBorder(border);
116         //设置各种按钮的监听器行为
117         btPlay.addActionListener(new ActionListener() {
118             public void actionPerformed(ActionEvent ae) {
119                 playGame();
120             }
121         });
122 
123         btPause.addActionListener(new ActionListener() {
124             public void actionPerformed(ActionEvent ae) {
125                 if (btPause.getText().equals(new String("暂停"))) {
126                     pauseGame();
127                 } else {
128                     resumeGame();
129                 }
130             }
131         });
132 
133         btStop.addActionListener(new ActionListener() {
134             public void actionPerformed(ActionEvent ae) {
135                 stopGame();
136             }
137         });
138 
139         btTurnLevelUp.addActionListener(new ActionListener() {
140             public void actionPerformed(ActionEvent ae) {
141                 try {
142                     int level = ctrlPanel.getLevel();
143                     if (level < ErsBlocksGame.MAX_LEVEL)
144                         ctrlPanel.setLevel(level + 1);
145                 } catch (NumberFormatException e) {}
146                 requestFocus();
147             }
148         });
149 
150         btTurnLevelDown.addActionListener(new ActionListener() {
151             public void actionPerformed(ActionEvent ae) {
152                 try {
153                     int level = ctrlPanel.getLevel();
154                     if (level > 1)
155                         ctrlPanel.setLevel(level - 1);
156                 } catch (NumberFormatException e) {}
157                 requestFocus();
158             }
159         });
160     }
161     
162     
163 
164     private void createMenu() {
165         bar.add(mGame);
166         bar.add(mControl);
167         bar.add(mInfo);
168 
169         mGame.add(miNewGame);
170         mGame.addSeparator(); //分隔条
171         mGame.add(miSetBackColor);
172         mGame.add(miSetBlockColor);
173         mGame.addSeparator();
174         mGame.add(miTurnHarder);
175         mGame.add(miTurnEasier);
176         mGame.addSeparator();
177         mGame.add(miExit);
178 
179         mControl.add(miPlay);
180         mControl.add(miPause);
181         mControl.add(miResume);
182         mControl.add(miStop);
183 
184         mInfo.add(miAuthor);
185         mInfo.add(miSourceInfo);
186 
187         setJMenuBar(bar);
188 
189         //设置对应的菜单响应事件
190         
191         //设置快捷键
192         miPause.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK));
193         miResume.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
194 
195         //开始菜单项
196         miPlay.addActionListener(new ActionListener() {
197             public void actionPerformed(ActionEvent ae) {
198                 stopGame();
199                 reset();
200                 setLevel(DEFAULT_LEVEL);
201             }
202         });
203         
204         miNewGame.addActionListener(new ActionListener() {
205             public void actionPerformed(ActionEvent ae) {
206                 stopGame();
207                 reset();
208                 setLevel(DEFAULT_LEVEL);
209             }
210         });
211 
212         miSetBlockColor.addActionListener(new ActionListener() {
213             public void actionPerformed(ActionEvent ae) {
214                 Color newFrontColor = JColorChooser.showDialog(ErsBlocksGame.this, "设置方块颜色", canvas.getBlockColor());
215                 if(newFrontColor != null)
216                     canvas.setBlockColor(newFrontColor);
217             }
218         });
219 
220         miSetBackColor.addActionListener(new ActionListener() {
221             public void actionPerformed(ActionEvent ae) {
222                 Color newBackColor = JColorChooser.showDialog(ErsBlocksGame.this, "设置背景颜色", canvas.getBackgroundColor());
223                 if(newBackColor != null) 
224                     canvas.setBackgroundColor(newBackColor);
225             }
226         });
227 
228         miTurnHarder.addActionListener(new ActionListener() {
229             public void actionPerformed(ActionEvent ae) {
230                 int curLevel = getLevel();
231                 if(curLevel < MAX_LEVEL)
232                     setLevel(curLevel + 1);
233             }
234         });
235 
236         miTurnEasier.addActionListener(new ActionListener() {
237             public void actionPerformed(ActionEvent ae) {
238                 int curLevel = getLevel();
239                 if(curLevel > 1) 
240                     setLevel(curLevel - 1);
241             }
242         });
243 
244         miExit.addActionListener(new ActionListener() {
245             public void actionPerformed(ActionEvent ae) {
246                 System.exit(0);
247             }
248         });
249 
250         //控制
251         miPlay.addActionListener(new ActionListener() {
252             public void actionPerformed(ActionEvent ae) {
253                 playGame();
254             }
255         });
256 
257         miPause.addActionListener(new ActionListener() {
258             public void actionPerformed(ActionEvent ae) {
259                 pauseGame();
260             }
261         });
262 
263         miResume.addActionListener(new ActionListener() {
264             public void actionPerformed(ActionEvent ae) {
265                 resumeGame();
266             }
267         });
268         
269         miStop.addActionListener(new ActionListener() {
270             public void actionPerformed(ActionEvent ae) {
271                 stopGame();
272             }
273         });
274     }
275 
276     /*控制方法*/
277     //重置
278     public void reset() {
279         ctrlPanel.reset();
280         canvas.reset();
281     }
282     //get&set
283     public boolean isPlaying() {
284         return playing;
285     }
286 
287     public ErsBlock getCurBlock() {
288         return block;
289     }
290 
291     public GameCanvas getCanvas() {
292         return canvas;
293     }
294 
295     public int getLevel() {
296         return ctrlPanel.getLevel();
297     }
298 
299     public void setLevel(int level) {
300         if(level < 11 && level > 0)
301             ctrlPanel.setLevel(level);
302     }
303     
304     public int getScore() {
305         if(canvas != null)
306             return canvas.getScore();
307         return 0;
308     }
309 
310     public int getScoreForLevelUpdate() {
311         if(canvas != null)
312             return canvas.getScoreForLevelUpdate();
313         return 0;
314     }
315     
316 
317     public void setPauseButtonLabel(boolean pause) {
318         btPause.setText(pause ? "暂停" : "继续");
319     }
320 
321     //控制函数(主要是让按钮事件调用)
322     public void playGame() {
323         play();
324         btPlay.setEnabled(false);
325         miPlay.setEnabled(false);
326         ctrlPanel.requestFocus();
327     }
328 
329     public void pauseGame() {
330         if(block != null)
331             block.pauseMove();
332         //btPause.setEnabled(false);
333         miPause.setEnabled(false);
334         miResume.setEnabled(true);
335         setPauseButtonLabel(false);
336     }
337     
338     public void resumeGame() {
339         if(block != null)
340             block.resumeMove();
341         //btPause.setEnabled(true);
342         miPause.setEnabled(true);
343         miResume.setEnabled(false);
344         setPauseButtonLabel(true);
345         ctrlPanel.requestFocus();
346     }
347 
348     public void stopGame() {
349         playing = false;
350         if(block != null)
351             block.stopMove();
352         miPlay.setEnabled(true);
353         miPause.setEnabled(true);
354         miResume.setEnabled(false);
355         btPlay.setEnabled(true);
356         btPause.setEnabled(true);
357     }
358 
359     public boolean levelUpdate() {
360         int curLevel = getLevel();
361         if(curLevel < MAX_LEVEL) {
362             setLevel(curLevel + 1);
363             canvas.resetScoreForLevelUpdate();
364             return true;
365         }
366         return false;
367     }
368     
369     //内部实现
370     private void play() {
371         reset();
372         playing = true;
373         Thread thread = new Thread(new Game());
374         thread.start();
375     }
376 
377     private void reportGameOver() {
378         JOptionPane.showMessageDialog(this, "游戏结束");
379     }
380     
381     /*方向键的类,作为监听类*/
382     private  class ControlKeyListener extends KeyAdapter {
383             public void keyPressed(KeyEvent ke) {
384                 /*debug*/
385                 //System.out.println("direction key");
386                 if (!isPlaying())
387                     return;
388                 ErsBlock block = getCurBlock();
389                 switch (ke.getKeyCode()) {
390                     case KeyEvent.VK_DOWN:
391                         block.moveDown();
392                         break;
393                     case KeyEvent.VK_LEFT:
394                         block.moveLeft();
395                         break;
396                     case KeyEvent.VK_RIGHT:
397                         block.moveRight();
398                         break;
399                     case KeyEvent.VK_UP:
400                         block.turnNext();
401                         break;
402                     default:
403                         break;
404                 }
405             }
406         }
407 
408     /*Game内部类,用于产生一个新的游戏局*/
409     private class Game implements Runnable {
410         public void run() {
411             //随机产生一个方块
412             int col = (int) (Math.random() * (canvas.getCols() - 3)),
413                 style = ErsBlock.STYLES[(int)(Math.random()*7)][(int)(Math.random()*4)];
414             while(playing) {
415                 if(block != null) {
416                     if(block.isAlive()) { //判断线程是否在活动状态
417                         try {
418                             Thread.currentThread().sleep(100);
419                         }
420                         catch(InterruptedException ie) {
421                             ie.printStackTrace();
422                         }
423                         continue;
424                     }
425                 }
426                 checkFullLine();
427                 if(isGameOver()) {
428                     miPlay.setEnabled(true);
429                     miPause.setEnabled(true);
430                     miResume.setEnabled(false);
431                     btPause.setEnabled(true);
432                     btPlay.setEnabled(true);
433                     reportGameOver();
434                     return;
435                 }
436                 //创建一个游戏块
437                 block = new ErsBlock(style, 0, col, getLevel(), canvas);
438                 block.start();
439 
440                 /*debug*/
441                 //System.out.println("new block");
442                     
443                 //生成下一个的列和类型
444                 col = (int) (Math.random()*(canvas.getCols() - 3));
445                 style = (int)ErsBlock.STYLES[(int)(Math.random()*7)][(int)(Math.random()*4)];
446                 ctrlPanel.setTipStyle(style);
447             }
448         }
449         
450         /*检查是否有填满的一行*/
451         public void checkFullLine() {
452             int i, j, row;//i最大的检查行次数
453             for(i = 0; i < canvas.getRows(); ++i) {
454                 row = -1; //需要移动的行
455                 boolean fullLineColorBox = true;
456                 for(j = 0; j < canvas.getCols(); ++j) {
457                     if(!canvas.getBox(i, j).isColorBox()) {
458                         fullLineColorBox = false;
459                         break;
460                     }
461                 }
462                 if(fullLineColorBox) {
463                     row = i--;
464                     canvas.removeLine(row); //i之上的行都在下移一行
465                 }
466             }
467         }
468 
469         private boolean isGameOver() {
470             for(int j = 0; j < canvas.getCols(); j++) {
471                 ErsBox box = canvas.getBox(0, j);
472                 if(box.isColorBox()) {
473                     /*debug*/
474                     System.out.println("isGameOver:why");
475                     return true;
476                 }
477             }
478             return false;
479         }
480     }
481 
482     public static void main(String[] args) {
483         new ErsBlocksGame("俄罗斯方块游戏");
484     }
485 }
View Code

makefile

 1 ErsBlocksGame.class:ControlPanel.class GameCanvas.class ErsBlock.class ErsBlocksGame.java
 2     javac -d . ErsBlocksGame.java
 3 ControlPanel.class:ErsBox.class ControlPanel.java
 4     javac -d . ControlPanel.java
 5 ErsBlock.class:ErsBox.class GameCanvas.class ErsBlock.java
 6     javac -d . ErsBlock.java
 7 GameCanvas.class: ErsBox.class GameCanvas.java
 8     javac -d . GameCanvas.java
 9 ErsBox.class:ErsBox.java
10     javac -d . ErsBox.java
11 clean:
12     rm *.class; rm Mypackage/*.class

 

posted @ 2015-08-15 20:16  Kinthon  阅读(533)  评论(0编辑  收藏  举报