俄罗斯方块的各种方块由四个小方块组成,所以单独抽象为Cell类
属性有:行坐标,列坐标,各种颜色的方块图片
方法有:左移一格,右移一格,下移一格
import java.awt.image.BufferedImage;
/**
* 描述:小方块类
* 属性:行,列以及单元格的图片
* 方法: 左移一格,右移一格,下移一格
*/
public class Cell {
private int row;
private int col;
private BufferedImage image;
public Cell() {
}
public Cell(int row, int col, BufferedImage image) {
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 left() {
col--;
}
//右移
public void right() {
col++;
}
//下移
public void drop() {
row++;
}
}
创建四方格父类,子类继承后可以进行左移,右移,下移以及变形
/**
* 描述:四方格父类
* 属性:Cell[]数组用于创建4个小方块
* 方法:左移一格,右移一格,下移一格,变形(等会写)
*/
public class Tetromino {
protected Cell[] cells = new Cell[4];
//编写旋转状态
protected State[] states;
//声明旋转次数
protected int count = 10000;
//编写顺时针旋转四方格方法
public void rotateRight() {
if (states.length == 0) {
return;
}
//旋转次数加1
count++;
//获取当前状态
State s = states[count % states.length];
Cell cell = cells[0];
int row = cell.getRow();
int col = cell.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() {
//旋转次数加1
count--;
//获取当前状态
State s = states[count % states.length];
Cell cell = cells[0];
int row = cell.getRow();
int col = cell.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);
}
/**描述:四方格旋转状态的内部类
* 属性:记录四方格的相对位置
*/
class State {
int row0,col0,row1,col1,row2,col2,row3,col3;
public State(){
}
public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) {
this.row0 = row0;
this.col0 = col0;
this.row1 = row1;
this.col1 = col1;
this.row2 = row2;
this.col2 = col2;
this.row3 = row3;
this.col3 = col3;
}
public int getRow0() {
return row0;
}
public void setRow0(int row0) {
this.row0 = row0;
}
public int getRow1() {
return row1;
}
public void setRow1(int row1) {
this.row1 = row1;
}
public int getRow2() {
return row2;
}
public void setRow2(int row2) {
this.row2 = row2;
}
public int getRow3() {
return row3;
}
public void setRow3(int row3) {
this.row3 = row3;
}
public int getCol0() {
return col0;
}
public void setCol0(int col0) {
this.col0 = col0;
}
public int getCol1() {
return col1;
}
public void setCol1(int col1) {
this.col1 = col1;
}
public int getCol2() {
return col2;
}
public void setCol2(int col2) {
this.col2 = col2;
}
public int getCol3() {
return col3;
}
public void setCol3(int col3) {
this.col3 = col3;
}
}
//左移
public void moveLeft() {
for (Cell cell : cells) {
cell.left();
}
}
//右移
public void moveRight() {
for (Cell cell : cells) {
cell.right();
}
}
//下移
public void softDrop() {
for (Cell cell : cells) {
cell.drop();
}
}
//随机生成四方格
public static Tetromino randomOne() {
int num = (int)(Math.random() * 7);
Tetromino tetromino = null;
switch (num) {
case 0 :
tetromino = new I();
break;
case 1 :
tetromino = new J();
break;
case 2 :
tetromino = new L();
break;
case 3 :
tetromino = new O();
break;
case 4 :
tetromino = new S();
break;
case 5 :
tetromino = new T();
break;
case 6 :
tetromino = new Z();
break;
}
return tetromino;
}
}
建立各种形状子类 I J L O S T Z
public class I extends Tetromino{
public I() {
cells[0] = new Cell(0,4,Tetris.I);
cells[1] = new Cell(0,3,Tetris.I);
cells[2] = new Cell(0,5,Tetris.I);
cells[3] = new Cell(0,6,Tetris.I);
//两种状态
states = new State[2];
//相对坐标
states[0] = new State(0,0,0,-1,0,1,0,2);
states[1] = new State(0,0,-1,0,1,0,2,0);
}
}
public class J extends Tetromino{
public J() {
cells[0] = new Cell(0,4,Tetris.J);
cells[1] = new Cell(0,3,Tetris.J);
cells[2] = new Cell(0,5,Tetris.J);
cells[3] = new Cell(1,5,Tetris.J);
//4种状态
states = new State[4];
states[0] = new State(0,0,0,1,0,1,1,1);
states[1] = new State(0,0,-1,0,1,0,1,-1);
states[2] = new State(0,0,0,1,0,-1,-1,-1);
states[3] = new State(0,0,1,0,-1,0,-1,1);
}
}
public class L extends Tetromino{
public L() {
cells[0] = new Cell(0,4,Tetris.L);
cells[1] = new Cell(0,3,Tetris.L);
cells[2] = new Cell(0,5,Tetris.L);
cells[3] = new Cell(1,3,Tetris.L);
//4种状态
states = new State[4];
//初始化
states[0] = new State(0,0,0,-1,0,1,1,-1);
states[1] = new State(0,0,-1,0,1,0,-1,-1);
states[2] = new State(0,0,0,1,0,-1,-1,1);
states[3] = new State(0,0,1,0,-1,0,1,1);
}
}
public class O extends Tetromino{
public O() {
cells[0] = new Cell(0,4,Tetris.O);
cells[1] = new Cell(0,5,Tetris.O);
cells[2] = new Cell(1,4,Tetris.O);
cells[3] = new Cell(1,5,Tetris.O);
//0种状态
states = new State[0];
}
}
public class S extends Tetromino{
public S() {
cells[0] = new Cell(0,4,Tetris.S);
cells[1] = new Cell(0,5,Tetris.S);
cells[2] = new Cell(1,3,Tetris.S);
cells[3] = new Cell(1,4,Tetris.S);
//2种状态
states = new State[2];
//初始化相对位置
states[0] = new State(0,0,0,1,1,-1,1,0);
states[1] = new State(0,0,1,0,-1,-1,0,-1);
}
}
public class T extends Tetromino{
public T() {
cells[0] = new Cell(0,4,Tetris.T);
cells[1] = new Cell(0,3,Tetris.T);
cells[2] = new Cell(0,5,Tetris.T);
cells[3] = new Cell(1,4,Tetris.T);
//4种状态
states = new State[4];
//初始化相对坐标
states[0] = new State(0,0,0,-1,0,1,1,0);
states[1] = new State(0,0,-1,0,1,0,0,-1);
states[2] = new State(0,0,0,1,0,-1,-1,0);
states[3] = new State(0,0,1,0,-1,0,0,1);
}
}
public class Z extends Tetromino{
public Z() {
cells[0] = new Cell(1,4,Tetris.Z);
cells[1] = new Cell(0,3,Tetris.Z);
cells[2] = new Cell(0,4,Tetris.Z);
cells[3] = new Cell(1,5,Tetris.Z);
//两种状态
states = new State[2];
//初始化相对位置
states[0] = new State(0,0,-1,-1,-1,0,0,1);
states[1] = new State(0,0,-1,1,0,1,1,0);
}
}
编写俄罗斯方块主类并并且继承JPanel框架,然后静态载入图片import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
//俄罗斯方块主类
public class Tetris extends JPanel {
static int ROW = 15;
static int COL = 9;
//声明正在下落的方块
private Tetromino currentOne = Tetromino.randomOne();
//声明将要下落的方块
private Tetromino nextOne = Tetromino.randomOne();
//声明游戏主区域
private Cell[][] wall = new Cell[ROW][COL];
//声明单元格像素为48像素
private static final int CELL_SIZE = 48;
//游戏分数池
int[] scores_pool = {0, 1, 2, 5, 10};
//游戏总分
private int totalScore = 0;
//游戏消除总行数
private int totalLine = 0;
//游戏的状态:游戏中,游戏暂停,游戏结束
private static final int PLAYING = 0;
private static final int PAUSE = 1;
private static final int GAMEOVER = 2;
//声明变量来存放当前游戏状态
private int game_state;
//数组显示当前游戏状态
String[] show_state = {"P[暂停]","C[继续]","R[重开]"};
//静态载入图片
public static BufferedImage I;
public static BufferedImage J;
public static BufferedImage L;
public static BufferedImage O;
public static BufferedImage S;
public static BufferedImage T;
public static BufferedImage Z;
public static BufferedImage backImage;
static {
try {
I = ImageIO.read(new File("images/I.png"));
J = ImageIO.read(new File("images/J.png"));
L = ImageIO.read(new File("images/L.png"));
O = ImageIO.read(new File("images/O.png"));
S = ImageIO.read(new File("images/S.png"));
T = ImageIO.read(new File("images/T.png"));
Z = ImageIO.read(new File("images/Z.png"));
backImage = ImageIO.read(new File("images/background.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void paint(Graphics g) {
g.drawImage(backImage,0,0,null);
//平移坐标轴
g.translate(22,15);
//绘制游戏主区域
paintWall(g);
//绘制正在下落的四方格
paintCurrentOne(g);
//绘制下一个下落的四方格
paintNextOne(g);
//绘制游戏得分
paintScore(g);
//绘制游戏当前状态
paintState(g);
}
//start 方法,用于调用游戏操作逻辑并监听键盘和描述游戏主要逻辑
public void start() {
game_state = PLAYING;
KeyListener listener = new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
switch (code) {
case KeyEvent.VK_DOWN: //↓
sortDropAction(); //下落一格
break;
case KeyEvent.VK_LEFT://←
moveLeftAction(); //左移一格
break;
case KeyEvent.VK_RIGHT: //→
moveRightAction(); //右移一格
break;
case KeyEvent.VK_UP://↑
rotateRightAction();//顺时针旋转
break;
case KeyEvent.VK_SPACE://空格
handDropAction();//瞬间下落
break;
case KeyEvent.VK_P: //p
//判断游戏是否在运行,没有才能暂停
if (game_state == PLAYING) {
game_state = PAUSE;
}
break;
case KeyEvent.VK_C:
//游戏暂停后,才能继续
if (game_state == PAUSE) {
game_state = PLAYING;
}
break;
case KeyEvent.VK_R:
//重新开始游戏,把游戏状态变为正在游戏
game_state = PLAYING;
//界面清空
wall = new Cell[ROW][COL];
currentOne = Tetromino.randomOne();
nextOne = Tetromino.randomOne();
//数据清空
totalLine = 0;
totalScore = 0;
break;
}
}
};
//把俄罗斯方块窗口设置为焦点
this.addKeyListener(listener);
this.requestFocus();
while(true){
//判断,当前游戏状态在游戏中时,每隔0.5秒下落
if(game_state == PLAYING){
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断能否下落
if(canDrop()){
currentOne.softDrop();
}else{
//嵌入到墙中
landToWall();
//判断能否消行
destroyLine();
//判断游戏是否结束
if(isGameOver()){
game_state = GAMEOVER;
}else{
currentOne = nextOne;
nextOne = Tetromino.randomOne();
}
}
}
//重新绘制
repaint();
}
}
//顺时针旋转
public void rotateRightAction() {
currentOne.rotateRight();
//判断是否越界或者重合,否则恢复原来的状态
if (outOfBounds() || coincide()) {
currentOne.rotateLeft();
}
}
//瞬间下落
public void handDropAction() {
while (canDrop()) {
currentOne.softDrop();
}
//把四方格嵌入墙中
landToWall();
//判断能否销行
destroyLine();
//判断游戏是否结束
if (isGameOver()) {
game_state = GAMEOVER;
} else {
//继续生成四方格
currentOne = nextOne;
nextOne = Tetromino.randomOne();
}
}
//按键一次四方格下落一个
public void sortDropAction() {
//判断能否下落
if (canDrop()) {
//当前四方格下落一格
currentOne.softDrop();
} else {
//把四方格嵌入墙中
landToWall();
//判断能否销行
destroyLine();
//判断游戏是否结束
if (isGameOver()) {
game_state = GAMEOVER;
} else {
//继续生成四方格
currentOne = nextOne;
nextOne = Tetromino.randomOne();
}
}
}
//把四方格嵌入墙中
private void landToWall() {
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
wall[row][col] = cell;
}
}
//判断四方格能否下落
public boolean canDrop() {
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
//判断能否全部到达底部
if (row == wall.length - 1) {
return false;
} else if(wall[row + 1][col] != null) { //判断该位置是否有方块
return false;
}
}
return true;
}
//创建销行方法
public void destroyLine() {
//统计当前形参行数
int line = 0;
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int row = cell.getRow();
//判断当前行是否满
if (isFullLine(row)) {
line++;
//将消除行以上的方块下落到对应行数
for (int i = row; i > 0; i--) {
System.arraycopy(wall[i - 1],0,wall[i],0,wall[0].length);
}
//重新创造第一行
wall[0] = new Cell[9];
}
}
//更新分数
totalScore += scores_pool[line];
//更新消除行数
totalLine += line;
}
//判断当前行是否满,满返回true,没有满返回false
public boolean isFullLine(int row) {
Cell[] cells = wall[row];
for (Cell cell : cells) {
if (cell == null) {
return false;
}
}
return true;
}
//判断游戏是否结束,结束返回true,继续返回false
public boolean isGameOver() {
Cell[] cells = nextOne.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
if (wall[row][col] != null) {
return true;
}
}
return false;
}
//按键←触发左移
public void moveLeftAction() {
currentOne.moveLeft();
//判断是否越界或者重合,如果是则右移恢复原来的状态,不是则左移
if (outOfBounds() || coincide()) {
currentOne.moveRight();
}
}
//按键→触发右移
public void moveRightAction() {
currentOne.moveRight();
//判断是否越界或者重合,如果是则左移恢复原来的状态,不是则右移
if (outOfBounds() || coincide()) {
currentOne.moveLeft();
}
}
//判断方块是否重合,重合返回true,没有返回false
public boolean coincide() {
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int col = cell.getCol();
int row = cell.getRow();
if (wall[row][col] != null) {
return true;
}
}
return false;
}
//判断方块是否出界,出界返回true,没有则返回false
public boolean outOfBounds() {
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int col = cell.getCol();
int row = cell.getRow();
if (col < 0 || col > COL - 1 || row < 0 || row > ROW - 1) {
return true;
}
}
return false;
}
//绘制游戏当前状态
private void paintState(Graphics g) {
if (game_state == PLAYING) {
g.drawString(show_state[0],500,660);
} else if (game_state == PAUSE) {
g.drawString(show_state[1],500,660);
} else if (game_state == GAMEOVER) {
g.drawString(show_state[2],500,660);
g.setColor(Color.red);
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,60));
g.drawString("GAMEOVER!",30,400);
}
}
//绘制游戏得分
private void paintScore(Graphics g) {
g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,40));
g.drawString("得分:" + totalScore,500,248);
g.drawString("行数:"+ totalLine,500,440);
}
//绘制下一个下落的四方格
private void paintNextOne(Graphics g) {
Cell[] cells = nextOne.cells;
for (Cell cell : cells) {
int x = cell.getCol() * CELL_SIZE + 370;
int y = cell.getRow() * CELL_SIZE + 25;
g.drawImage(cell.getImage(),x,y,null);
}
}
//绘制正在下落的四方格
private void paintCurrentOne(Graphics g) {
Cell[] cells = currentOne.cells;
for (Cell cell : cells) {
int x = cell.getCol() * CELL_SIZE;
int y = cell.getRow() * CELL_SIZE;
g.drawImage(cell.getImage(),x,y,null);
}
}
//绘制游戏主区域
private void paintWall(Graphics g) {
for (int i = 0; i < wall.length; i++) {
for (int j = 0; j < wall[i].length; j++) {
int x = j * CELL_SIZE;
int y = i * CELL_SIZE;
Cell cell = wall[i][j];
//判断当前单元格是否有小方格,如果无则绘制矩形,否则将小方块嵌到墙中
if (cell == null) {
g.drawRect(x,y,CELL_SIZE,CELL_SIZE);
} else {
g.drawImage(cell.getImage(),x,y,null);
}
}
}
}
public static void main(String[] args) {
//创建窗口对象
JFrame frame = new JFrame("俄罗斯方块");
//创建游戏窗口(即面板)
Tetris panel = new Tetris();
//把面板嵌入到窗口中
frame.add(panel);
//设置可见
frame.setVisible(true);
//设置窗口尺寸
frame.setSize(810,940);
//设置窗口居中
frame.setLocationRelativeTo(null);
//设置窗口关闭时程序中止
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//游戏逻辑封装在方法中
panel.start();
}}