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

news2025/1/19 11:23:08

这是一个用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编程、事件驱动编程和游戏开发有更深入的理解。这个俄罗斯方块游戏是一个很好的入门项目,同时也是进一步学习和扩展的良好基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1790324.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Qt】Qt Style Sheets (QSS) 指南:打造个性化用户界面

文章目录 前言&#xff1a;1. QSS 选择器2. 子控件选择器&#xff08;Sub-Controls&#xff09;2.1. 示例&#xff1a;给 QComboBox 给下拉按钮加上图标2.2. 示例&#xff1a;修改进度条颜色 3. 伪类选择器3.1. 代码示例: 设置按钮的伪类样式.3.2. 代码示例: 使用事件方式实现同…

想要成长就要持续地学习,而如何学习更有效率呢

为什么很多人学了知识&#xff0c;但是总感觉记不住&#xff0c;用不上呢&#xff1f; 在学习的过程中&#xff0c;为什么总感觉没什么进步呢&#xff1f; 看了很多书&#xff0c;为什么总感觉没什么用呢&#xff1f; 要说明这些问题&#xff0c;首先我们要知道一个好的、完整的…

语言模型测试系列【9】

语言模型 文心一言讯飞星火通义千问2.5豆包360智脑百小应腾讯元宝KimiC知道 好长时间没有做语言模型的测试了&#xff0c;一方面是没有好的素材&#xff0c;各模型都在升级优化&#xff0c;而且频率很高&#xff1b;另一方面近期在阅读和学习其他的知识&#xff0c;所以更的也…

阿里影业业绩大涨,除了沸腾的文娱市场还有什么原因?

影视文娱市场的火热仍在延续&#xff0c;新定档的电影和演出&#xff0c;不断引人关注这个行业的生机。而这个行业的支持者、受益者&#xff0c;就站在一线。 5月29日晚&#xff0c;阿里影业发布截至2024年3月31日的2024财年业绩公告。社会文娱消费的热情&#xff0c;对优质项…

怎么等比例缩小图片尺寸?这四种方法肯定可以帮到你!

怎么等比例缩小图片尺寸&#xff1f;在当今日常生活中&#xff0c;图片文件是我们不可或缺的一部分&#xff0c;它们以各种形式出现&#xff0c;从社交媒体上的照片到工作文档中的插图&#xff0c;然而&#xff0c;随之而来的问题是&#xff0c;有时这些图片文件的尺寸过大&…

Linux---用户及权限配置

文章目录 目录 文章目录 前言 一.基本概念 二.用户管理 创建用户 修改用户属性 用户组管理 用户授权 前言 用户在操作系统中是非常重要的&#xff0c;我们登录系统&#xff0c;访问共享文件夹等都需要用户进行验证。所以&#xff0c;掌握管理用户的知识非常有必要的 一.基…

Java Web学习笔记2——Web开发介绍

什么是Web&#xff1f; Web&#xff1a;全球广域网&#xff0c;也称为万维网&#xff08;WWW World Wide Web&#xff09;&#xff0c;能够通过浏览器访问的网站。 1&#xff09;淘宝、京东、唯品会等电商系统&#xff1b; 2&#xff09;CRM、OA、ERP企业管理系统&#xff1…

解锁财富新篇章:消费增值模式引领未来消费趋势

你是否曾对日常消费感到一丝单调&#xff0c;认为它仅仅是一种物质上的交换&#xff0c;而非财富增长的途径&#xff1f;那么&#xff0c;让我们为你打开一扇全新的消费之门——消费增值模式。这不仅是一种全新的消费体验&#xff0c;更是一种让你的资金在消费过程中不断积累与…

【并发】Synchronized的底层原理

基本概念 Synchronized【对象锁】采用互斥的方式让同一时刻最多只有一个线程能够持有【对象锁】&#xff0c;如果其他线程想要获取这个【对象锁】就会被阻塞住 底层实现原理 我们可能听过&#xff0c;synchronized底层是通过Monitor来实现的&#xff0c;但如何直观的观察呢&…

kingbase重置序列

1、建立表接口 drop table if exists ncc_apple; CREATE TABLE ncc_apple ( id BIGSERIAL NOT null PRIMARY KEY, apple_name VARCHAR(128), creator BIGINT, create_time timestamp DEFAULT CURRENT_TIMESTAMP, updater INT8, update_time timestamp …

欧洲历史的五个阶段

欧洲的历史基本上都是分裂的&#xff0c;大致可以分为五个时期&#xff0c;分别为古希腊时代、罗马帝国时代、中世纪时代&#xff0c;文艺复兴时代、工业革命时代。 一&#xff0c;古希腊时代 古希腊是西方文明的源头&#xff0c;也是最重要和最直接的文明起源&#xff0c;首…

2024年社会发展与管理创新科学国际学术会议(ICSDMIS 2024)

2024年社会发展与管理创新科学国际学术会议&#xff08;ICSDMIS 2024&#xff09; 2024 International Conference on Social Development and Management Innovation Science&#xff08;ICSDMIS 2024&#xff09; 会议简介&#xff1a; 2024年社会发展与管理创新科学国际学术…

ClickHouse内幕(1)数据存储与过滤机制

本文主要讲述ClickHouse中的数据存储结构&#xff0c;包括文件组织结构和索引结构&#xff0c;以及建立在其基础上的数据过滤机制&#xff0c;从Part裁剪到Mark裁剪&#xff0c;最后到基于SIMD的行过滤机制。 数据过滤机制实质上是构建在数据存储格式之上的算法&#xff0c;所…

MAB规范(1):概览介绍

前言 MATLAB的MAAB&#xff08;MathWorks Automotive Advisory Board&#xff09;建模规范是一套由MathWorks主导的建模指南&#xff0c;旨在提高基于Simulink和Stateflow进行建模的代码质量、可读性、可维护性和可重用性。这些规范最初是由汽车行业的主要厂商共同制定的&…

Python语法详解module2(运算符、表达式、流程控制)

目录 一、运算符1. 算术运算符&#xff08;Arithmetic Operators&#xff09;2. 比较运算符&#xff08;Comparison Operators&#xff09;3. 赋值运算符&#xff08;Assignment Operators&#xff09;4. 逻辑运算符&#xff08;Logical Operators&#xff09;5. 位运算符&…

低代码专题 | 什么是低代码?低代码是什么意思?最详细解释!

什么是低代码&#xff0c;低代码是什么意思&#xff1f;低代码到底有什么用&#xff1f;企业该如何用低代码赋能&#xff1f;......因为现在太多碎片化信息了&#xff0c;所以大家对于一个概念的理解都是零散的。 故给大家开一个专题&#xff0c;将低代码给大家掰开揉碎了讲清…

[C++]vector的模拟实现

下面是简单的实现vector的功能&#xff0c;没有涉及使用内存池等复杂算法来提高效率。 一、vector的概述 &#xff08;一&#xff09;、抽象数据类型定义 容器&#xff1a;向量&#xff08;vector&#xff09;vector是表示大小可以变化的数组的序列容器。像数组一样&#xf…

JavaWeb基础(JQuery,XML及解析)

这个阶段有点拖沓了&#xff0c;因为事情比较多&#xff0c;耽搁了一段时间&#xff0c;学习的主要内容为JQuery和XML&#xff0c;因为vue的出现&#xff0c;JQuery技术现在已经不流行了&#xff0c;但是不流行不代表我不会&#xff0c;JQuery最最最最核心的就是他的$()核心函数…

关于yolov8识别滑块关键点

1,images,annotations创建 IMAGES:放图片材料的 ANNTATIONS:放labelImg标记的xml文件 2,labels,txt怎么来的 labels :可以手动创建,里面还配置了train,val,test文件夹。可手动(以下代码中没有写) txt:由一下代码自动生成,前提是images,annotations需要自己去创建 …

从零入手人工智能(1)——卷积神经网络

1.前言 本人作为一名单片机工程师&#xff0c;近期对人工智能领域产生了浓厚的兴趣&#xff0c;并开始了我的探索之旅。人工智能是一个博大精深的领域&#xff0c;我相信有许多志同道合的朋友也希望涉足这个领域&#xff0c;因此我写下这篇文章&#xff0c;旨在详细记录我学习…