1 packageersblockgamedemo;2
3 /**
4 *5 *@authorjiangnan3146 */
7 importjava.applet.Applet;8 importjava.applet.AudioClip;9 import java.awt.*;10 import java.awt.event.*;11 importjava.text.DateFormat;12 importjava.text.SimpleDateFormat;13 importjava.util.Date;14 import javax.swing.*;15 importjavax.swing.border.Border;16 importjavax.swing.border.EtchedBorder;17
18 /**
19 * 游戏主类,继承自JFrame类,负责游戏的全局控制。 内含: 1.一个GameCanvas画布类的实例对象,20 * 2.一个保存当前活动块(ErsBlock)实例的对象; 3.一个保存当前控制面板(ControlPanel)实例的对象;21 */
22 public class ErsBlocksGame extendsJFrame {23
24 /**
25 * 每填满一行计多少分26 */
27 public final static int PER_LINE_SCORE = 100;28 /**
29 * 积多少分以后能升级30 */
31 public final static int PER_LEVEL_SCORE = PER_LINE_SCORE * 20;32 /**
33 * 最大级数是10级34 */
35 public final static int MAX_LEVEL = 10;36 /**
37 * 默认级数是238 */
39 public final static int DEFAULT_LEVEL = 2;40 privateGameCanvas canvas;41 privateErsBlock block;42 private FileDialog dialog = new FileDialog(this);43 private boolean playing = false;44 privateAudioClip audioclip;45 privateControlPanel ctrlPanel;46 private JMenuBar bar = newJMenuBar();47 private JMenu mGame = new JMenu(” 游戏”),48 mControl = new JMenu(” 控制”),49 mWindowStyle = new JMenu(“游戏风格”),50 mMusic = new JMenu(“设置游戏音乐”),51 mInfo = new JMenu(“帮助”);52 private JMenuItem miNewGame = new JMenuItem(“新游戏”),53 miSetBlockColor = new JMenuItem(“设置方块颜色…”),54 miSetBackColor = new JMenuItem(“设置背景颜色…”),55 miTurnHarder = new JMenuItem(“升高游戏难度”),56 miTurnEasier = new JMenuItem(“降低游戏难度”),57 miExit = new JMenuItem(“退出”),58 miPlay = new JMenuItem(“开始”),59 miPause = new JMenuItem(“暂停”),60 miResume = new JMenuItem(“恢复”),61 miOpen = new JMenuItem(“打开”),62 playMusic = new JMenuItem(“播放”),63 stopMusic = new JMenuItem(“停止”),64 miStop = new JMenuItem(“终止游戏”),65 loopMusic = new JMenuItem(“循环”),66 miAuthor = new JMenuItem(“关于本游戏”);67 private JCheckBoxMenuItem miAsWindows = new JCheckBoxMenuItem(“Windows”),68 miAsMotif = new JCheckBoxMenuItem(“Motif”),69 miAsMetal = new JCheckBoxMenuItem(“Metal”, true);70
71 /**
72 * 主游戏类的构造方法73 *74 *@paramtitle String ,窗口标题75 */
76 publicErsBlocksGame(String title) {77 super(title); //设置标题
78 setSize(328, 405); //设置窗口大小
79 setLocationRelativeTo(null); //设置窗口居中
80
81 creatMenu();82 Container container =getContentPane();83 container.setLayout(new BorderLayout(6, 0)); //设置窗口的布局管理器
84 canvas = new GameCanvas(20, 15); //新建游戏画布
85 ctrlPanel = new ControlPanel(this); //新建控制面板
86 container.add(canvas, BorderLayout.CENTER); //左边加上画布
87 container.add(ctrlPanel, BorderLayout.EAST); //右边加上控制面板
88
89 addWindowListener(new WindowAdapter() { //注册窗口事件。当点击关闭按钮时,结束游戏,系统退出。
90 @Override91 public voidwindowClosing(WindowEvent we) {92 stopGame();93 System.exit(0);94 }95 });96 addComponentListener(newComponentAdapter() {97 @Override98 public voidcomponentResized(ComponentEvent ce) {99 canvas.fanning();100 }101 });102
103 setVisible(true);104 canvas.fanning();105
106
107 }108
109 /**
110 * 让游戏复位111 */
112 public void reset() { //画布复位,控制面板复位
113 ctrlPanel.setPlayButtonEnable(true);114 ctrlPanel.setPauseButtonEnable(false);115 ctrlPanel.setPauseButtonLabel(true);116 ctrlPanel.setStopButtonEnable(false);117 ctrlPanel.setTurnLevelDownButtonEnable(true);118 ctrlPanel.setTurnLevelUpButtonEnable(true);119 miPlay.setEnabled(true);120 miPause.setEnabled(false);121 miResume.setEnabled(false);122 miStop.setEnabled(false);123 ctrlPanel.reset();124 canvas.reset();125 }126
127 /**
128 * 判断游戏是否还在进行129 *130 *@returnboolean,true -还在运行,false-已经停止131 */
132 public booleanisPlaying() {133 returnplaying;134 }135
136 /**
137 * 得到当前活动的块138 *139 *@returnErsBlock,当前活动块的引用140 */
141 publicErsBlock getCurBlock() {142 returnblock;143 }144
145 /**
146 * 得到当前画布147 *148 *@returnGameCanvas,当前画布的引用149 */
150 publicGameCanvas getCanvas() {151 returncanvas;152 }153
154 /**
155 * 开始游戏156 */
157 public voidplayGame() {158 play();159 ctrlPanel.setPlayButtonEnable(false);160 ctrlPanel.setPauseButtonEnable(true);161 ctrlPanel.setPauseButtonLabel(true);162 ctrlPanel.setStopButtonEnable(true);163 ctrlPanel.setTurnLevelDownButtonEnable(false);164 ctrlPanel.setTurnLevelUpButtonEnable(false);165 miPlay.setEnabled(false);166 miPause.setEnabled(true);167 miResume.setEnabled(false);168 miStop.setEnabled(true);169 miTurnHarder.setEnabled(false);170 miTurnEasier.setEnabled(false);171 ctrlPanel.requestFocus(); //设置焦点
172 }173
174 /**
175 * 游戏暂停176 */
177 public voidpauseGame() {178 if (block != null) {179 block.pauseMove();180 }181 ctrlPanel.setPlayButtonEnable(false);182 ctrlPanel.setPauseButtonLabel(false);183 ctrlPanel.setStopButtonEnable(true);184 miPlay.setEnabled(false);185 miPause.setEnabled(false);186 miResume.setEnabled(true);187 miStop.setEnabled(true);188 }189
190 /**
191 * 让暂停中的游戏继续192 */
193 public voidresumeGame() {194 if (block != null) {195 block.resumeMove();196 }197 ctrlPanel.setPlayButtonEnable(false);198 ctrlPanel.setPauseButtonEnable(true);199 ctrlPanel.setPauseButtonLabel(true);200 miPause.setEnabled(true);201 miResume.setEnabled(false);202 ctrlPanel.requestFocus();203 }204
205 /**
206 * 用户停止游戏207 */
208 public voidstopGame() {209 playing = false;210 if (block != null) {211 block.stopMove();212 }213 ctrlPanel.setPlayButtonEnable(true);214 ctrlPanel.setPauseButtonEnable(false);215 ctrlPanel.setPauseButtonLabel(true);216 ctrlPanel.setStopButtonEnable(false);217 ctrlPanel.setTurnLevelDownButtonEnable(true);218 ctrlPanel.setTurnLevelUpButtonEnable(true);219 miPlay.setEnabled(true);220 miPause.setEnabled(false);221 miResume.setEnabled(false);222 miStop.setEnabled(false);223 miTurnHarder.setEnabled(true);224 miTurnEasier.setEnabled(true);225 }226
227 publicAudioClip getAudioClip() {228 returnaudioclip;229 }230
231 public voidsetAudioClip(AudioClip clip) {232 this.audioclip =clip;233 }234
235 public voidplayAudio() {236 if (audioclip != null) {237 audioclip.play();238 }239 }240
241 public voidloop() {242 if (audioclip != null) {243 loop();244 }245 }246
247 public voidstop() {248 if (audioclip != null) {249 stop();250 }251 }252
253 /**
254 * 得到游戏者设置的难度255 *256 *@returnint ,游戏难度1-MAX_LEVEL257 */
258 public intgetLevel() {259 returnctrlPanel.getLevel();260 }261
262 /**
263 * 用户设置游戏难度264 *265 *@paramlevel int ,游戏难度1-MAX_LEVEL266 */
267 public void setLevel(intlevel) {268 if (level < 11 && level > 0) {269 ctrlPanel.setLevel(level);270 }271 }272
273 /**
274 * 得到游戏积分275 *276 *@returnint,积分277 */
278 public intgetScore() {279 if (canvas != null) {280 returncanvas.getScore();281 }282 return 0;283 }284
285 /**
286 * 得到自上次升级以来的游戏积分,升级以后,此积分清零287 *288 *@returnint,积分289 */
290 public intgetScoreForLevelUpdate() {291 if (canvas != null) {292 returncanvas.getScoreForLevelUpdate();293 }294 return 0;295 }296
297 /**
298 * 当积分累积到一定数值时,升一次级299 *300 *@returnBoolean,true-update succeed,false-update fail301 */
302 public booleanlevelUpdate() {303 int curLevel =getLevel();304 if (curLevel
312 /**
313 * 游戏开始314 */
315 private voidplay() {316 reset();317 playing = true;318 Thread thread = new Thread(newGame());319 thread.start();320 }321
322 /**
323 * 报告游戏结束了324 */
325 private voidreportGameOver() {326 new gameOverDialog(this, “俄罗斯方块”, “游戏结束,您的得分为” +canvas.getScore());327 }328
329 /**
330 * 建立并设置窗口菜单331 */
332 private voidcreatMenu() {333 bar.add(mGame);334 bar.add(mControl);335 bar.add(mWindowStyle);336 bar.add(mMusic);337 bar.add(mInfo);338 mGame.add(miNewGame);339 mGame.addSeparator();340 mGame.add(miSetBlockColor);341 mGame.add(miSetBackColor);342 mGame.addSeparator();343 mGame.add(miTurnHarder);344 mGame.add(miTurnEasier);345 mGame.addSeparator();346 mGame.add(miExit);347 mControl.add(miPlay);348 miPlay.setEnabled(true);349 mControl.add(miPause);350 miPause.setEnabled(false);351 mControl.add(miResume);352 miResume.setEnabled(false);353 mControl.add(miStop);354 miStop.setEnabled(false);355 mWindowStyle.add(miAsWindows);356 mWindowStyle.add(miAsMotif);357 mWindowStyle.add(miAsMetal);358 mMusic.add(miOpen);359 mMusic.add(playMusic);360 mMusic.add(stopMusic);361 mMusic.add(loopMusic);362 mInfo.add(miAuthor);363 setJMenuBar(bar);364
365 miPause.setAccelerator(KeyStroke.getKeyStroke(366 KeyEvent.VK_P, KeyEvent.CTRL_MASK));367 miResume.setAccelerator(KeyStroke.getKeyStroke(368 KeyEvent.VK_R, KeyEvent.CTRL_MASK));369
370 miNewGame.addActionListener(newActionListener() {371 @Override372 public voidactionPerformed(ActionEvent e) {373 stopGame();374 reset();375 setLevel(DEFAULT_LEVEL);376 }377 });378 miSetBlockColor.addActionListener(newActionListener() {379 @Override380 public voidactionPerformed(ActionEvent e) {381 Color newFrontColor =
382 JColorChooser.showDialog(ErsBlocksGame.this, “设置方块颜色”, canvas.getBlockColor());383 if (newFrontColor != null) {384 canvas.setBlockColor(newFrontColor);385 }386 }387 });388 miSetBackColor.addActionListener(newActionListener() {389 @Override390 public voidactionPerformed(ActionEvent e) {391 Color newBackColor =
392 JColorChooser.showDialog(ErsBlocksGame.this, “设置背景颜色”, canvas.getBackgroundColor());393 if (newBackColor != null) {394 canvas.setBackgroundColor(newBackColor);395 }396 }397 });398 miAuthor.addActionListener(new ActionListener() { //定义菜单栏”关于”的功能,弹出确认框。
399 @Override400 public voidactionPerformed(ActionEvent e) {401 JOptionPane.showMessageDialog(null, “© Copyright 姜楠-张卓\n” + ” All Rights Reserved.”, “关于俄罗斯方块 – 2013”, 1);402 }403 });404 miTurnHarder.addActionListener(newActionListener() {405 @Override406 public voidactionPerformed(ActionEvent e) {407 int curLevel =getLevel();408 if (!playing && curLevel 1) {418 setLevel(curLevel – 1);419 }420 }421 });422 miExit.addActionListener(newActionListener() {423 @Override424 public voidactionPerformed(ActionEvent e) {425 System.exit(0);426 }427 });428 miPlay.addActionListener(newActionListener() {429 @Override430 public voidactionPerformed(ActionEvent e) {431 playGame();432 }433 });434 miPause.addActionListener(newActionListener() {435 @Override436 public voidactionPerformed(ActionEvent e) {437 pauseGame();438 }439 });440 miResume.addActionListener(newActionListener() {441 @Override442 public voidactionPerformed(ActionEvent e) {443 resumeGame();444 }445 });446 miStop.addActionListener(newActionListener() {447 @Override448 public voidactionPerformed(ActionEvent e) {449 stopGame();450 }451 });452 miOpen.addActionListener(newActionListener() {453 @Override454 public voidactionPerformed(ActionEvent e) {455 dialog.setVisible(true);456 if (dialog.getFile() != null) {457 String filename = dialog.getDirectory() +dialog.getFile();458 try{459 setAudioClip(Applet.newAudioClip((newjava.io.File(filename)).toURI().toURL()));460 playAudio();461 } catch(Exception ex) {462 ex.printStackTrace();463 }464 }465 }466 });467 playMusic.addActionListener(newActionListener() {468 @Override469 public voidactionPerformed(ActionEvent e) {470 playAudio();471 playMusic.setEnabled(false);472 stopMusic.setEnabled(true);473 }474 });475 stopMusic.addActionListener(newActionListener() {476 @Override477 public voidactionPerformed(ActionEvent e) {478 stop();479 }480 });481 loopMusic.addActionListener(newActionListener() {482 @Override483 public voidactionPerformed(ActionEvent e) {484 loop();485 }486 });487 miAsWindows.addActionListener(new ActionListener() { //改变游戏风格,Windows风格,motif风格,metal风格
488 @Override489 public voidactionPerformed(ActionEvent ae) {490 String plaf = “com.sun.java.swing.plaf.windows.WindowsLookAndFeel”;491 setWindowStyle(plaf);492 canvas.fanning(); //以新的界面风格的重新绘制画布和控制面板
493 ctrlPanel.fanning();494 miAsWindows.setState(true); //495 miAsMetal.setState(false);496 miAsMotif.setState(false);497 }498 });499 miAsMotif.addActionListener(newActionListener() {500 @Override501 public voidactionPerformed(ActionEvent e) {502 String plaf = “com.sun.java.swing.plaf.motif.MotifLookAndFeel”;503 setWindowStyle(plaf);504 canvas.fanning();505 ctrlPanel.fanning();506 miAsWindows.setState(false);507 miAsMetal.setState(false);508 miAsMotif.setState(true);509 }510 });511 miAsMetal.addActionListener(newActionListener() {512 @Override513 public voidactionPerformed(ActionEvent e) {514 String plaf = “javax.swing.plaf.metal.MetalLookAndFeel”;515 setWindowStyle(plaf);516 canvas.fanning();517 ctrlPanel.fanning();518 miAsWindows.setState(false);519 miAsMetal.setState(true);520 miAsMotif.setState(false);521 }522 });523
524
525 }526
527 /**
528 * 根据字串设置窗口外观529 *530 *@paramplaf String,窗口外观的描述531 */
532 private voidsetWindowStyle(String plaf) {533 try{534 UIManager.setLookAndFeel(plaf);535 SwingUtilities.updateComponentTreeUI(this);536 } catch(Exception e) {537 }538 }539
540 /**
541 * 一轮游戏过程,实现了Runnable接口 一轮游戏是一个大循环,在这个循环中,每隔100毫秒, 检查游戏中的当前块是否已经到底了,如果没有,542 * 就继续等待。如果到底了,就看有没有全填满的行, 如果有就删除它,并为游戏者加分,同时随机产生一个 新的当前块人 让它自动落下。543 * 当新产生一个块时,先检查画布最顶上的一行是否已经 被占了,如果是,可以判断Game Over 了。544 */
545 private class Game implementsRunnable {546
547 @Override548 public voidrun() {549 int col = (int) (Math.random() * (canvas.getCols() – 3));550 int style = ErsBlock.STYLES[ (int) (Math.random() * 7)][(int) (Math.random() * 4)];551
552 while(playing) {553 if (block != null) { //第一次循环时,block为空
554 if(block.isAlive()) {555 try{556 Thread.currentThread().sleep(500);557 } catch(InterruptedException ie) {558 ie.printStackTrace();559 }560 continue;561 }562 }563
564 checkFullLine(); //检查是否有全填满的行
565
566 if(isGameOver()) {567 reportGameOver();568 miPlay.setEnabled(true);569 miPause.setEnabled(false);570 miResume.setEnabled(false);571 miStop.setEnabled(false);572 ctrlPanel.setPlayButtonEnable(true);573 ctrlPanel.setPauseButtonLabel(false);574 ctrlPanel.setStopButtonEnable(false);575 return;576 }577
578 block = new ErsBlock(style, -1, col, getLevel(), canvas);579 block.start();580
581 col = (int) (Math.random() * (canvas.getCols() – 3));582 style = ErsBlock.STYLES[ (int) (Math.random() * 7)][(int) (Math.random() * 4)];583
584 ctrlPanel.setTipStyle(style);585 }586 }587
588 //检查画布中是否有全填满的行,如果有就删之
589 public voidcheckFullLine() {590 for (int i = 0; i < canvas.getRows(); i++) {591 int row = -1;592 boolean fullLineColorBox = true;593 for (int j = 0; j < canvas.getCols(); j++) {594 if (!canvas.getBox(i, j).isColorBox()) {595 fullLineColorBox = false;596 break;597 }598 }599 if(fullLineColorBox) {600 row = i–;601 canvas.removeLine(row);602 }603 }604 }605
606 //根据最顶行是否被占,判断游戏是否已经结束了607 //@return boolean ,true-游戏结束了,false-游戏未结束
608 private booleanisGameOver() {609 for (int i = 0; i < canvas.getCols(); i++) {610 ErsBox box = canvas.getBox(0, i);611 if(box.isColorBox()) {612 return true;613 }614 }615 return false;616 }617 }618
619 /**
620 * 定义GameOver对话框。621 */
622 private class gameOverDialog extends JDialog implementsActionListener {623
624 privateJButton againButton, exitButton;625 private Border border = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140));626
627 publicgameOverDialog(JFrame parent, String title, String message) {628 super(parent, title, true);629 if (parent != null) {630 setSize(240, 120);631 this.setLocationRelativeTo(parent);632 JPanel messagePanel = newJPanel();633 messagePanel.add(newJLabel(message));634 messagePanel.setBorder(border);635 Container container = this.getContentPane();636 container.setLayout(new GridLayout(2, 0, 0, 10));637 container.add(messagePanel);638 JPanel choosePanel = newJPanel();639 choosePanel.setLayout(new GridLayout(0, 2, 4, 0));640 container.add(choosePanel);641 againButton = new JButton(“再玩一局”);642 exitButton = new JButton(“退出游戏”);643 choosePanel.add(newJPanel().add(againButton));644 choosePanel.add(newJPanel().add(exitButton));645 choosePanel.setBorder(border);646 }647 againButton.addActionListener(this);648 exitButton.addActionListener(this);649 this.setVisible(true);650 }651
652 @Override653 public voidactionPerformed(ActionEvent e) {654 if (e.getSource() ==againButton) {655 this.setVisible(false);656 reset();657 } else if (e.getSource() ==exitButton) {658 stopGame();659 System.exit(0);660
661 }662 }663 }664
665 /**
666 * 程序入口函数667 *668 *@paramargs String[],附带的命令行参数669 */
670 public static voidmain(String[] args) {671 new ErsBlocksGame(“俄罗斯方块:ZJUT-CS&T”);672 }673 }674
675 /**
676 * 画布类,内有* 个方格类实例。 继承自JPanel类。 ErsBlock线程类动态改变画布类的方格颜色,画布类通过677 * 检查方格颜色来体现ErsBlock块的移动情况。678 */
679 class GameCanvas extendsJPanel {680
681 private Color backColor = Color.LIGHT_GRAY, frontColor =Color.orange;682 private int rows, cols, score = 0, scoreForLevelUpdate = 0;683 privateErsBox[][] boxes;684 private intboxWidth, boxHeight;685
686 /**
687 * 画布类的构造函数688 *689 *@paramrows int,画布的行数690 *@paramcols int,画布的列数 行数和列数决定着画布拥有方格的数目691 */
692 public GameCanvas(int rows, intcols) {693 this.rows =rows;694 this.cols =cols;695
696 boxes = newErsBox[rows][cols];697 for (int i = 0; i < boxes.length; i++) {698 for (int j = 0; j < boxes[i].length; j++) {699 boxes[i][j] = new ErsBox(false);700 }701 }702
703 setBorder(new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140)));704 }705
706 /**
707 * 画布类的构造函数708 *709 *@paramrows710 *@paramcols711 *@parambackColor712 *@paramfrontColor713 */
714 public GameCanvas(int rows, intcols,715 Color backColor, Color frontColor) {716 this(rows, cols);717 this.backColor =backColor;718 this.frontColor =frontColor;719 }720
721 /**
722 * 设置游戏背景色彩723 *724 *@parambackColor Color,背景色彩725 */
726 public voidsetBackgroundColor(Color backColor) {727 this.backColor =backColor;728 }729
730 /**
731 * 取得游戏背景色彩732 *733 *@returnColor ,背景色彩734 */
735 publicColor getBackgroundColor() {736 returnbackColor;737 }738
739 /**
740 * 设置游戏方块颜色741 *742 *@paramfrontColor Color,方块颜色743 */
744 public voidsetBlockColor(Color frontColor) {745 this.frontColor =frontColor;746 }747
748 /**
749 * 取得游戏方块色彩750 *751 *@returnColor,方块颜色752 */
753 publicColor getBlockColor() {754 returnfrontColor;755 }756
757 /**
758 * 取得画布中方格的列数759 *760 *@return
761 */
762 public intgetRows() {763 returnrows;764 }765
766 /**
767 * 取得画布中方格的行数768 *769 *@returnint,方格的行数770 */
771 public intgetCols() {772 returncols;773 }774
775 /**
776 * 取得游戏成绩777 *778 *@returnint, 分数779 */
780 public intgetScore() {781 returnscore;782 }783
784 /**
785 * 取得自上一次升级后的积分786 *787 *@returnint ,上一次升级后的积分788 */
789 public intgetScoreForLevelUpdate() {790 returnscoreForLevelUpdate;791 }792
793 /**
794 * 升级后,将上一次升级以来的积分清零795 */
796 public voidresetScoreForLevelUpdate() {797 scoreForLevelUpdate -=ErsBlocksGame.PER_LEVEL_SCORE;798 }799
800 /**
801 * 得到某一行某一列的方格引用802 *803 *@returnrow int ,要引用的方格所在的行804 *@paramcol int, 要引用的方格所在的行805 *@returnErsBox,在row行col列的方格的引用806 */
807 public ErsBox getBox(int row, intcol) {808 if (row < 0 || row > boxes.length – 1 || col < 0 || col > boxes[0].length – 1) {809 return null;810 }811 return(boxes[row][col]);812 }813
814 /**
815 * 覆盖JComponent类的函数,画组件。816 *817 *@paramg 图形设备环境818 */
819 @Override820 public voidpaintComponent(Graphics g) {821 super.paintComponent(g);822
823 g.setColor(frontColor);824 for (int i = 0; i < boxes.length; i++) {825 for (int j = 0; j < boxes[i].length; j++) {826 g.setColor(boxes[i][j].isColorBox() ?frontColor : backColor);827 g.fill3DRect(j * boxWidth, i *boxHeight,828 boxWidth, boxHeight, true);829 }830 }831 }832
833 /**
834 * 根据窗口大小,自动调节方格的尺寸835 */
836 public voidfanning() {837 boxWidth = getSize().width /cols;838 boxHeight = getSize().height /rows;839 }840
841 /**
842 * 当一行被游戏者叠满后,将此行清除,并为游戏者加分843 *844 *@paramrow int,要清除的行,是由ErsBoxesGame类计算的845 */
846 public synchronized void removeLine(introw) {847 for (int i = row; i > 0; i–) {848 for (int j = 0; j < cols; j++) {849 boxes[i][j] = (ErsBox) boxes[i – 1][j].clone(); //将上一行的方块颜色克隆下来,
850 } //即消去一行方块
851 }852
853 score +=ErsBlocksGame.PER_LEVEL_SCORE;854 scoreForLevelUpdate +=ErsBlocksGame.PER_LEVEL_SCORE;855 repaint();856 }857
858 /**
859 * 重置画布,置积分为零860 */
861 public voidreset() {862 score = 0;863 scoreForLevelUpdate = 0;864 for (int i = 0; i < boxes.length; i++) {865 for (int j = 0; j < boxes[i].length; j++) {866 boxes[i][j].setColor(false);867 }868 }869
870 repaint();871 }872 }873
874 /**
875 * 方格类,是组成块的基本元素,用自己的颜色来表示块的外观876 */
877 class ErsBox implementsCloneable {878
879 private booleanisColor;880 private Dimension size = newDimension();881
882 /**
883 * 方格类的构造函数,884 *885 *@paramisColor 是不是用前景色来为此方格着色 true前景色,false 用背景色886 */
887 public ErsBox(booleanisColor) {888 this.isColor =isColor;889 }890
891 /**
892 * 此方格是不是用前景色表现893 *894 *@returnboolean ,true用前景色表现,false 用背景色表现895 */
896 public booleanisColorBox() {897 returnisColor;898 }899
900 /**
901 * 设置方格的颜色,902 *903 *@paramisColor boolean ,true用前景色表现,false 用背景色表现904 */
905 public void setColor(booleanisColor) {906 this.isColor =isColor;907 }908
909 /**
910 * 得到此方格的尺寸911 *912 *@returnDimension ,方格的尺寸913 */
914 publicDimension getSize() {915 returnsize;916 }917
918 /**
919 * 设置方格的尺寸,920 *921 *@paramsize Dimension ,方格的尺寸922 */
923 public voidsetSize(Dimension size) {924 this.size =size;925 }926
927 /**
928 * 覆盖Object的Object clone(),实现克隆929 *930 *@returnObject,克隆的结果931 */
932 @Override933 publicObject clone() {934 Object cloned = null;935 try{936 cloned = super.clone();937 } catch(Exception ex) {938 ex.printStackTrace();939 }940
941 returncloned;942 }943 }944
945 /**
946 * 块类,继承自线程类(Thread) 由4 × 4个方块(ErsBox)构成一个方块, 控制块的移动·下落·变形等947 */
948 class ErsBlock extendsThread {949
950 /**
951 * 一个块占的行数是4行952 */
953 public final static int BOXES_ROWS = 4;954 /**
955 * 一个块占的列数是4列956 */
957 public final static int BOXES_COLS = 4;958 /**
959 * 让升级变化平滑的因子,避免最后几级之间的速度相差近一倍960 */
961 public final static int LEVEL_FLATNESS_GENE = 3;962 /**
963 * 相近的两级之间,块每下落一行的时间差别为多少(毫秒)964 */
965 public final static int BETWEEN_LEVELS_DEGRESS_TIME = 50;966 /**
967 * 方块的样式数目为7968 */
969 public final static int BLOCK_KIND_NUMBER = 7;970 /**
971 * 每一个样式的方块的反转状态种类为4972 */
973 public final static int BLOCK_STATUS_NUMBER = 4;974 /**
975 * 分别对应7种模型的28种状态976 */
977 public final static int[][] STYLES = { //共28种状态
978 {0x0f00, 0x4444, 0x0f00, 0x4444}, //长条型的四种状态
979 {0x04e0, 0x0464, 0x00e4, 0x04c4}, //T型的四种状态
980 {0x4620, 0x6c00, 0x4620, 0x6c00}, //反Z型的四种状态
981 {0x2640, 0xc600, 0x2640, 0xc600}, //Z型的四种状态
982 {0x6220, 0x1700, 0x2230, 0x0740}, //7型的四种状态
983 {0x6440, 0x0e20, 0x44c0, 0x8e00}, //反7型的四种状态
984 {0x0660, 0x0660, 0x0660, 0x0660}, //方块的四种状态
985 };986 privateGameCanvas canvas;987 private ErsBox[][] boxes = newErsBox[BOXES_ROWS][BOXES_COLS];988 private intstyle, y, x, level;989 private boolean pausing = false, moving = true;990
991 /**
992 * 构造函数,产生一个特定的块993 *994 *@paramstyle 块的样式,对应STYLES的28个值中的一个995 *@paramy 起始位置,左上角在canvas中的坐标行996 *@paramx 起始位置,左上角在canvas中的坐标lie997 *@paramlevel 游戏等级,控制块的下落速度998 *@paramcanvas 画板999 */
1000 public ErsBlock(int style, int y, int x, intlevel, GameCanvas canvas) {1001 this.style =style;1002 this.y =y;1003 this.x =x;1004 this.level =level;1005 this.canvas =canvas;1006
1007 int key = 0x8000;1008 for (int i = 0; i < boxes.length; i++) {1009 for (int j = 0; j < boxes[i].length; j++) {1010 boolean isColor = ((style & key) != 0);1011 boxes[i][j] = newErsBox(isColor);1012 key >>= 1;1013 }1014 }1015
1016 display();1017 }1018
1019 /**
1020 * 线程类的run()函数覆盖,下落块,直到块不能再下落1021 */
1022 @Override1023 public voidrun() {1024 while(moving) {1025 try{1026 sleep(BETWEEN_LEVELS_DEGRESS_TIME1027 * (ErsBlocksGame.MAX_LEVEL – level +LEVEL_FLATNESS_GENE));1028 } catch(InterruptedException ie) {1029 ie.printStackTrace();1030 }1031 //后边的moving是表示在等待的100毫秒间,moving没有被改变
1032 if (!pausing) {1033 moving = (moveTo(y + 1, x) &&moving);1034 }1035 }1036 }1037
1038 /**
1039 * 块向左移动一格1040 */
1041 public voidmoveLeft() {1042 moveTo(y, x – 1);1043 }1044
1045 /**
1046 * 块向右移动一格1047 */
1048 public voidmoveRight() {1049 moveTo(y, x + 1);1050 }1051
1052 /**
1053 * 块向下移动一格1054 */
1055 public voidmoveDown() {1056 moveTo(y + 1, x);1057 }1058
1059 /**
1060 * 块变型1061 */
1062 public voidturnNext() {1063 for (int i = 0; i < BLOCK_KIND_NUMBER; i++) {1064 for (int j = 0; j < BLOCK_STATUS_NUMBER; j++) {1065 if (STYLES[i][j] ==style) {1066 int newStyle = STYLES[i][(j + 1) %BLOCK_STATUS_NUMBER];1067 turnTo(newStyle);1068 return;1069 }1070 }1071 }1072 }1073
1074 public voidstartMove() {1075 pausing = false;1076 moving = true;1077 }1078
1079 /**
1080 * 暂停块的下落,对应游戏暂停1081 */
1082 public voidpauseMove() {1083 pausing = true;1084 //moving = false;
1085 }1086
1087 /**
1088 * 继续块的下落,对应游戏继续1089 */
1090 public voidresumeMove() {1091 pausing = false;1092 moving = true;1093 }1094
1095 /**
1096 * 停止块的下落,对应游戏停止1097 */
1098 public voidstopMove() {1099 pausing = false;1100 moving = false;1101 }1102
1103 /**
1104 * 将当前块从画布的对应位置移除,要等到下次重画画布时才能反映出来1105 */
1106 private voiderase() {1107 for (int i = 0; i < boxes.length; i++) {1108 for (int j = 0; j < boxes[i].length; j++) {1109 if(boxes[i][j].isColorBox()) {1110 ErsBox box = canvas.getBox(i + y, j +x);1111 if (box == null) {1112 continue;1113 }1114 box.setColor(false);1115 }1116 }1117 }1118 }1119
1120 /**
1121 * 让当前块放置在画布的对因位置上,要等到下次重画画布时才能看见1122 */
1123 private voiddisplay() {1124 for (int i = 0; i < boxes.length; i++) {1125 for (int j = 0; j < boxes[i].length; j++) {1126 if(boxes[i][j].isColorBox()) {1127 ErsBox box = canvas.getBox(i + y, j +x);1128 if (box == null) {1129 continue;1130 }1131 box.setColor(true);1132 }1133 }1134 }1135 }1136
1137 /**
1138 * 当前块能否移动到newRow/newCol 所指定的位置1139 *1140 *@paramnewRow int,目的地所在行1141 *@paramnewCol int,目的地所在列1142 *@returnboolean,true-能移动,false-不能移动1143 */
1144 public boolean isMoveAble(int newRow, intnewCol) {1145 erase();1146 for (int i = 0; i < boxes.length; i++) {1147 for (int j = 0; j < boxes[i].length; j++) {1148 if(boxes[i][j].isColorBox()) {1149 ErsBox box = canvas.getBox(i + newRow, j +newCol);1150 if (box == null ||(box.isColorBox())) {1151 display();1152 return false;1153 }1154 }1155 }1156 }1157 display();1158 return true;1159 }1160
1161 /**
1162 * 将当前块移动到newRow/newCol 所指定的位置1163 *1164 *@paramnewRow int,目的地所在行1165 *@paramnewCol int,目的地所在列1166 *@returnboolean,true-移动成功,false-移动失败1167 */
1168 private synchronized boolean moveTo(int newRow, intnewCol) {1169 if (!isMoveAble(newRow, newCol) || !moving) {1170 return false;1171 }1172
1173 erase();1174 y =newRow;1175 x =newCol;1176
1177 display();1178 canvas.repaint();1179
1180 return true;1181 }1182
1183 /**
1184 * 当前块能否变成newStyle所指定的块样式,主要是考虑 边界以及被其他块挡住,不能移动的情况1185 *1186 *@paramnewSytle int,希望改变的块样式,对应STYLES的28个值中的一个1187 *@returnboolean,true-能改变,false-不能改变1188 */
1189 private boolean isTurnAble(intnewStyle) {1190 int key = 0x8000;1191 erase();1192 for (int i = 0; i < boxes.length; i++) {1193 for (int j = 0; j < boxes[i].length; j++) {1194 if ((newStyle & key) != 0) {1195 ErsBox box = canvas.getBox(i + y, j +x);1196 if (box == null ||(box.isColorBox())) {1197 display();1198 return false;1199 }1200 }1201 key >>= 1;1202 }1203 }1204 display();1205 return true;1206 }1207
1208 /**
1209 * 将当前块变成newStyle所指定的块样式1210 *1211 *@paramnewStyle int,希望改变的块样式,对应STYLES的28个值中的一个1212 *@returntrue-改变成功,false-改变失败1213 */
1214 private boolean turnTo(intnewStyle) {1215 if (!isTurnAble(newStyle) || !moving) {1216 return false;1217 }1218
1219 erase();1220 int key = 0x8000;1221 for (int i = 0; i < boxes.length; i++) {1222 for (int j = 0; j < boxes[i].length; j++) {1223 boolean isColor = ((newStyle & key) != 0);1224 boxes[i][j].setColor(isColor);1225 key >>= 1;1226 }1227 }1228 style =newStyle;1229
1230 display();1231 canvas.repaint();1232
1233 return true;1234 }1235 }1236
1237 /**
1238 * 控制面板类,继承自JPanel。 上边安放预显窗口,等级,得分,控制按钮 主要用来控制游戏进程。1239 */
1240 class ControlPanel extendsJPanel {1241
1242 private JTextField tfLevel = new JTextField(“” +ErsBlocksGame.DEFAULT_LEVEL),1243 tfScore = new JTextField(” 0″),1244 tfTime = new JTextField(” “);1245 private JButton btPlay = new JButton(” 开始”),1246 btPause = new JButton(” 暂停”),1247 btStop = new JButton(“终止游戏”),1248 btTurnLevelUp = new JButton(” 增加难度”),1249 btTurnLevelDown = new JButton(” 降低难度”);1250 private JPanel plTip = new JPanel(newBorderLayout());1251 private TipPanel plTipBlock = newTipPanel();1252 private JPanel plInfo = new JPanel(new GridLayout(4, 1));1253 private JPanel plButton = new JPanel(new GridLayout(6, 1));1254 privateTimer timer;1255 privateErsBlocksGame game;1256 private Border border = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(148, 145, 140));1257
1258 /**
1259 * 控制面板类的构造函数1260 *1261 *@paramgame ErsBlocksGame,ErsBlocksGame 类的一个实例引用 方便直接控制ErsBlocksGame类的行为。1262 */
1263 public ControlPanel(finalErsBlocksGame game) {1264 setLayout(new GridLayout(3, 1, 0, 2));1265 this.game =game;1266
1267 plTip.add(new JLabel(” 下一个方块”), BorderLayout.NORTH); //添加组件
1268 plTip.add(plTipBlock);1269 plTip.setBorder(border);1270
1271 plInfo.add(new JLabel(” 难度系数”));1272 plInfo.add(tfLevel);1273 plInfo.add(new JLabel(” 得分”));1274 plInfo.add(tfScore);1275 plInfo.setBorder(border);1276
1277 plButton.add(btPlay);1278 btPlay.setEnabled(true);1279 plButton.add(btPause);1280 btPause.setEnabled(false);1281 plButton.add(btStop);1282 btStop.setEnabled(false);1283 plButton.add(btTurnLevelUp);1284 plButton.add(btTurnLevelDown);1285 plButton.add(tfTime);1286 plButton.setBorder(border);1287
1288 tfLevel.setEditable(false);1289 tfScore.setEditable(false);1290 tfTime.setEditable(false);1291
1292 add(plTip);1293 add(plInfo);1294 add(plButton);1295
1296 addKeyListener(newKeyAdapter() {1297 @Override1298 public voidkeyPressed(KeyEvent ke) {1299 if (!game.isPlaying()) {1300 return;1301 }1302
1303 ErsBlock block =game.getCurBlock();1304 switch(ke.getKeyCode()) {1305 caseKeyEvent.VK_DOWN:1306 block.moveDown();1307 break;1308 caseKeyEvent.VK_LEFT:1309 block.moveLeft();1310 break;1311 caseKeyEvent.VK_RIGHT:1312 block.moveRight();1313 break;1314 caseKeyEvent.VK_UP:1315 block.turnNext();1316 break;1317 default:1318 break;1319 }1320 }1321 });1322
1323 btPlay.addActionListener(new ActionListener() { //开始游戏
1324 @Override1325 public voidactionPerformed(ActionEvent ae) {1326 game.playGame();1327 }1328 });1329 btPause.addActionListener(new ActionListener() { //暂停游戏
1330 @Override1331 public voidactionPerformed(ActionEvent ae) {1332 if (btPause.getText().equals(” 暂停”)) {1333 game.pauseGame();1334 } else{1335 game.resumeGame();1336 }1337 }1338 });1339 btStop.addActionListener(new ActionListener() { //停止游戏
1340 @Override1341 public voidactionPerformed(ActionEvent ae) {1342 game.stopGame();1343 }1344 });1345 btTurnLevelUp.addActionListener(new ActionListener() { //升高难度
1346 @Override1347 public voidactionPerformed(ActionEvent ae) {1348 try{1349 int level =Integer.parseInt(tfLevel.getText());1350 if (level
1359 @Override1360 public voidactionPerformed(ActionEvent ae) {1361 try{1362 int level =Integer.parseInt(tfLevel.getText());1363 if (level > 1) {1364 tfLevel.setText(“” + (level – 1));1365 }1366 } catch(NumberFormatException e) {1367 }1368 requestFocus();1369 }1370 });1371
1372 addComponentListener(newComponentAdapter() {1373 @Override1374 public voidcomponentResized(ComponentEvent ce) {1375 plTipBlock.fanning();1376 }1377 });1378
1379 timer = new Timer(1000, newActionListener() {1380 @Override1381 public voidactionPerformed(ActionEvent ae) {1382 DateFormat format = new SimpleDateFormat(“时间:HH:mm:ss”); //系统获得时间
1383 Date date = newDate();1384 tfTime.setText(format.format(date));1385
1386 tfScore.setText(“” +game.getScore());1387 int ScoreForLevelUpdate = //判断当前分数是否能升级
1388 game.getScoreForLevelUpdate();1389 if (ScoreForLevelUpdate >=ErsBlocksGame.PER_LEVEL_SCORE1390 && ScoreForLevelUpdate > 0) {1391 game.levelUpdate();1392 }1393 }1394 });1395 timer.start();1396 }1397
1398 /**
1399 * 设置预显窗口的样式1400 *1401 *@paramstyle int,对应ErsBlock类的STYLES中的28个值1402 */
1403 public void setTipStyle(intstyle) {1404 plTipBlock.setStyle(style);1405 }1406
1407 /**
1408 * 取得用户设置的游戏等级。1409 *1410 *@returnint ,难度等级,1-ErsBlocksGame.MAX_LEVEL1411 */
1412 public intgetLevel() {1413 int level = 0;1414 try{1415 level =Integer.parseInt(tfLevel.getText());1416 } catch(NumberFormatException e) {1417 }1418 returnlevel;1419 }1420
1421 /**
1422 * 让用户修改游戏难度等级。1423 *1424 *@paramlevel 修改后的游戏难度等级1425 */
1426 public void setLevel(intlevel) {1427 if (level > 0 && level < 11) {1428 tfLevel.setText(“” +level);1429 }1430 }1431
1432 /**
1433 * 设置“开始”按钮的状态。1434 */
1435 public void setPlayButtonEnable(booleanenable) {1436 btPlay.setEnabled(enable);1437 }1438
1439 public void setPauseButtonEnable(booleanenable) {1440 btPause.setEnabled(enable);1441 }1442
1443 public void setPauseButtonLabel(booleanpause) {1444 btPause.setText(pause ? ” 暂停” : ” 继续”);1445 }1446
1447 public void setStopButtonEnable(booleanenable) {1448 btStop.setEnabled(enable);1449 }1450
1451 public void setTurnLevelUpButtonEnable(booleanenable) {1452 btTurnLevelUp.setEnabled(enable);1453 }1454
1455 public void setTurnLevelDownButtonEnable(booleanenable) {1456 btTurnLevelDown.setEnabled(enable);1457 }1458
1459 /**
1460 * 重置控制面板1461 */
1462 public voidreset() {1463 tfScore.setText(” 0″);1464 plTipBlock.setStyle(0);1465 }1466
1467 /**
1468 * 重新计算TipPanel里的boxes[][]里的小框的大小1469 */
1470 public voidfanning() {1471 plTipBlock.fanning();1472 }1473
1474 /**
1475 * 预显窗口的实现细节类1476 */
1477 private class TipPanel extends JPanel { //TipPanel用来显示下一个将要出现方块的形状
1478
1479 private Color backColor = Color.LIGHT_GRAY, frontColor =Color.ORANGE;1480 private ErsBox[][] boxes = newErsBox[ErsBlock.BOXES_ROWS][ErsBlock.BOXES_COLS];1481 private intstyle, boxWidth, boxHeight;1482 private boolean isTiled = false;1483
1484 /**
1485 * 预显示窗口类构造函数1486 */
1487 publicTipPanel() {1488 for (int i = 0; i < boxes.length; i++) {1489 for (int j = 0; j < boxes[i].length; j++) {1490 boxes[i][j] = new ErsBox(false);1491 }1492 }1493 }1494
1495 /**
1496 * 预显示窗口类构造函数1497 *1498 *@parambackColor Color,窗口的背景色1499 *@paramfrontColor Color,窗口的前景色1500 */
1501 publicTipPanel(Color backColor, Color frontColor) {1502 this();1503 this.backColor =backColor;1504 this.frontColor =frontColor;1505 }1506
1507 /**
1508 * 设置预显示窗口的方块样式1509 *1510 *@paramstyle int,对应ErsBlock类的STYLES中的28个值1511 */
1512 public void setStyle(intstyle) {1513 this.style =style;1514 repaint();1515 }1516
1517 /**
1518 * 覆盖JComponent类的函数,画组件。1519 *1520 *@paramg 图形设备环境1521 */
1522 @Override1523 public voidpaintComponent(Graphics g) {1524 super.paintComponent(g);1525
1526 if (!isTiled) {1527 fanning();1528 }1529
1530 int key = 0x8000;1531 for (int i = 0; i < boxes.length; i++) {1532 for (int j = 0; j < boxes[i].length; j++) {1533 Color color = ((key & style) != 0 ?frontColor : backColor);1534 g.setColor(color);1535 g.fill3DRect(j * boxWidth, i *boxHeight,1536 boxWidth, boxHeight, true);1537 key >>= 1;1538 }1539 }1540 }1541
1542 /**
1543 * g根据窗口的大小,自动调整方格的尺寸1544 */
1545 public voidfanning() {1546 boxWidth = getSize().width /ErsBlock.BOXES_COLS;1547 boxHeight = getSize().height /ErsBlock.BOXES_ROWS;1548 isTiled = true;1549 }1550 }1551 }
今天的文章俄罗斯方块java版_俄罗斯方块 Java 版分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/26282.html