Java实现俄罗斯方块游戏源代码(启动即可玩)

这是一个用Java Swing实现的俄罗斯方块游戏,具有经典的游戏机制和图形界面。游戏中,玩家需要旋转和移动不断下落的方块,使其填满一行来消除该行并得分。

该项目适合学习Java GUI编程、游戏开发基础以及面向对象编程(OOP)概念。

功能特性
  1. 图形界面

    • 使用Java Swing库实现用户界面。
    • 提供直观的游戏界面,显示当前下落的方块和游戏得分。
  2. 游戏逻辑

    • 方块自动下落,玩家可以通过键盘控制方块的移动和旋转。
    • 当方块填满一行时,该行会被消除,玩家得分增加。
    • 游戏结束时,显示最终得分并停止游戏。
  3. 控件说明

    • 左右箭头键:移动方块左右。
    • 上箭头键:旋转方块(顺时针)。
    • 下箭头键:旋转方块(逆时针)。
    • 空格键:快速下落方块。
    • 'D'键:快速下降一行。
    • 'P'键:暂停和继续游戏。
  4. 扩展性

    • 代码结构清晰,便于扩展和修改,例如添加新的方块形状或改变下落速度。
    • 通过调整计时器的延迟,可以轻松改变游戏难度。
技术亮点
  1. 面向对象编程

    • 使用类和对象封装游戏中的方块形状、游戏逻辑和界面。
    • 代码模块化,便于理解和维护。
  2. 事件驱动编程

    • 使用键盘事件和计时器事件控制游戏流程。
    • 实现了对用户输入的实时响应,使游戏更加流畅。
  3. 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/89401357icon-default.png?t=N7T8https://download.csdn.net/download/qq_35759769/89401357

结论

这个项目不仅是一个有趣的游戏实现,还涵盖了Java编程中许多重要的概念和技术。通过学习和运行这个项目,您将对Java GUI编程、事件驱动编程和游戏开发有更深入的理解。这个俄罗斯方块游戏是一个很好的入门项目,同时也是进一步学习和扩展的良好基础。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值