这是一个用Java Swing实现的俄罗斯方块游戏,具有经典的游戏机制和图形界面。游戏中,玩家需要旋转和移动不断下落的方块,使其填满一行来消除该行并得分。
该项目适合学习Java GUI编程、游戏开发基础以及面向对象编程(OOP)概念。
功能特性
-
图形界面:
- 使用Java Swing库实现用户界面。
- 提供直观的游戏界面,显示当前下落的方块和游戏得分。
-
游戏逻辑:
- 方块自动下落,玩家可以通过键盘控制方块的移动和旋转。
- 当方块填满一行时,该行会被消除,玩家得分增加。
- 游戏结束时,显示最终得分并停止游戏。
-
控件说明:
- 左右箭头键:移动方块左右。
- 上箭头键:旋转方块(顺时针)。
- 下箭头键:旋转方块(逆时针)。
- 空格键:快速下落方块。
- 'D'键:快速下降一行。
- 'P'键:暂停和继续游戏。
-
扩展性:
- 代码结构清晰,便于扩展和修改,例如添加新的方块形状或改变下落速度。
- 通过调整计时器的延迟,可以轻松改变游戏难度。
技术亮点
-
面向对象编程:
- 使用类和对象封装游戏中的方块形状、游戏逻辑和界面。
- 代码模块化,便于理解和维护。
-
事件驱动编程:
- 使用键盘事件和计时器事件控制游戏流程。
- 实现了对用户输入的实时响应,使游戏更加流畅。
-
Swing库的应用:
- 学习如何使用Swing库创建窗口、绘制图形、处理事件。
- 通过定制化绘制方法,展示不同颜色和形状的方块。
游戏界面
游戏代码(展示部分文件,完整代码可下载资源)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
// Tetris游戏主类,继承自JPanel,并实现ActionListener接口
public class Tetris extends JPanel implements ActionListener {
private final int BOARD_WIDTH = 10; // 游戏板宽度(单位:格子)
private final int BOARD_HEIGHT = 20; // 游戏板高度(单位:格子)
private final int CELL_SIZE = 30; // 每个格子的大小(单位:像素)
private final int TIMER_DELAY = 500; // 方块下落的时间间隔(单位:毫秒)
private Timer timer; // 控制方块下落的计时器
private boolean isFallingFinished = false; // 标记是否方块已经落地
private boolean isStarted = false; // 标记游戏是否开始
private boolean isPaused = false; // 标记游戏是否暂停
private int numLinesRemoved = 0; // 记录消除的行数(即得分)
private int currentX = 0; // 当前方块的x坐标
private int currentY = 0; // 当前方块的y坐标
private Shape currentPiece; // 当前的方块形状
private Shape.Tetrominoes[] board; // 存储游戏板上的方块
private JLabel statusBar; // 显示得分的状态栏
public Tetris(JLabel statusBar) {
setFocusable(true);
currentPiece = new Shape();
timer = new Timer(TIMER_DELAY, this);
board = new Shape.Tetrominoes[BOARD_WIDTH * BOARD_HEIGHT];
clearBoard();
addKeyListener(new TAdapter());
this.statusBar = statusBar;
}
// 启动游戏
public void start() {
if (isPaused) {
return;
}
isStarted = true;
isFallingFinished = false;
numLinesRemoved = 0;
clearBoard();
newPiece();
timer.start();
}
// 暂停游戏
private void pause() {
if (!isStarted) {
return;
}
isPaused = !isPaused;
if (isPaused) {
timer.stop();
statusBar.setText("暂停");
} else {
timer.start();
statusBar.setText(String.valueOf(numLinesRemoved));
}
repaint();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
// 绘制游戏界面
private void doDrawing(Graphics g) {
Dimension size = getSize();
int boardTop = (int) size.getHeight() - BOARD_HEIGHT * CELL_SIZE;
// 绘制游戏板上的方块
for (int i = 0; i < BOARD_HEIGHT; i++) {
for (int j = 0; j < BOARD_WIDTH; j++) {
Shape.Tetrominoes shape = shapeAt(j, BOARD_HEIGHT - i - 1);
if (shape != Shape.Tetrominoes.NoShape) {
drawSquare(g, j * CELL_SIZE, boardTop + i * CELL_SIZE, shape);
}
}
}
// 绘制当前活动的方块
if (currentPiece.getShape() != Shape.Tetrominoes.NoShape) {
for (int i = 0; i < 4; i++) {
int x = currentX + currentPiece.x(i);
int y = currentY - currentPiece.y(i);
drawSquare(g, x * CELL_SIZE, boardTop + (BOARD_HEIGHT - y - 1) * CELL_SIZE, currentPiece.getShape());
}
}
}
// 方块快速下落到最底部
private void dropDown() {
int newY = currentY;
while (newY > 0) {
if (!tryMove(currentPiece, currentX, newY - 1)) {
break;
}
newY--;
}
pieceDropped();
}
// 方块下落一行
private void oneLineDown() {
if (!tryMove(currentPiece, currentX, currentY - 1)) {
pieceDropped();
}
}
// 清空游戏板
private void clearBoard() {
for (int i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; i++) {
board[i] = Shape.Tetrominoes.NoShape;
}
}
// 处理方块落地后的逻辑
private void pieceDropped() {
for (int i = 0; i < 4; i++) {
int x = currentX + currentPiece.x(i);
int y = currentY - currentPiece.y(i);
board[(y * BOARD_WIDTH) + x] = currentPiece.getShape();
}
removeFullLines();
if (!isFallingFinished) {
newPiece();
}
}
// 生成新的方块
private void newPiece() {
currentPiece.setRandomShape();
currentX = BOARD_WIDTH / 2;
currentY = BOARD_HEIGHT - 1 + currentPiece.minY();
if (!tryMove(currentPiece, currentX, currentY)) {
currentPiece.setShape(Shape.Tetrominoes.NoShape);
timer.stop();
isStarted = false;
statusBar.setText("游戏结束. 分数: " + numLinesRemoved);
}
}
// 尝试移动方块
private boolean tryMove(Shape newPiece, int newX, int newY) {
for (int i = 0; i < 4; i++) {
int x = newX + newPiece.x(i);
int y = newY - newPiece.y(i);
if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) {
return false;
}
if (shapeAt(x, y) != Shape.Tetrominoes.NoShape) {
return false;
}
}
currentPiece = newPiece;
currentX = newX;
currentY = newY;
repaint();
return true;
}
// 移除填满的行
private void removeFullLines() {
int numFullLines = 0;
for (int i = BOARD_HEIGHT - 1; i >= 0; i--) {
boolean lineIsFull = true;
for (int j = 0; j < BOARD_WIDTH; j++) {
if (shapeAt(j, i) == Shape.Tetrominoes.NoShape) {
lineIsFull = false;
break;
}
}
if (lineIsFull) {
numFullLines++;
for (int k = i; k < BOARD_HEIGHT - 1; k++) {
for (int j = 0; j < BOARD_WIDTH; j++) {
board[(k * BOARD_WIDTH) + j] = shapeAt(j, k + 1);
}
}
}
}
if (numFullLines > 0) {
numLinesRemoved += numFullLines;
statusBar.setText(String.valueOf(numLinesRemoved));
isFallingFinished = true;
currentPiece.setShape(Shape.Tetrominoes.NoShape);
repaint();
}
}
// 绘制单个方块
private void drawSquare(Graphics g, int x, int y, Shape.Tetrominoes shape) {
Color colors[] = { Color.black, Color.red, Color.green, Color.blue, Color.yellow, Color.magenta, Color.orange, Color.cyan };
Color color = colors[shape.ordinal()];
g.setColor(color);
g.fillRect(x, y, CELL_SIZE, CELL_SIZE);
g.setColor(color.brighter());
g.drawLine(x, y, x + CELL_SIZE - 1, y);
g.drawLine(x, y, x, y + CELL_SIZE - 1);
g.setColor(color.darker());
g.drawLine(x + 1, y + CELL_SIZE - 1, x + CELL_SIZE - 1, y + CELL_SIZE - 1);
g.drawLine(x + CELL_SIZE - 1, y + CELL_SIZE - 1, x + CELL_SIZE - 1, y + 1);
}
// 获取指定位置的方块形状
private Shape.Tetrominoes shapeAt(int x, int y) {
return board[(y * BOARD_WIDTH) + x];
}
@Override
public void actionPerformed(ActionEvent e) {
if (isFallingFinished) {
isFallingFinished = false;
newPiece();
} else {
oneLineDown();
}
}
// 键盘适配器类,用于处理用户输入
class TAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
if (!isStarted || currentPiece.getShape() == Shape.Tetrominoes.NoShape) {
return;
}
int keycode = e.getKeyCode();
if (keycode == 'p' || keycode == 'P') {
pause();
return;
}
if (isPaused) {
return;
}
switch (keycode) {
case KeyEvent.VK_LEFT:
tryMove(currentPiece, currentX - 1, currentY);
break;
case KeyEvent.VK_RIGHT:
tryMove(currentPiece, currentX + 1, currentY);
break;
case KeyEvent.VK_DOWN:
tryMove(currentPiece.rotateRight(), currentX, currentY);
break;
case KeyEvent.VK_UP:
tryMove(currentPiece.rotateLeft(), currentX, currentY);
break;
case KeyEvent.VK_SPACE:
dropDown();
break;
case 'd':
case 'D':
oneLineDown();
break;
}
}
}
// 主函数,启动Tetris游戏
public static void main(String[] args) {
JFrame frame = new JFrame("俄罗斯方块");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(320, 640);
frame.setLayout(new BorderLayout());
frame.setResizable(false); // 禁止调整窗口大小
JLabel statusBar = new JLabel("0");
frame.add(statusBar, BorderLayout.SOUTH);
Tetris game = new Tetris(statusBar);
frame.add(game, BorderLayout.CENTER);
frame.setVisible(true);
game.start();
}
}
源代码下载
https://download.csdn.net/download/qq_35759769/89401357https://download.csdn.net/download/qq_35759769/89401357
结论
这个项目不仅是一个有趣的游戏实现,还涵盖了Java编程中许多重要的概念和技术。通过学习和运行这个项目,您将对Java GUI编程、事件驱动编程和游戏开发有更深入的理解。这个俄罗斯方块游戏是一个很好的入门项目,同时也是进一步学习和扩展的良好基础。