Java20: 俄罗斯方块
业务分析:百度
数据模型:
类的设计:
1) Cell 格子
int row 行;
int col 列;
Image image 贴图;
2) Tetromino 四格方块
Cell[] cells 4个格子;
3) Tetris 俄罗斯方块 继承 JPanel
int score 分数;
int lines 行数;
Cell[][] wall = new Cell[20][10] 墙;
Tetromino tetromino 四格方块;
Tetromino nextOne 下一个四格方块;
数据的初始化:
构造器
设计功能:
下落
左移动
右移动
旋转
计分
入墙
界面绘制
java Swing API
背景图片
结束游戏图片
七种方块
ps技术有限,有个样子就行了
package xyz.rhel.els;
import java.awt.Image;
public class Cell {
private int row;
private int col;
private Image image;
public Cell(int row, int col, Image image) {
this.row = row;
this.col = col;
this.image = image;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public Image getImage() {
return image;
}
public void setRow(int row) {
this.row = row;
}
public void setCol(int col) {
this.col = col;
}
public void setImage(Image image) {
this.image = image;
}
public void up() {
row--;
}
public void drop() {
row++;
}
public void moveLeft() {
col--;
}
public void moveRight() {
col++;
}
public String toString() {
return "[" + row + "," + col + "]";
}
}
package xyz.rhel.els;
import java.util.Random;
public abstract class Tetromino {
protected Cell[] cells = new Cell[4];
protected State[] states;
private int index = 100;
private Tetromino() {
}
protected class State {
int row0, col0;
int row1, col1;
int row2, col2;
int row3, col3;
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 static Tetromino randomOne() {
Random r = new Random();
int type = r.nextInt(7);
switch (type) {
case 0:
return new T();
case 1:
return new I();
case 2:
return new S();
case 3:
return new Z();
case 4:
return new J();
case 5:
return new L();
case 6:
return new O();
}
return null;
}
public void up() {
for (Cell cell : cells) {
cell.up();
}
}
public void softDrop() {
for (Cell cell : cells) {
cell.drop();
}
}
public void moveRight() {
for (Cell cell : cells) {
cell.moveRight();
}
}
public void moveLeft() {
for (Cell cell : cells) {
cell.moveLeft();
}
}
public void rotateRight() {
index++;
State s = states[index % states.length];
Cell rotatingCenter = cells[0];
int row = rotatingCenter.getRow();
int col = rotatingCenter.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 rotatingCenter = cells[0];
int row = rotatingCenter.getRow();
int col = rotatingCenter.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);
}
private static 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);
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);// 右90
states[2] = new State(0, 0, 0, 1, 0, -1, -1, 0);// 右90
states[3] = new State(0, 0, 1, 0, -1, 0, 0, 1);// 右90
}
}
private static 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);
}
}
private static 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);
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);
}
}
private static class Z extends Tetromino {
public Z() {
cells[0] = new Cell(0, 4, Tetris.Z);
cells[1] = new Cell(0, 3, Tetris.Z);
cells[2] = new Cell(1, 4, Tetris.Z);
cells[3] = new Cell(1, 5, Tetris.Z);
states = new State[2];
states[0] = new State(0, 0, 0, -1, 1, 0, 1, 1);
states[1] = new State(0, 0, -1, 0, 0, -1, 1, -1);
}
}
private static 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);
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);
}
}
private static 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);
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);
}
}
private static 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);
states = new State[1];
states[0] = new State(0, 0, 0, 1, 1, 0, 1, 1);
}
}
}
package xyz.rhel.els;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class Tetris extends JPanel {
public static final int ROWS = 20;// 墙的行
public static final int COLS = 10;// 墙的列
public static final int CELL_SIZE = 18;// 格子大小
public static final int FONT_COLOR = 0x741852;
public static final int FONT_SIZE = 25;
public static Image background;// 背景图片
public static Image I;
public static Image T;
public static Image S;
public static Image Z;
public static Image L;
public static Image J;
public static Image O;
public static Image gameOverImg;
private boolean pause;// 暂停标志
private boolean gameOver;// 游戏结束标志
private Timer timer;//
private int inteval = 800;// 时间间隔
private int lines;// 消除的行数
private int[] scoreTable = { 0, 1, 20, 40, 60 };// 得分表
private int score;// 得分
private Cell[][] wall = new Cell[20][10];// 墙
private Tetromino tetromino;// 正在下落
private Tetromino nextOne;// 下一个将下落的
static {// 静态加载图片
try {
Class cls = Tetris.class;
background = ImageIO.read(cls.getResource("background.png"));
I = ImageIO.read(cls.getResource("I.png"));
T = ImageIO.read(cls.getResource("T.png"));
S = ImageIO.read(cls.getResource("S.png"));
Z = ImageIO.read(cls.getResource("Z.png"));
L = ImageIO.read(cls.getResource("L.png"));
J = ImageIO.read(cls.getResource("J.png"));
O = ImageIO.read(cls.getResource("O.png"));
gameOverImg = ImageIO.read(cls.getResource("gameOverImg.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
private void paintGmaeOver(Graphics g) {// 画结束图片
g.drawImage(gameOverImg, 200, 200, null);
}
private void paintScore(Graphics g) {// 画得分
String str = "分数:" + score;
g.setColor(new Color(FONT_COLOR));
Font font = getFont();
font = new Font(font.getName(), Font.BOLD, FONT_SIZE);// 为了跨平台
g.setFont(font);
g.drawString(str, 250, 200);
}
private void paintLines(Graphics g) {// 画行
String str = "行数:" + lines;
g.drawString(str, 250, 250);
}
private void paintNextOne(Graphics g) {// 画下一个方块的方法
if (nextOne == null) {
return;
}
Cell[] cells = nextOne.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int x = cell.getCol() * CELL_SIZE;
int y = cell.getRow() * CELL_SIZE;
g.drawImage(cell.getImage(), x + 200, y + 100, null);
}
}
private void paintNextOneBox(Graphics g) {// 画将要下落方块的容器的方法
g.drawRect(250, 80, 80, 80);
}
private void paintTetromino(Graphics g) {// 画下落的方块
if (tetromino == null) {
return;
}
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
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 row = 0; row < wall.length; row++) {
Cell[] line = wall[row];
for (int col = 0; col < line.length; col++) {
Cell cell = line[col];
int x = col * CELL_SIZE;
int y = row * CELL_SIZE;
if (cell == null) {
g.setColor(new Color(0xff0000));
g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
} else {
g.drawImage(cell.getImage(), x, y, null);
}
}
}
}
public void paint(Graphics g) {// 重写JPanel 中的paint方法 repaint来调用
g.drawImage(background, 0, 0, null);// 在窗口中画背景图片
g.translate(10, 10);// 坐标系平移
paintWall(g);// 画墙
paintTetromino(g);// 画下落的方块
paintNextOneBox(g);// 画将要下落方块的容器
paintNextOne(g);// 画下一个将下落的
paintScore(g);// 画得分
paintLines(g);// 画行
if (pause) {
g.drawString("暂停中请按C继续", 400, 100);
}
if (gameOver) {
paintGmaeOver(g);
g.drawString("重新开始请按S", 400, 100);
}
}
private boolean canUp() {// 作弊使用,向上
Cell[] cells = tetromino.cells;
for (Cell cell : cells) {
int row = cell.getRow();
if (row == 0) {
return false;
}
}
return true;
}
private boolean canDrop() {// 判断当前方块是否可以下落
Cell[] cells = tetromino.cells;
for (Cell cell : cells) {// 检查当前方块是否到达底部
int row = cell.getRow();
if (row == ROWS - 1) {
return false;
}
}
for (Cell cell : cells) {// 检查当前方块的下一行是否有方块
int row = cell.getRow();
int col = cell.getCol();
if (wall[row + 1][col] != null) {
return false;
}
}
return true;
}
private void landToWall() {// 进入墙
Cell[] cells = tetromino.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
wall[row][col] = cell;
}
}
private boolean fullCells(int row) {// 查格子是否是满的
Cell[] line = wall[row];
for (Cell cell : line) {
if (cell == null) {
return false;
}
}
return true;
}
private void deleteLine(int row) {// 删除满行
for (int i = row; i >= 1; i--) {
System.arraycopy(wall[i - 1], 0, wall[i], 0, COLS);
}
Arrays.fill(wall[0], null);
}
private void destroyLines() {// 消除行方法
int lines = 0;
for (int row = 0; row < ROWS; row++) {
if (fullCells(row)) {
deleteLine(row);
lines++;
}
}
this.lines += lines;
this.score += scoreTable[lines];
}
private void checkGameOver() {// 检查游戏是否结束
if (wall[0][4] != null) {
gameOver = true;
timer.cancel();
repaint();
}
}
private boolean outOfBounds() {// 左右边界检查
Cell[] cells = tetromino.cells;
for (Cell cell : cells) {
int col = cell.getCol();
if (col < 0 || col >= COLS) {
return true;
}
}
return false;
}
private boolean coincide() {// 格子重合检查
Cell[] cells = tetromino.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
if (row >= 0 && row < ROWS && col >= 0 && col < COLS
&& wall[row][col] != null) {
return true;
}
}
return false;
}
private void upAction() {// 作弊使用,向上
if (canUp()) {
tetromino.up();
}
}
private void softDropAction() {// 下落动作
if (canDrop()) {
tetromino.softDrop();
} else {
landToWall();
destroyLines();
checkGameOver();
tetromino = nextOne;
nextOne = Tetromino.randomOne();
}
}
private void hardDropAction() {// 硬下落
while (canDrop()) {
tetromino.softDrop();
}
landToWall();
destroyLines();
checkGameOver();
tetromino = nextOne;
nextOne = Tetromino.randomOne();
}
private void moveLeftAction() {// 左移动方法
tetromino.moveLeft();
if (outOfBounds() || coincide()) {
tetromino.moveRight();
}
}
private void moveRightAction() {// 右移动方法
tetromino.moveRight();
if (outOfBounds() || coincide()) {
tetromino.moveLeft();
}
}
private void rotateRightAction() {// 右转动
tetromino.rotateRight();
if (outOfBounds() || coincide()) {
tetromino.rotateLeft();
}
}
private void rotateLeftAction() {// 左转动
tetromino.rotateLeft();
if (outOfBounds() || coincide()) {
tetromino.rotateRight();
}
}
private void action() {// 开始方法
startAction();
repaint();
KeyListener l = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_Q) {
System.exit(0);
}
if (gameOver) {
if (key == KeyEvent.VK_S) {
startAction();
}
return;
}
if (pause) {
if (key == KeyEvent.VK_C) {
continueAction();
}
return;
}
switch (key) {
case KeyEvent.VK_UP:
upAction();
break;
case KeyEvent.VK_DOWN:
softDropAction();
break;
case KeyEvent.VK_RIGHT:
moveRightAction();
break;
case KeyEvent.VK_LEFT:
moveLeftAction();
break;
case KeyEvent.VK_Z:
rotateLeftAction();
break;
case KeyEvent.VK_X:
rotateRightAction();
break;
case KeyEvent.VK_SPACE:
hardDropAction();
break;
case KeyEvent.VK_S:
pauseAction();
break;
}
repaint();
}
};
this.addKeyListener(l);
this.requestFocus();
}
private void startAction() {// 开始
pause = false;
gameOver = false;
score = 0;
lines = 0;
for (Cell[] line : wall) {
Arrays.fill(line, null);
}
tetromino = Tetromino.randomOne();
nextOne = Tetromino.randomOne();
TimerTask task = new TimerTask() {
public void run() {
softDropAction();
repaint();
}
};
timer = new Timer();
timer.schedule(task, inteval, inteval);
}
private void pauseAction() {// 暂停
timer.cancel();
pause = true;
}
private void continueAction() {// 继续
pause = false;
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
softDropAction();
repaint();
}
}, inteval, inteval);
}
public static void main(String[] args) {
JFrame frame = new JFrame("<俄罗斯方块>");
Tetris tetris = new Tetris();
// tetris.setBackground(new Color(0xff5511));
frame.add(tetris);
frame.setSize(800, 450);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
tetris.action();
}
}