java俄罗斯方块简单实现,新手适合学习

来源:互联网 发布:php框架排名 编辑:程序博客网 时间:2024/05/20 04:31

备注,程序采用了 substance.jar ,若缺少可以去掉main方法前面的代码。

一、方块类

import java.util.Random;import java.util.Timer;import java.util.TimerTask;public class BlockGrid16 {/*所有方块网格类型*/public static final int[][] MODELS = {{0x0063,0x0264,0x0063,0x0264}, //Z{0x006c,0x0462,0x006c,0x0462}, //反Z{0x0446,0x002e,0x0622,0x00e8}, //L{0x0226,0x0047,0x0644,0x0071}, //反L{0x0027,0x0464,0x0072,0x0131}, //T{0x0066,0x0066,0x0066,0x0066}, //田{0x000f,0x4444,0x000f,0x4444}, //l};/*随机数生成器*/public static final Random random = new Random();/*每一维大小*/public static final int dimension = 4;/*方块类型*/public int type;/*方块状态*/public int status;/*方块速度等级*/public int level;/*网格模型*/public boolean[][] model;/*当前所在画布*/public Canvas canvas;/*网格模型左上角在画布坐标系中的行位置*/public int row;/*网格模型左上角在画布坐标系中的列位置*/public int column;/*计时器*/public Timer t;/*构造方法*/public BlockGrid16(Canvas canvas,int level) {this.type = random.nextInt(MODELS.length);this.status = random.nextInt(MODELS[0].length);this.level = level;this.canvas = canvas;this.row = -999;this.column = 4;buildModel(MODELS[type][status]);}/*带参数构造方法*/public BlockGrid16(int type,int status,int level,Canvas canvas,int row,int column) {this(canvas,level);this.type = type;this.status = status;this.row = row;this.column = column;}public void init(){row = -3;column = 4;/*判断游戏是否结束*/if (isTouchBottom(row, column)) {canvas.isEnd = true;}}/*更新方块模型在画布上的位置*/public void update(){ for (int i=0;i<dimension;i++) {for (int j=0;j<dimension;j++) {if ( canvas.isValidPlace(row + i, column + j) && model[i][j]) {canvas.map[row+i][column+j] = true;}}}}/*方块移动*/public void moveTo(int r,int c) { /* 判断移动的可能性 */if (!moveable(r,c))return;/*擦除方块模型移动前的位置*/erase();/*调整方块模型位置*/row = r;column = c;/*更新*/update();/*如果已经到达底部,延时1000-level*50 毫秒更换当前方块模型*/if (isTouchBottom(row,column)) {canvas.haveFullLine();t = new Timer();t.schedule(new TimerTask(){public void run() {if(t != null){canvas.currBlock = canvas.nextBlock;canvas.currBlock.init();canvas.nextBlock = new BlockGrid16(canvas,level);t = null;canvas.repaint();}}}, 1000-level*50);}}/*向左移动*/public void moveLeft() {moveTo(row,column-1);}/*向右移动*/public void moveRight() {moveTo(row, column+1);}/*向下移动*/public void moveDown() {if (t != null && isTouchBottom(row,column)) {canvas.haveFullLine();canvas.currBlock = canvas.nextBlock;canvas.currBlock.init();canvas.nextBlock = new BlockGrid16(canvas,level);canvas.repaint();t = null;}moveTo(row+1, column);}/*移动到底部*/public void moveBottom() {for (int i=-3;i<Canvas.ROW;i++) {if (moveable(i, column) && isTouchBottom(i, column)) {t = new Timer();moveTo(i, column);canvas.haveFullLine();canvas.currBlock = canvas.nextBlock;canvas.currBlock.init();canvas.nextBlock = new BlockGrid16(canvas,level);canvas.repaint();t = null;break;}}}/*是否可以移动到指定位置*/public boolean moveable(int row,int column) {/*擦除当前要移动方块模型所占位置,以免影响判断*/erase();/*判断方块模型每一个单元格将要移动到的位置是否已经被占有*/for (int i=0;i<dimension;i++) {for (int j=0;j<dimension;j++) {/*只需判断方块模型中被占有的单元格*/if (model[i][j]) {/*判断合法性*/if (i + row >= Canvas.ROW || j + column <0 || j + column >= Canvas.COLUMN){update();return false;}/*判断将要移动的位置上是否已经被占用*/if (canvas.isValidPlace(i+row, j+column) && canvas.map[i+row][j+column]) {update();return false;}}}}/*恢复方块模型*/update();return true;}/*判断方块模型是否到底部*/public boolean isTouchBottom(int row,int column) {erase();for (int i=0;i<dimension;i++) {for (int j=0;j<dimension;j++) {if (model[i][j]) {int nextR = i + 1 + row;int nextC = j + column;/*若已经到底部*/if (nextR == Canvas.ROW) {update();return true;}/*判断当前单元格下方的单元格是否已经被占用*/if (canvas.isValidPlace(nextR, nextC)) {if (canvas.map[nextR][nextC]) {update();return true;}}}}}update();return false;}/*变形*/public void rorate() {int newStatus = (status + 1)%MODELS[type].length;if (!rorateable(MODELS[type][newStatus])) {return;}else {status ++;}/*擦除原先*/erase();/*旋转*/buildModel(MODELS[type][newStatus]);/*更新*/update();}//TODO 检查是否可以变形public boolean rorateable(int keyCode) {erase();/*初始化临时模型*/boolean[][] tempModel = new boolean[dimension][dimension];int bitKey = 0x8000;for (int i = 0;i<dimension;i++) {for (int j = 0;j<dimension;j++) {tempModel[i][j] = !((bitKey & keyCode) == 0);bitKey = bitKey >> 1;}}for (int i=0;i<dimension;i++) {for (int j=0;j<dimension;j++) {if (tempModel[i][j]) {if ( row + i >= Canvas.ROW || column+j < 0 || column +j >=Canvas.COLUMN ) {update();return false;}}}}update();return true;}/*擦除方块*/ public void erase() {for (int i=0;i<dimension;i++) {for (int j=0;j<dimension;j++) {if ( canvas.isValidPlace(row + i, column + j) && model[i][j]) {canvas.map[row+i][column+j] = false;}}}}/*构建网格模型*/public void buildModel(int modelCode) {int bitKey = 0x8000;model = new boolean[dimension][dimension];for (int i = 0;i<dimension;i++) {for (int j = 0;j<dimension;j++) {model[i][j] = !((bitKey & modelCode) == 0);bitKey = bitKey >> 1;}}}}

二、画布类

import java.awt.Color;import java.awt.Dimension;import java.awt.GradientPaint;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Paint;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.util.Timer;import java.util.TimerTask;import javax.swing.JOptionPane;import javax.swing.JPanel;public class Canvas extends JPanel implements KeyListener{private static final long serialVersionUID = -1354251777507926593L;/*游戏参数*/public static final int COLUMN = 10;public static final int ROW = 18;public static final int SIZE = 24;public static final Color backgroundColor = new Color(0xf1,0xf1,0xf1);public static final Color blockColor = Color.YELLOW;public static final Color cblockColor = Color.ORANGE;public static final int[] PADDING = {10,20,10,20};public static final int WIDTH = PADDING[1] + PADDING[3] + SIZE*COLUMN;public static final int HEIGHT= PADDING[0] + PADDING[2] + SIZE*ROW;public final int borderWidth = 1;public int oneLineScore = 100;public int level; //游戏当前等级public int score; //游戏当前分数/*游戏对象*/public BlockGrid16 currBlock; //当前操作的方块网格public BlockGrid16 nextBlock; //下一个将要操作的方块网格public boolean[][] map; //游戏图  18X10 网格public Timer downTimer; //下落计数器/*游戏标志*/public boolean isEnd = true; /*游戏是否结束*/public boolean isPause = false; /*游戏是否暂停*//*主窗口对象*/public GameApplication app;/*线程*/public ChangeBlockThread cbThread; /*切换方块线程*/public Canvas(GameApplication app) {this.app = app;setPreferredSize(null);         /*设置面板大小*/map = new boolean[ROW][COLUMN]; /*初始化地图数组*/setBackground(backgroundColor); /*设置背景颜色*/addKeyListener(this); /*注册键盘监听*/cbThread = new ChangeBlockThread();}public void gameInit(int level) { /*标志初始化*/isEnd = false;isPause = false;/*地图初始化*/map = new boolean[ROW][COLUMN];/*当前操作方块初始化*/currBlock = new BlockGrid16(this,level);currBlock.init();/*下一个操作方块初始化*/nextBlock = new BlockGrid16(this,level);/*等级*/this.level = level;/*分数*/this.score = 0;/*重绘*/repaint();}/*判断指定位置是否为合法位置*/public boolean isValidPlace(int row,int column) {if ( row < 0 || row >= ROW || column < 0 || column >= COLUMN)return false;return true;}/*检查是否底部为满行*/public void haveFullLine() {for (int i=0;i<ROW;i++) {boolean isFullLine = true;for (int j=0;j<COLUMN;j++) {if (!map[i][j]) {isFullLine = false;break;}}if (isFullLine) {clearLine(i);i -- ;}}}/*删除指定行*/public void clearLine(int row) {for (int i=row;i>0;i--) {for (int j=0;j<COLUMN;j++) {map[i][j] = map[i-1][j];}}score += oneLineScore;}@Overridepublic void setPreferredSize(Dimension arg0) {super.setPreferredSize(new Dimension(WIDTH,HEIGHT));}@Overridepublic void paint(Graphics g) {super.paint(g);/*画游戏边界*/g.drawLine(PADDING[3], PADDING[0], PADDING[3]+SIZE*COLUMN, PADDING[0]);g.drawLine(PADDING[3], PADDING[0] + SIZE*ROW, PADDING[3]+SIZE*COLUMN, PADDING[0]+ SIZE*ROW);g.drawLine(PADDING[3], PADDING[0], PADDING[3], PADDING[0] + ROW*SIZE);g.drawLine(PADDING[3]+SIZE*COLUMN, PADDING[0], PADDING[3]+SIZE*COLUMN, PADDING[0] + ROW*SIZE);/*更新当前操作方块位置*/if(currBlock != null)currBlock.update();/*画方块*/if(map != null)for ( int i=0;i<ROW;i++) {for ( int j=0;j<COLUMN;j++){if (map[i][j]) { /*画矩形*/g.drawRect(PADDING[3] + j*SIZE, PADDING[0] + i*SIZE, SIZE, SIZE);/*选择颜色变填充矩形*/Color oldColor = g.getColor();g.setColor(Color.PINK);g.fillRect(PADDING[3] + j*SIZE + borderWidth, PADDING[0] + i*SIZE + borderWidth, SIZE -borderWidth , SIZE -borderWidth);/*还原颜色*/g.setColor(oldColor);}}}}/*键盘监听*/@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();if ( (key >=37 && key <= 40 || key == 32) && !isEnd) {if (key == 37) {currBlock.moveLeft();} else if (key == 39) {currBlock.moveRight();} else if (key == 40) {currBlock.moveDown();} else if (key == 32) {currBlock.moveBottom();} else if (key == 38) {currBlock.rorate();}System.out.println(score);repaint();}else if ( key == 80) { //P}else if ( key == 78) { //Nif (downTimer != null) {downTimer.cancel();downTimer = null;}if (isEnd != true)if( JOptionPane.showConfirmDialog(this, "您确定要重新开始吗?", "新的游戏", JOptionPane.YES_NO_OPTION) == 0) {gameInit(app.gameLevel);downTimer = new Timer();downTimer.schedule(new TimerTask(){public void run() {currBlock.moveDown();repaint();}}, 0, 1000-level*50);return;}gameInit(app.gameLevel);downTimer = new Timer();downTimer.schedule(new TimerTask(){public void run() {currBlock.moveDown();repaint();}}, 0, 1000-level*50);}else if ( key == 82) { //R}else if ( key == 79) { //O}//上:38//下:40//左:37//右:39//P:80//N:78//R:82//O:79}@Overridepublic void keyReleased(KeyEvent arg0) {// TODO Auto-generated method stub}@Overridepublic void keyTyped(KeyEvent arg0) {// TODO Auto-generated method stub}/*方块下落控制的线程*/class ChangeBlockThread extends Thread{public long delay = 1000;@Overridepublic void run() {try {Thread.sleep(delay);} catch (InterruptedException e) {e.printStackTrace();}}}}

三、主界面类

import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JSplitPane;import javax.swing.JToolBar;import javax.swing.UIManager;import javax.swing.UnsupportedLookAndFeelException;public class GameApplication extends JFrame implements ActionListener{private static final long serialVersionUID = -1653174441012031192L;   private Canvas canvas;public int gameLevel = 10;/*工具栏*/    private JToolBar toolbar;   /*构造方法*/public GameApplication() {init();}/*界面初始化函数*/private void init() {setTitle("俄罗斯方块                     by:luiyikeke");add(createOrGetCanvas());add(createOrGetToolBar(),BorderLayout.NORTH);pack();setLocationRelativeTo(null);canvas.requestFocus();setResizable(false);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}/*创建画布面板,位于分割面板的左部*/private Canvas createOrGetCanvas(){if(canvas == null){canvas = new Canvas(this);}return canvas;}/*创建工具栏*/private JToolBar createOrGetToolBar() {if ( toolbar == null) {toolbar = new JToolBar();toolbar.add(createButtonWithAction("重新开始(N)"));toolbar.add(createButtonWithAction("暂停(P)"));toolbar.add(createButtonWithAction("排行榜(R)"));toolbar.add(createButtonWithAction("设置(O)"));}return toolbar;}/*创建按钮,并且带有事件监听*/private JButton createButtonWithAction(String btnString) { JButton btn = new JButton(btnString);btn.addActionListener(this);return btn;}// ------------------------------------// 事件监听// ------------------------------------@Overridepublic void actionPerformed(ActionEvent e) {String command = e.getActionCommand();if("重新开始(N)".equals(command)) {canvas.gameInit(gameLevel);}else if("暂停(P)".equals(command)) {}else if("排行榜(R)".equals(command)) {}else if("设置(O)".equals(command)) {}canvas.requestFocus();}public static void main(String[] args) {try {// 设置程序将采用的界面风格UIManager.setLookAndFeel("org.jvnet.substance.skin.SubstanceOfficeSilver2007LookAndFeel");} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (UnsupportedLookAndFeelException e) {e.printStackTrace();}new GameApplication().setVisible(true);}}