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 }
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 }
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 }
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 }
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 }
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