Java制作俄罗斯方块

Java俄罗斯方块小游戏

在这里插入图片描述

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class TetrisGame extends JFrame implements ActionListener, KeyListener {

    private final int BOARD_WIDTH = 10;
    private final int BOARD_HEIGHT = 20;
    private final int CELL_SIZE = 30;

    private Timer timer;
    private Board board;
    private Shape currentShape;

    public TetrisGame() {
        initUI();
    }

    private void initUI() {
        board = new Board();
        add(board);

        timer = new Timer(500, this);
        timer.start();

        setTitle("俄罗斯方块游戏");
        setSize(BOARD_WIDTH * CELL_SIZE, BOARD_HEIGHT * CELL_SIZE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        addKeyListener(this);
        setFocusable(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            TetrisGame tetrisGame = new TetrisGame();
            tetrisGame.setVisible(true);
        });
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 定时器触发,尝试向下移动当前方块
        if (board.canMoveDown(currentShape)) {
            currentShape.moveDown();
        } else {
            // 如果无法继续下移,将当前方块加入游戏板并生成新的方块
            board.addShape(currentShape);
            currentShape = new Shape();
            if (!board.canMoveDown(currentShape)) {
                // 如果新生成的方块无法下移,游戏结束
                timer.stop();
                JOptionPane.showMessageDialog(this, "游戏结束!");
                System.exit(0);
            }
        }
        repaint();
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        // 根据按键事件执行相应操作
        if (e.getKeyCode() == KeyEvent.VK_LEFT && board.canMoveLeft(currentShape)) {
            // 左移
            currentShape.moveLeft();
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT && board.canMoveRight(currentShape)) {
            // 右移
            currentShape.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN && board.canMoveDown(currentShape)) {
            // 下移
            currentShape.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_SPACE && board.canRotate(currentShape)) {
            // 旋转
            currentShape.rotate();
        }
        repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    // 游戏板
    class Board extends JPanel {

        private boolean[][] filledCells;

        public Board() {
            filledCells = new boolean[BOARD_HEIGHT][BOARD_WIDTH];
            currentShape = new Shape();
        }

        // 判断是否可以左移
        public boolean canMoveLeft(Shape shape) {
            for (Cell cell : shape.getCells()) {
                if (cell.getX() <= 0 || filledCells[cell.getY()][cell.getX() - 1]) {
                    return false;
                }
            }
            return true;
        }

        // 判断是否可以右移
        public boolean canMoveRight(Shape shape) {
            for (Cell cell : shape.getCells()) {
                if (cell.getX() >= BOARD_WIDTH - 1 || filledCells[cell.getY()][cell.getX() + 1]) {
                    return false;
                }
            }
            return true;
        }

        // 判断是否可以下移
        public boolean canMoveDown(Shape shape) {
            for (Cell cell : shape.getCells()) {
                if (cell.getY() >= BOARD_HEIGHT - 1 || filledCells[cell.getY() + 1][cell.getX()]) {
                    return false;
                }
            }
            return true;
        }

        // 判断是否可以旋转
        public boolean canRotate(Shape shape) {
            Shape rotatedShape = shape.getRotatedShape();
            for (Cell cell : rotatedShape.getCells()) {
                if (cell.getX() < 0 || cell.getX() >= BOARD_WIDTH || cell.getY() >= BOARD_HEIGHT || filledCells[cell.getY()][cell.getX()]) {
                    return false;
                }
            }
            return true;
        }

        // 将方块加入已填充单元格
        public void addShape(Shape shape) {
            for (Cell cell : shape.getCells()) {
                filledCells[cell.getY()][cell.getX()] = true;
            }
            clearLines();
        }

        // 消除满行
        private void clearLines() {
            for (int i = BOARD_HEIGHT - 1; i >= 0; i--) {
                boolean isFullLine = true;
                for (int j = 0; j < BOARD_WIDTH; j++) {
                    if (!filledCells[i][j]) {
                        isFullLine = false;
                        break;
                    }
                }
                if (isFullLine) {
                    moveLinesDown(i);
                }
            }
        }

        // 将上方所有行向下移动
        private void moveLinesDown(int row) {
            for (int i = row; i > 0; i--) {
                for (int j = 0; j < BOARD_WIDTH; j++) {
                    filledCells[i][j] = filledCells[i - 1][j];
                }
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            drawBoard(g);
            drawShape(g, currentShape);
        }

        // 绘制游戏板
        private void drawBoard(Graphics g) {
            for (int i = 0; i < BOARD_HEIGHT; i++) {
                for (int j = 0; j < BOARD_WIDTH; j++) {
                    if (filledCells[i][j]) {
                        g.setColor(Color.BLUE);
                        g.fillRect(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                        g.setColor(Color.BLACK);
                        g.drawRect(j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                    }
                }
            }
        }

        // 绘制方块
        private void drawShape(Graphics g, Shape shape) {
            for (Cell cell : shape.getCells()) {
                g.setColor(Color.RED);
                g.fillRect(cell.getX() * CELL_SIZE, cell.getY() * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                g.setColor(Color.BLACK);
                g.drawRect(cell.getX() * CELL_SIZE, cell.getY() * CELL_SIZE, CELL_SIZE, CELL_SIZE);
            }
        }
    }

    // 单元格
    class Cell {
        private int x;
        private int y;

        public Cell(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }

    // 方块
    class Shape {
        private List<Cell> cells;

        public Shape() {
            cells = new ArrayList<>();
            // 初始化形状
            Random random = new Random();
            int shapeType = random.nextInt(7); // 0 到 6
            switch (shapeType) {
                case 0: // I
                    cells.add(new Cell(3, 0));
                    cells.add(new Cell(3, 1));
                    cells.add(new Cell(3, 2));
                    cells.add(new Cell(3, 3));
                    break;
                case 1: // J
                    cells.add(new Cell(4, 0));
                    cells.add(new Cell(4, 1));
                    cells.add(new Cell(4, 2));
                    cells.add(new Cell(3, 2));
                    break;
                case 2: // L
                    cells.add(new Cell(3, 0));
                    cells.add(new Cell(3, 1));
                    cells.add(new Cell(3, 2));
                    cells.add(new Cell(4, 2));
                    break;
                case 3: // O
                    cells.add(new Cell(4, 0));
                    cells.add(new Cell(4, 1));
                    cells.add(new Cell(3, 0));
                    cells.add(new Cell(3, 1));
                    break;
                case 4: // S
                    cells.add(new Cell(4, 1));
                    cells.add(new Cell(3, 1));
                    cells.add(new Cell(3, 0));
                    cells.add(new Cell(2, 0));
                    break;
                case 5: // T
                    cells.add(new Cell(3, 0));
                    cells.add(new Cell(3, 1));
                    cells.add(new Cell(3, 2));
                    cells.add(new Cell(4, 1));
                    break;
                case 6: // Z
                    cells.add(new Cell(2, 1));
                    cells.add(new Cell(3, 1));
                    cells.add(new Cell(3, 0));
                    cells.add(new Cell(4, 0));
                    break;
            }
        }

        public List<Cell> getCells() {
            return cells;
        }

        // 左移
        public void moveLeft() {
            for (Cell cell : cells) {
                cell.x--;
            }
        }

        // 右移
        public void moveRight() {
            for (Cell cell : cells) {
                cell.x++;
            }
        }

        // 下移
        public void moveDown() {
            for (Cell cell : cells) {
                cell.y++;
            }
        }

        // 旋转
        public void rotate() {
            int centerX = cells.get(1).getX();
            int centerY = cells.get(1).getY();

            for (Cell cell : cells) {
                int x = cell.getX() - centerX;
                int y = cell.getY() - centerY;

                cell.x = centerX - y;
                cell.y = centerY + x;
            }
        }

        // 获取旋转后的形状
        public Shape getRotatedShape() {
            Shape rotatedShape = new Shape();
            rotatedShape.cells.clear();
            rotatedShape.cells.addAll(this.cells);
            rotatedShape.rotate();
            return rotatedShape;
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

open3d ICP 配准

文章目录 Three common registration techniquesPoint-to-point techniquePoint-to-plane registration ICP registrationHelper visualization functionInputGlobal registrationExtract geometric featureInputRANSAC Point-to-point ICPPoint-to-plane ICP References Three…

搭建Android自动化python+appium环境

一. 需要软件 JDK:JAVA安装后配置JDK环境 SDK:SDK下载后配置adb环境 Python:pyhton语言 Pycharm:python脚本编译工具 Appium-python-client:pyhton中的库Appium客户端 二. 搭建步骤 1.配置JDK环境 ①. 下载安装java: https://www.oracle.com/java/technologies/javase-j…

语音特征提取: 梅尔频谱(Mel-spectrogram)与梅尔倒频系数(MFCCS)

1 核心概念 1.1 语音信号 语音信号是一个非平稳的时变信号&#xff0c;但语音信号是由声门的激励脉冲通过声道形成的&#xff0c;经过声道(人的三腔&#xff0c;咽口鼻)的调制&#xff0c;最后由口唇辐射而出。认为“短时间”(帧长/窗长&#xff1a;10~30ms)内语音信号是平稳…

Unity中Shader法线贴图(下)理论篇

文章目录 前言一、采样出错的原因二、切线空间是什么&#xff1f;切线空间图解&#xff1a; 三、计算方式1、统一变换到切线空间下进行计算2、统一变换到世界空间下进行计算 四、一般统一变换到世界空间下的坐标进行计算1、求M^-1^2、求出n~w~ 前言 这篇文章&#xff0c;主要解…

【Kettle实战】字符串处理及网络请求JSON格式处理

经过大量的kettle操作实践&#xff0c;我们会渐渐掌握一些技巧&#xff0c;大大减轻清洗的工作量。比如在哪里 处理字符串更方便&#xff0c;在哪儿处理更合理都是一个取舍问题。 字符串拼接 MySQL中使用concat(字段1,字段2)&#xff0c;但是如果“字段2”为NULL&#xff0c;结…

如何挖掘xss漏洞

如何挖掘xss漏洞 对于如何去挖掘一个xss漏洞我是这样理解的 在实战情况下不能一上来就使用xss语句来进行测试很容易被发现 那这种情况该怎么办呢 打开准备渗透测试的web网站&#xff0c;寻找可以收集用户输入的地方比如搜索框&#xff0c;url框等 发现后寻找注入点 选在输入…

【Q1—45min】

1.epoll除了边沿触发还有什么&#xff1f;与select区别. epoll 是Linux平台下的一种特有的多路复用IO实现方式&#xff0c;与传统的 select 相比&#xff0c;epoll 在性能上有很大的提升。 epoll是一种当文件描述符的内核缓冲区非空的时候&#xff0c;发出可读信号进行通知&…

Find My蓝牙耳机|苹果Find My技术与耳机结合,智能防丢,全球定位

蓝牙耳机就是将蓝牙技术应用在免持耳机上&#xff0c;让使用者可以免除恼人电线的牵绊&#xff0c;自在地以各种方式轻松通话。自从蓝牙耳机问世以来&#xff0c;一直是行动商务族提升效率的好工具。正是应为蓝牙耳机小巧无线&#xff0c;人们越来越喜欢随身携带蓝牙耳机出门&a…

人民网_领导留言板data2022年-2023年

人民网_领导留言板data_2022年全年-2023年11月数据_全国任意城市 包含且不限于&#xff1a;留言ID,留言对象,留言标题,种类名,领域名,目前状态,留言日期,留言内容,回复机构,回复时间,回复内容,满意度,解决力度,沟通态度,办理时效 对于有需要爬取领导留言板的朋友&#xff0c;…

【Qt开发流程之】布局管理

介绍 一个界面呈现&#xff0c;如果要让用户有更好的观感&#xff0c;布局必不可少。 【Qt之布局】QVBoxLayout、QHBoxLayout、QGridLayout、QFormLayout介绍及使用 链接: https://blog.csdn.net/MrHHHHHH/article/details/133915208 qt布局类图&#xff1a; Qt布局是Qt图形…

echarts的使用

1. 普通版 其实主要就是option1&#xff0c;option1就是画的图 echats不能响应刷新&#xff0c;要想实时刷新监听刷新的值重新调用一下方法即可 html <div class"echart" style"width: 100%;height: calc(100% - 130px)" ref"main1">&l…

生物医药行业密钥管理系统特点 安当加密

生物医药行业密钥管理系统的特点主要表现在以下几个方面&#xff1a; 安全性&#xff1a;生物医药行业涉及的数据往往具有极高的私密性和敏感性&#xff0c;因此&#xff0c;密钥管理系统必须具备极高的安全性。这包括对密钥的生成、存储、传输和使用等各个环节进行严格的管理和…

广州一母婴店因设置0元购导致关店

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 广州的一家母婴用品网店Minitutu因双十一优惠券设置错误&#xff0c;导致所有商品变成0元购买&#xff0c;引发消费者疯狂抢购&#xff0c;15万多单订单中有800多万元的损失。店家无奈之下只能暂停营…

亚马逊,shopee,lazada自养号测评:提高店铺曝光,增加产品销量

如何在较短的时间内让自己的店铺排名升高&#xff0c;提高产品销量&#xff0c;除了依靠选品和广告之外&#xff0c;亚马逊测评 在店铺的运营中也是必不可少的环节。 自养号测评对亚马逊卖家来说&#xff0c;是运营店铺的重要手段之一。一个产品想要有更好的曝光、更高的转化率…

优卡特脸爱云一脸通智慧管理平台权限绕过漏洞复现【CVE-2023-6099】

优卡特脸爱云一脸通智慧管理平台权限绕过漏洞复现【CVE-2023-6099】 一、 产品简介二、 漏洞概述三、 影响范围四、 复现环境五、 漏洞复现手动复现自动化复现(小龙POC开源) 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信…

OSCP系列靶场-Esay-DC-1

目录 总结 准备工作 信息收集-端口扫描 目标开放端口收集 目标端口对应服务探测 信息收集-端口测试 22-SSH端口的信息收集 22-SSH端口版本信息与MSF利用(pass) 22-SSH手动登录尝试(失败) 22-SSH弱口令爆破(爆破着玩) 80-HTTP端口的信息收集 信息收集-网站指纹 漏洞…

水库大坝安全监测系统守护水利工程安全的坚实后盾

WX-WY1 随着社会经济的发展和科技的进步&#xff0c;水利工程的安全问题越来越受到人们的关注。水库大坝作为水利工程的重要组成部分&#xff0c;其安全状况直接关系到周边地区人民的生命财产安全和生态环境。因此&#xff0c;建立一个高效、可靠的水库大坝安全监测系统至关重要…

【2021集创赛】NI杯三等奖:基于IECUBE-3100的高精度数模转换器设计及自动化测试方案

本作品参与极术社区组织的有奖征集|秀出你的集创赛作品风采,免费电子产品等你拿~活动。 杯赛题目&#xff1a;DAC芯片测试 参赛要求&#xff1a;本科生组 赛题内容&#xff1a; NIC公司最近正在竞争一个8bit DAC芯片设计的订单机会&#xff0c;需要按照甲方需求尽快提交芯片的设…

二百零四、Flume——登录监听窗口报错Ncat: bind to :::44444: Address already in use. QUITTING.

一、目的 Flume安装好后测试开启监听窗口44444&#xff0c;结果报错Ncat: bind to :::44444: Address already in use. QUITTING. 二、报错详情 Ncat: bind to :::44444: Address already in use. QUITTING. 三、报错原因 经过分析发现&#xff0c;44444窗口已经被占用 […

在UOS系统中编译CEF源码

一、下载cef代码 git clone gitbitbucket.org:chromiumembedded/cef.git 二、执行自动下载代码 由于chromium的代码很大&#xff0c;至少需要准备大概80G的硬盘&#xff01;&#xff01;&#xff01;整个代码量太大还是多准备一些空间吧&#xff08;强烈建议使用固态硬盘保存否…