俄罗斯方块(简单版)

news/2025/2/2 16:46:11/文章来源:https://www.cnblogs.com/Ryanjxy/p/18696577

csdn出处

package tetris;import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;public class Main extends JFrame implements KeyListener {private JTextArea[][] grids;// 把整个界面变为一个文本区域,整个游戏在里面进行private int data[][]; // 对于每个格子的数据,1代表有方块,0代表为空白区private int[] allRect; // 所有的方块类型,用16个字节来存储,俄罗斯方块图形都是在4*4格子里private int rect; // 当前游戏下落的方块类型;private int x, y; // 当前方块的坐标位置,x代表行,y代表列private int score = 0; // 记录当前游戏得分情况,每消一层得10分private JLabel label; // 显示分数的标签private JLabel label1;// 显示游戏是否结束private boolean running; // 用于判断游戏是否结束/*无参构造函数*/public Main() {grids = new JTextArea[26][12];//设置游戏区域行和列data = new int[26][12];//开辟data数组空间与游戏区域行和列一致allRect = new int[] { 0x00cc, 0x8888, 0x000f, 0x0c44, 0x002e, 0x088c, 0x00e8, 0x0c88, 0x00e2, 0x044c, 0x008e,0x08c4, 0x006c, 0x04c8, 0x00c6, 0x08c8, 0x004e, 0x04c4, 0x00e4 };//19种方块形状,如0x00cc就是   0000 表示一个2*2的正方形方块//0000//1100//1100label = new JLabel("score: 0"); //此标签存放得分情况,初始化为0分label1 = new JLabel("开始游戏"); //此标签为提示游戏状态:开始还是结束running = false; //为标志变量,false为游戏结束,true为游戏正在进行init(); // 游戏界面初始化}/*游戏界面初始化函数*/public void init() {JPanel center = new JPanel(); //此面板为游戏核心区域JPanel right = new JPanel(); //此面板为游戏说明区域center.setLayout(new GridLayout(26, 12, 1, 1)); //给游戏核心区域划分行、列共26行,12列for (int i = 0; i < grids.length; i++) {//初始化面板for (int j = 0; j < grids[i].length; j++) {grids[i][j] = new JTextArea(20, 20);grids[i][j].setBackground(Color.WHITE);grids[i][j].addKeyListener(this);// 添加键盘监听事件//初始化游戏边界if (j == 0 || j == grids[i].length - 1 || i == grids.length - 1) {grids[i][j].setBackground(Color.PINK);data[i][j] = 1;}grids[i][j].setEditable(false);// 文本区域不可编辑center.add(grids[i][j]); //把文本区域添加到主面板上}}//初始化游戏说明面板right.setLayout(new GridLayout(4, 1));right.add(new JLabel(" a : left        d : right"));right.add(new JLabel(" s : down   w : change"));right.add(label);label1.setForeground(Color.RED);// 设置标签内容为红色字体right.add(label1);//把主面板和说明面板添加到窗体中this.setLayout(new BorderLayout());this.add(center, BorderLayout.CENTER);this.add(right, BorderLayout.EAST);running = true; //初始化running状态为true,表示程序运行即游戏开始this.setSize(600, 850);// 设置窗体大小this.setVisible(true);// 窗体可见this.setLocationRelativeTo(null);// 设置窗体居中this.setResizable(false);// 窗体大小不可改变this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 释放窗体}/*主函数*/public static void main(String[] args) {Main m = new Main(); //创建Main对象,主要用于初始化数据m.go();// 开始游戏}/*开始游戏*/public void go() {// 开始游戏while (true) {//游戏开始直到游戏失败才结束,否则一直执行if (running == false) {//如果游戏失败break;}ranRect();// 绘制下落方格形状start();// 开始游戏}label1.setText("游戏结束!");//则游戏结束}/*绘制下落方格形状*/public void ranRect() {rect = allRect[(int) (Math.random() * 19)];// 随机生成方块类型(共7种,19个形状)}/*游戏开始函数*/public void start() {x = 0;y = 5; //初始化下落方块的位置for (int i = 0; i < 26; i++) {//共26层,一层一层下落try {Thread.sleep(1000);//每层延时1秒if (canFall(x, y) == false) {// 如果不可以掉落saveData(x, y);//把此方块区域data[][]标志为1,表示有数据for (int k = x; k < x + 4; k++) {//循环遍历4层,看是否有哪一层都有方块的情况,以便消除那一行方格和统计得分int sum = 0;for (int j = 1; j <= 10; j++) {if (data[k][j] == 1) {sum++;}}if (sum == 10) {//如果k层都有方块,则消除k层方块removeRow(k);}}for (int j = 1; j <= 10; j++) {//游戏最上面的4层不能有方块,否则游戏失败if (data[3][j] == 1) {running = false;break;}}break;}// 如果可以掉落x++;// 层加一fall(x, y);// 掉下来一层} catch (InterruptedException e) {e.printStackTrace();}}}/*判断正下落的方块是否可以下落*/public boolean canFall(int m, int n) {int temp = 0x8000;//表示1000 0000 0000 0000for (int i = 0; i < 4; i++) {//循环遍历16个方格(4*4)for (int j = 0; j < 4; j++) {if ((temp & rect) != 0) {// 此处有方块时if (data[m + 1][n] == 1)// 如果下一个地方有方块,则直接返回falsereturn false;}n++;//列加一temp >>= 1;}m++;// 下一行n = n - 4;// 回到首列}return true;//可以掉落返回true}/*把不可下降的方块的对应的data存储为1,表示此坐标有方块*/public void saveData(int m, int n) {int temp = 0x8000;//表示1000 0000 0000 0000for (int i = 0; i < 4; i++) {//循环遍历16个方格(4*4)for (int j = 0; j < 4; j++) {if ((temp & rect) != 0) {// 此处有方块时data[m][n] = 1;//data数组存放为1}n++;//下一列temp >>= 1;}m++;// 下一行n = n - 4;// 回到首列}}/*移除row行所有方块,以上的依次往下降*/public void removeRow(int row) {for (int i = row; i >= 1; i--) {for (int j = 1; j <= 10; j++) {data[i][j] = data[i - 1][j];//}}reflesh();// 刷新移除row行方块后的游戏主面板区域score += 10;// 分数加10;label.setText("score: " + score);//显示得分}/* 刷新移除row行方块后的游戏主面板区域*/public void reflesh() {for (int i = 1; i < 25; i++) {for (int j = 1; j < 11; j++) {if (data[i][j] == 1) {//有方块的地方把方块设置为绿色grids[i][j].setBackground(Color.GREEN);} else {//无方块的地方把方块设置为白色grids[i][j].setBackground(Color.WHITE);}}}}/*方块掉落一层*/public void fall(int m, int n) {if (m > 0)// 方块下落一层时clear(m - 1, n);// 清除上一层有颜色的方块draw(m, n);// 重新绘制方块图像}/*清除方块掉落之前有颜色的地方*/public void clear(int m, int n) {int temp = 0x8000;//表示1000 0000 0000 0000for (int i = 0; i < 4; i++) {//循环遍历16个方格(4*4)for (int j = 0; j < 4; j++) {if ((temp & rect) != 0) {// 此处有方块时grids[m][n].setBackground(Color.WHITE);//清除颜色,变为白色}n++;//下一列temp >>= 1;}m++;//下一行n = n - 4;//回到首列}}/*绘制掉落后方块图像*/public void draw(int m, int n) {int temp = 0x8000;//表示1000 0000 0000 0000for (int i = 0; i < 4; i++) {//循环遍历16个方格(4*4)for (int j = 0; j < 4; j++) {if ((temp & rect) != 0) {// 此处有方块时grids[m][n].setBackground(Color.GREEN);//有方块的地方变为绿色}n++;//下一列temp >>= 1;}m++;//下一行n = n - 4;//回到首列}}@Overridepublic void keyPressed(KeyEvent e) {}@Overridepublic void keyReleased(KeyEvent e) {}@Overridepublic void keyTyped(KeyEvent e) {if (e.getKeyChar() == 'a') {// 方格进行左移if (running == false) {return;}if (y <= 1)//碰到左边墙壁时return;int temp = 0x8000;//表示1000 0000 0000 0000for (int i = x; i < x + 4; i++) {//循环遍历16个方格(4*4)for (int j = y; j < y + 4; j++) {if ((rect & temp) != 0) {// 此处有方块时if (data[i][j - 1] == 1) {//如果左移一格有方块时return;}}temp >>= 1;}}clear(x, y);//可以进行左移操作时,清除左移前方块颜色y--;draw(x, y);//然后重新绘制左移后方块的图像}if (e.getKeyChar() == 'd') {//方块进行右移操作if (running == false) {return;}int temp = 0x8000;int m = x, n = y;int num = 7;for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if ((temp & rect) != 0) {if (n > num) {num = n;}}temp >>= 1;n++;}m++;n = n - 4;}if (num >= 10) {return;}temp = 0x8000;for (int i = x; i < x + 4; i++) {for (int j = y; j < y + 4; j++) {if ((rect & temp) != 0) {if (data[i][j + 1] == 1) {return;}}temp >>= 1;}}clear(x, y);//可以进行右移操作时,清除右移前方块颜色y++;draw(x, y);//然后重新绘制右移后方块的图像}if (e.getKeyChar() == 's') {//方块进行下移操作if (running == false) {return;}if (canFall(x, y) == false) {saveData(x, y);return;}clear(x, y);//可以进行下移操作时,清除下移前方块颜色x++;draw(x, y);//然后重新绘制下移后方块的图像}if (e.getKeyChar() == 'w') {//改变方块形状if (running == false) {return;}int i = 0;for (i = 0; i < allRect.length; i++) {//循环遍历19个方块形状if (allRect[i] == rect)//找到下落的方块对应的形状,然后进行形状改变break;}if (i == 0)//为正方形方块无需形状改变,为方块图形种类1return;clear(x, y);if (i == 1 || i == 2) {//为方块图形种类2rect = allRect[i == 1 ? 2 : 1];if (y > 7)y = 7;}if (i >= 3 && i <= 6) {//为方块图形种类3rect = allRect[i + 1 > 6 ? 3 : i + 1];}if (i >= 7 && i <= 10) {//为方块图形种类4rect = allRect[i + 1 > 10 ? 7 : i + 1];}if (i == 11 || i == 12) {//为方块图形种类5rect = allRect[i == 11 ? 12 : 11];}if (i == 13 || i == 14) {//为方块图形种类6rect = allRect[i == 13 ? 14 : 13];}if (i >= 15 && i <= 18) {//为方块图形种类7rect = allRect[i + 1 > 18 ? 15 : i + 1];}draw(x, y);}}
}

1.awt

(1)BorderLayout

Java AWT(Abstract Window Toolkit)中的一个布局管理器,用于将容器划分为五个区域:北(North)、南(South)、东(East)、西(West)和中(Center)。每个区域可以放置一个组件。

(2)Color

这个没啥说的

(3)GridLayout

布局管理器,将容器划分为一个网格,每个网格单元可以放置一个组件。它非常适合需要整齐排列多个组件的场景。
行数和列数:通过构造函数指定网格的行数和列数。
组件大小:所有组件的大小相同。

(4)KeyEvent

Java AWT 中的一个事件类,表示键盘事件,例如按键按下、按键释放或按键输入。
常用方法:
getKeyCode():获取按键的键码。
getKeyChar():获取按键的字符。
isShiftDown():判断是否按下了 Shift 键。
isControlDown():判断是否按下了 Ctrl 键。

(5) KeyListener

一个接口,用于监听键盘事件。它包含三个方法:
keyPressed(KeyEvent e):按键按下时触发。
keyReleased(KeyEvent e):按键释放时触发。
keyTyped(KeyEvent e):按键输入时触发。

2.swing

(1) JFrame

JFrame 是 Java Swing 中的一个类,用于创建窗口。它是 java.awt.Frame 的子类,提供了更丰富的功能和更好的跨平台支持。
常用方法:
setTitle(String title):设置窗口标题。
setSize(int width, int height):设置窗口大小。
setDefaultCloseOperation(int operation):设置窗口关闭时的操作。
setVisible(boolean b):设置窗口是否可见。
add(Component comp):向窗口中添加组件。

(2)JLabel

JLabel 是一个用于显示文本或图像的组件。它通常用于显示提示信息或装饰性内容。

setText(String text):设置标签的文本。
setIcon(Icon icon):设置标签的图标。
setHorizontalAlignment(int alignment):设置文本或图标的水平对齐方式。

(3)JPanel

JPanel 是一个通用的容器组件,可以容纳其他组件(如按钮、标签等)。它通常用于组织复杂的布局。
常用方法:
add(Component comp):向面板中添加组件。
setLayout(LayoutManager mgr):设置面板的布局管理器。
setBackground(Color color):设置面板的背景颜色。

(4)JTextArea

JTextArea 是一个用于显示多行文本的组件。它支持文本的输入和编辑,非常适合需要显示大量文本的场景。
常用方法:
setText(String text):设置文本内容。
append(String str):在文本末尾追加内容。
setEditable(boolean b):设置文本区域是否可编辑。

3.代码分析

(1)

     center.setLayout(new GridLayout(26, 12, 1, 1)); //给游戏核心区域划分行、列共26行,12列
      grids[i][j] = new JTextArea(20, 20);

第一个代码是对整个画面划分成26*12的网格,第二个代码则是默认每一个网格块大小为20*20(但实际上最终具体的大小参数会由网格的划分决定)
用简单的类比来说:
书架(GridLayout):有26层,每层12格 → 对应代码中的 GridLayout(26, 12)

书本(JTextArea):每本书默认尺寸是20cm宽×20cm高 → 对应 new JTextArea(20, 20)

但书架的管理员(布局管理器)会强制要求:

所有书本必须完全填满书架格子,无视书本自身的尺寸要求。

(2)

this.setLayout(new BorderLayout()); // 设置窗体的布局为 BorderLayout

BorderLayout 是一种常用的布局管理器,分为五个区域:NORTH(北部)、SOUTH(南部)、EAST(东部)、WEST(西部)和 CENTER(中心)。通过 add() 方法将两个面板添加到指定的位置。

代码注释基本比较清晰,在此只对于一些地方进行阐述和相对的注释

1.temp用16进制表示16位2进制的数(4*4方块),用来检测对应的下落块是否能继续下落以及是否可以进行左右下移动
2.其中reflesh函数通过每次对于整个界面方块的遍历使整体效果达到最底下消除后所有方块自由调整下落的效果
3.其中因为需使用KeyListener这个接口,所有必须对于接口中的函数进行重构(回应)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库安全管理中的权限控制:保护数据资产的关键措施

title: 数据库安全管理中的权限控制:保护数据资产的关键措施 date: 2025/2/2 updated: 2025/2/2 author: cmdragon excerpt: 在信息化迅速发展的今天,数据库作为关键的数据存储和管理中心,已经成为了企业营运和决策的核心所在。然而,伴随着数据规模的不断扩大和数据价值的…

动手学大模型应用开发,第3天:大模型开发流程及架构

一、大模型开发整体流程 1. 何为大模型开发 我们将开发以大语言模型为功能核心、通过大语言模型的强大理解能力和生成能力、结合特殊的数据或业务逻辑来提供独特功能的应用称为大模型开发。开发大模型相关应用,其技术核心点虽然在大语言模型上,但一般通过调用 API 或开源模型…

Omnissa Horizon 8 2412 (8.14) 发布 - 虚拟桌面基础架构 (VDI) 和应用软件

Omnissa Horizon 8 2412 (8.14) 发布 - 虚拟桌面基础架构 (VDI) 和应用软件Omnissa Horizon 8 2412 (8.14) - 虚拟桌面基础架构 (VDI) 和应用软件 之前称为 VMware Horizon, 通过高效、安全的虚拟桌面交付增强您的工作空间 请访问原文链接:https://sysin.org/blog/omnissa-hor…

VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) 1.21 - 运营商 Kubernetes 解决方案

VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) 1.21 - 运营商 Kubernetes 解决方案VMware Tanzu Kubernetes Grid Integrated Edition (TKGI) 1.21 - 运营商 Kubernetes 解决方案 Kubernetes-based container solution with advanced networking, a private contain…

关于 高精度性能计数器的频率 和 cpu 频率 不一致问题

/* rdtsc指令, 该指令返回CPU自启动以来的时钟周期数;该时钟周期数,即处理器的时间戳。在CPU通电启动后,首先会重置EDX和EAX,在每个时钟周期上升或下降沿到来时,会自动累计周期数,并被记录到EDX和EAX寄存器中,EDX是高位,EAX是低位。rdtsc指令就是从该寄存器中进行获取的…

《操作系统真象还原》第十一章 TSS与用户进程

本文介绍了TSS(Task State Segment)的概念及其在操作系统中的应用。TSS是用于存储任务状态的数据结构,每个任务都有自己的TSS,包含任务切换时需要保存和恢复的信息。Intel建议为每个任务关联一个TSS,CPU通过TR寄存器指向当前任务的TSS,实现任务切换。现代操作系统采用基于…

【渗透测试】Vulnhub GROTESQUE 1.0.1

渗透环境 攻击机: IP: 192.168.10.18(Kali) 靶机: IP:192.168.10.9 靶机下载地址:https://www.vulnhub.com/entry/grotesque-101,658/ 涉及知识点:WordPress扫描(WPScan)、WrodPress反弹shell、Keypass文件解密进行渗透 一、 获取端口信息 nmap或者arp-scan都能…

DeepSeek 全面指南,95% 的人都不知道的9个技巧(建议收藏)

大家好,我是汤师爷~ 最近,DeepSeek这款AI工具爆火国内外。 虽然许多人都开始尝试使用它,但有人吐槽说,没想象中那么牛。 其实问题不在工具,很多人的使用姿势就搞错了,用大炮打蚊子,白白浪费DeepSeek的强大功能。 接下来,我将为大家分享9个实用技巧,你会发现DeepSeek远…

ez_pz_hackover_2016(shellcode)

首先检查一下保护,发现没有开启NX保护,说明可以往栈上写shellcode 首先要确定距离ebp的偏移,还有shellcode的地址(将ret覆盖到shellcode的地址上)确定离ebp偏移的代码 from pwn import * io=process("./ez_pz_hackover_2016") context.log_level=debug gdb.atta…

Android Studio 2024 不需要三方插件,直接wifi 开发调试,真方便

在测试旧版本时,wifi插件折腾了几天,还是没折腾上,最后下载了最新Android Studio Ladybug Feature Drop | 2024.2.2版本,发现居然已经集成,且放到了最显眼的位置,wifi开发,一步到位了。手机中,进开发者模式,选中 无线调试 ,再点使用二维码配对设备然后扫码,即可,…

Maven高级 -2025/1/22

分模块开发 依赖管理 可选依赖 <dependency><groupId>com.itheima</groupId><artifactId>maven_03_pojo</artifactId><version>1.0-SNAPSHOT</version><!--可选依赖是隐藏当前工程所依赖的资源,隐藏后对应资源将不具有依赖传递-…