项目架构:
主程 类Tetris
package com;
import java.awt.Color;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tetris extends JPanel {
private int state;
public static final int RUNNING = 0;
public final int Pause = 1;
final static int GAME_OVER = 2;
public static final int ROWS = 20;// 背景墙的行数
public static final int COLS = 10;// 背景墙的行数
private Cell[][] wallCells;// 背景墙
private Tetromino nextOne;
private int score=0;// 分数
private int line;
private int lines;// 销毁的分数
private Tetromino tetromino;// 正在下落的四格方块
// 背景图片
private static BufferedImage backgroundlBufferedImage;
private static BufferedImage gameoverBufferedImage;
private static BufferedImage pauseBufferedImage;
public static BufferedImage TBufferedImage;
public static BufferedImage SBufferedImage;
public static BufferedImage IBufferedImage;
public static BufferedImage LBufferedImage;
public static BufferedImage JBufferedImage;
public static BufferedImage OBufferedImage;
public static BufferedImage ZBufferedImage;
public static final int Rows = 20;// 背景墙的行数
public static final int Lines = 10;// 背景墙的行数
// 在Tetris类中增加定时器
private Timer timer;
// 速度
private int speed;
// 难度级别
private int level;
// 下落计数当index%speed==0时候下落一次
private int index;
// 使用静态代码块加载静态的图片
static {
// Tetris.class的同一个包中找“tetris.png”
try {
backgroundlBufferedImage = ImageIO.read(Tetris.class
.getResource("tetris.png"));
gameoverBufferedImage = ImageIO.read(Tetris.class
.getResource("game-over.png"));
pauseBufferedImage = ImageIO.read(Tetris.class
.getResource("pause.png"));
TBufferedImage = ImageIO.read(Tetris.class.getResource("T.png"));
SBufferedImage = ImageIO.read(Tetris.class.getResource("S.png"));
ZBufferedImage = ImageIO.read(Tetris.class.getResource("Z.png"));
JBufferedImage = ImageIO.read(Tetris.class.getResource("J.png"));
LBufferedImage = ImageIO.read(Tetris.class.getResource("L.png"));
OBufferedImage = ImageIO.read(Tetris.class.getResource("O.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// JPanel paint() paint画重写paint()修改原有的绘制方法
public static void main(String[] args) {
JFrame frame = new JFrame();
// 在加载Tetris类的时候,会执行静态代码块
// 静态代码快,装载了图片素材。为图片对象
Tetris tetris = new Tetris();
// 将面板的颜色设置蔚蓝色,用于测试u
// tetris.setBackground(new Color(0x0000ff));
frame.add(tetris);
frame.setSize(500, 524);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);// 在显示窗口的时候,回尽快调用paint()方法绘制界面
tetris.action();
}
// 在Tetris添加方法启动方法action()
public void action() {
wallCells = new Cell[ROWS][COLS];
tetromino = Tetromino.randomOne();
nextOne = Tetromino.randomOne();
state = RUNNING;
// 处理键盘按下事件,在按下按键时候执行下落方法
KeyAdapter lAdapter = new KeyAdapter() {
// key按键pressed按下了
@Override
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyCode();
switch (state) {
case GAME_OVER:
processGameOverKey(key);
break;
case Pause:
processGameOverKey(key);
break;
case RUNNING:
break;
}
repaint();
}
};
// 下落流程,监听键盘事件
// 如果按下箭头按下->执行下落算法tetromino.softDrop()->尽快调用paint()->方法会根据当前的数据
// 重新绘制界面->看到移动以后的方块了
// 邦定事件到当前面板
this.requestFocus();
this.addKeyListener(lAdapter);
// 在Action中添加定时计划任务
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
speed = 40 - (line / 100);
speed = speed < 1 ? 1 : speed;
level = 41 - speed;
if (state == RUNNING && index % speed == 0) {
softDropAction();
}
index++;
repaint();
}
}, 10, 10);
}
protected void softDropAction() {
if (canDrop()) {
tetromino.softDrop();
} else {
landIntoWall();
destroyLines();
if (isGameOver()) {
state = GAME_OVER;
} else {
tetromino = nextOne;
nextOne = Tetromino.randomOne();
}
}
}
//检查游戏是否结束
private boolean isGameOver() {
//如果下一个方块没有出场位置了,则游戏结束
// 就是:下一个出场方块每个格子行列对应的
// 墙上位置,如果有格子,就游戏结束
Cell[] cells = nextOne.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
if (wallCells[row][col] != null) {
return true;
}
}
return false;
}
private static int[] scoreTable = {0,1,10,50,100};
private void destroyLines() {
int lines = 0;
for (int row = 0; row < wallCells.length; row++) {
if (fullCells(row)) {
deleteRow(row);
lines++;
}
}
this.score += scoreTable[lines];
this.lines += lines;
}
private void deleteRow(int row) {
for (int i = row; i >= 1; i++) {
System.arraycopy(wallCells[i - 1], 0, wallCells[i], 0, COLS);
}
Arrays.fill(wallCells[0],null);
}
private boolean fullCells(int row) {
Cell[] lineCells = wallCells[row];
for (Cell cell : lineCells) {
if (cell == null) {// 如果有null返回false,否则返回true
return false;
}
}
return true;
}
private void landIntoWall() {
Cell[] cellls = tetromino.cells;
for (int i = 0; i < cellls.length; i++) {
Cell cell = cellls[i];
int row = cell.getRow();
int col = cell.getCol();
wallCells[row][col] = cell;
}
}
//检查当前的方块是否能够下落,返回true
private boolean canDrop() {
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
if (row == ROWS-1) {
return false;
}
}
for (Cell cell : cells) {
int row = cell.getRow()+1;
int col = cell.getCol();
if (row >= 0 && row<ROWS&&col>=0&&col<=COLS&& wallCells[row][col] != null) {
return false;
}
}
return true;
}
// 硬下落流程,下落到不能下落为止,邦定到空格(VK_SPACE)事件上
public void hardDropAction() {
while (canDrop()) {
tetromino.softDrop();
}
landIntoWall();
destroyLines();
if (isGameOver()) {
state = GAME_OVER;
}else {
tetromino = nextOne;
nextOne = Tetromino.randomOne();
}
}
// 在Tetris类中添加旋转流程控制方法
public void rotateRightAction() {
tetromino.rotateRight();
if (outOfBounds() || coincide()) {
tetromino.rotateLeft();
}
}
// 检查当前正在下落的方块是否出界了
private boolean outOfBounds() {
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int col = cell.getCol();
if (col<0 || col >=COLS) {
return true;
}
}
return false;
}
//检查正在下落的方块是否与墙上的重叠
private boolean coincide() {
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
int col = cell.getCol();
//如果墙的row,col位置上有格子,就重叠了
if (row>=0 && row<ROWS && col>0&& col<COLS&&wallCells !=null) {
return true;
}
}
return false;
}
//在Tetris 类上添加方法,向右移动的流程控制
public void moveRightAction() {
//尝试向右移动,如果超过了边界就向左移动,修正回来
tetromino.moveright();
if (outOfBounds() || coincide()) {
tetromino.moveLeft();
}
}
protected void processGameOverKey(int key) {
switch (key) {
case KeyEvent.VK_Q:
System.exit(0);
break;
case KeyEvent.VK_C:
index = 0;
state = RUNNING;
break;
default:
break;
}
}
}
格子类
package com;
import java.awt.image.BufferedImage;
public class Cell {
private int row;//格子的行
private int col;//格子的列
private BufferedImage image;//格子的贴图
public Cell(int row, int col, BufferedImage image) {
super();
this.row = row;
this.col = col;
this.image = image;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public void drop() {
row++;
}
public void moveRight() {
col--;
}
public void moveLeft() {
row++;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return row+","+col;
}
}
方块类
package com;
import java.lang.Thread.State;
import java.util.Arrays;
import java.util.Random;
import com.squareblock.J;
import com.squareblock.L;
import com.squareblock.I;
import com.squareblock.O;
import com.squareblock.S;
import com.squareblock.T;
import com.squareblock.Z;
/**
* @author ASUS
*4格方格
*/
public class Tetromino {
protected Cell[] cells = new Cell[4];
private int index;
// 旋转方块
protected State[] states;
// 内部类
protected class State{
int row0,ro10,row1,col1,row2,col2,row3,col3;
public State(int row0, int ro10, int row1, int col1, int row2,
int col2, int row3, int col3) {
super();
this.row0 = row0;
this.ro10 = ro10;
this.row1 = row1;
this.col1 = col1;
this.row2 = row2;
this.col2 = col2;
this.row3 = row3;
this.col3 = col3;
}
}
//工厂方法,随机生成4格方块
public static Tetromino randomOne() {
Random random = new Random();
int type = random.nextInt(7);
switch (type) {
case 0:
return new O();
case 1:
return new S();
case 2:
return new Z();
case 3:
return new J();
case 4:
return new L();
case 5:
return new I();
case 6:
return new T();
default:
break;
}
return null;
}
public void softDrop() {
for (int i = 0; i < cells.length; i++) {
cells[i].drop();
}
}
//向右转
public void rotateRight() {
// 取得变换前的下个数据状态states[n]
// 取得当前轴的row.col
// 旋转以后的数据=(row,col)+states[n]
index++;
State s = states[index % states.length];
Cell o = cells[0];
int row = o.getRow();
int col = o.getCol();
cells[1].setRow(row+s.row1);
cells[1].setCol(col+s.col1);
cells[2].setRow(row+s.row2);
cells[2].setCol(col+s.col2);
cells[3].setRow(row+s.row3);
cells[3].setCol(col+s.col3);
}
public void rotateLeft() {
index--;
State s = states[index % states.length];
Cell o = cells[0];
int row = o.getRow();
int col = o.getCol();
cells[1].setRow(row+s.row1);
cells[1].setCol(col+s.col1);
cells[2].setRow(row+s.row2);
cells[2].setCol(col+s.col2);
cells[3].setRow(row+s.row3);
cells[3].setCol(col+s.col3);
}
public void moveright() {
for (int i = 0; i < cells.length; i++) {
cells[i].moveRight();
}
}
public void moveLeft() {
for (int i = 0; i < cells.length; i++) {
cells[i].moveLeft();
}
}
@Override
public String toString() {
return Arrays.toString(cells);
}
}
七种方块:
方块I:
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class I extends Tetromino {
public I() {
cells[0] = new Cell(0, 4, Tetris.SBufferedImage);
cells[1] = new Cell(0, 3, Tetris.SBufferedImage);
cells[2] = new Cell(0, 5, Tetris.SBufferedImage);
cells[3] = new Cell(0, 6,Tetris.SBufferedImage);
states = new State[]{ new State(0, 0, 0, -1,0,1,0, 2),new State(0, 0, -1, 0,1,0,2, 0)};
}
}
方块J:
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class J extends Tetromino {
public J() {
cells[0] = new Cell(0, 4, Tetris.JBufferedImage);
cells[1] = new Cell(0, 3, Tetris.JBufferedImage);
cells[2] = new Cell(0, 5, Tetris.JBufferedImage);
cells[3] = new Cell(1, 5,Tetris.JBufferedImage);
states = new State[]{ new State(0, 0, 0, -1,0,1,1, 1),
new State(0, 0, -1, 0,1,0,1, -1),
new State(0, 0, 0, 1,0,-1,-1, -1),
new State(0, 0, 1, 0,-1,0,-1, 1),};
}
}
方块L:
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class L extends Tetromino {
public L() {
cells[0] = new Cell(0, 4, Tetris.LBufferedImage);
cells[1] = new Cell(0, 3, Tetris.LBufferedImage);
cells[2] = new Cell(0, 5, Tetris.LBufferedImage);
cells[3] = new Cell(1, 3,Tetris.LBufferedImage);
states = new State[]{ new State(0, 0, 0, 1,0,-1,-1, 1),
new State(0, 0, 1, 0,-1,0,1, 1),
new State(0, 0, 0, -1,0,1,1, -1),
new State(0, 0, -1, 0,1,0,-1, -1),};
}
}
方块O :
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class O extends Tetromino {
public O() {
cells[0] = new Cell(0, 4, Tetris.OBufferedImage);
cells[1] = new Cell(0, 3, Tetris.OBufferedImage);
cells[2] = new Cell(0, 5, Tetris.OBufferedImage);
cells[3] = new Cell(1, 3,Tetris.OBufferedImage);
states = new State[]{ new State(0, 0, 0, 1,1,0,1, 1),
new State(0, 0, 0, 1,1,0,1, 1)};
}
}
方块S
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class S extends Tetromino {
public S() {
cells[0] = new Cell(1, 4, Tetris.SBufferedImage);
cells[1] = new Cell(1, 3, Tetris.SBufferedImage);
cells[2] = new Cell(0, 4, Tetris.SBufferedImage);
cells[3] = new Cell(0, 5,Tetris.SBufferedImage);
states = new State[]{ new State(0, 0, 0, -1,-1,0,-1, 1),new State(0, 0, -1, 0,0,1,1, 1)};
}
}
方块 T
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class S extends Tetromino {
public S() {
cells[0] = new Cell(1, 4, Tetris.SBufferedImage);
cells[1] = new Cell(1, 3, Tetris.SBufferedImage);
cells[2] = new Cell(0, 4, Tetris.SBufferedImage);
cells[3] = new Cell(0, 5,Tetris.SBufferedImage);
states = new State[]{ new State(0, 0, 0, -1,-1,0,-1, 1),new State(0, 0, -1, 0,0,1,1, 1)};
}
}
方块Z:
package com.squareblock;
import com.Cell;
import com.Tetris;
import com.Tetromino;
public class Z extends Tetromino {
public Z() {
cells[0] = new Cell(1, 4, Tetris.ZBufferedImage);
cells[1] = new Cell(0, 3, Tetris.ZBufferedImage);
cells[2] = new Cell(0, 4, Tetris.ZBufferedImage);
cells[3] = new Cell(1, 5,Tetris.ZBufferedImage);
states = new State[]{ new State(0, 0, -1, -1,-1,0,0, 1),new State(0, 0, -1, 1,0,1,1, 0)};
}
}
///////////////OVER////////////////////////////////////