俄罗斯方块(详解)

2024-06-09 13:18
文章标签 详解 方块 俄罗斯

本文主要是介绍俄罗斯方块(详解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

几个重要的细节问题:

1、控件的布局问题:只有将布局方式设置为null,才能通过setBounds设置大小和位置

2、分层模式,内部类方式:各个类之间的相互的交流

3、事件的监听:键盘监听,失去焦点问题

4、碰壁问题:多画一行和一列

5、移动:判断是否碰壁方法不动,通过不同方式和所传的参数的不同,从而实现各种动作

package tetris3;import java.awt.Color;
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.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.Timer;
import javax.swing.border.TitledBorder;import tetris2.NextBlock;public class Tetris extends JFrame {public static boolean isPlay=true;//设置是否点击暂停Model tPanel;//方块面板JMenuItem jitemPause ;//暂停菜单项int grade = 0, rank = 1,numb = 1;//初始化基本数据JLabel score, level;NextBlock nextBlockPanel;//下一块的面板Color bgColor = Color.black, blockColor = Color.yellow;//颜色public Tetris() {super("俄罗斯方块");this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭控件this.setSize(378, 496);this.setLocationRelativeTo(null);//设置窗口居中setPanel();//布局addMenu();// 添加菜单this.setResizable(false);//设置窗口大小不能改变}//设置下一块的颜色public void setNextBlock(){this.nextBlockPanel.repaint();}//设置移动块的颜色public void setBlockColor(Color c){tPanel.setBlockColor(c);}//获取已经堆积块的颜色public Color getModelColor(){return tPanel.ModelColor;}//设置背景颜色public void setBGColor(Color c){bgColor=c;tPanel.setBackground(bgColor);}//设置已堆积块的颜色public void setModelColor(Color c){tPanel.setModelColor(c);}//设置分数public void setScore(int s){score.setText(""+s);}//设置下一块的颜色public void setNextBg(Color c){nextBlockPanel.setBg(c);}//设置等级public void setGrade(int s){level.setText(""+s);}//控制暂停菜单项中的暂停和继续间的切换public void setPause(boolean b){String str;if(b){str="continue";}else{str="pause";}jitemPause.setText(str);}//获取下一块的信息public NextBlock getNextBlock(){this.nextBlockPanel.repaint();return this.nextBlockPanel;}//<span style="color:#ff0000;">设置布局面板,这里要注意,要是添加按钮,文本编辑控件,都会失去焦点,使运行面板不能实现键盘监听,可以通过内部的类是其失去焦点,//为了避免不必要的错误,尽量不要用吧,这里慎重啊。还有记得设置这些面板布局方式为空,只有这样才能保证这些添加的控件能在规定的位置//正确的显示</span>.public void setPanel() {nextBlockPanel = new NextBlock();tPanel = new Model();tPanel.setBackground(bgColor);this.getContentPane().add(tPanel);this.addKeyListener(tPanel.listener);JPanel controlPanel = new JPanel();controlPanel.setLayout(null);controlPanel.setBorder(new TitledBorder("Control And Show"));JLabel nextBlockShape = new JLabel("Next Block Shape");nextBlockShape.setBounds(10, 20, 100, 20);controlPanel.add(nextBlockShape);nextBlockPanel.setBounds(0, 50, 120, 80);nextBlockPanel.repaint();controlPanel.add(nextBlockPanel);JLabel scoreLabel = new JLabel("Score");scoreLabel.setBounds(40, 120, 100, 60);controlPanel.add(scoreLabel);score = new JLabel("0");score.setBounds(15, 160, 108, 20);controlPanel.add(score);JLabel levelLabel = new JLabel("Level");levelLabel.setBounds(40, 160, 100, 100);controlPanel.add(levelLabel);level = new JLabel("1");level.setBounds(15, 220, 108, 20);controlPanel.add(level);JLabel jl1=new JLabel("注意自我保护,");jl1.setBounds(15, 280, 108, 30);JLabel jl2=new JLabel("适度游戏益脑,");jl2.setBounds(15, 310, 108, 30);JLabel jl3=new JLabel("合理安排时间,");jl3.setBounds(15, 340, 108, 30);JLabel jl4=new JLabel("享受健康生活。");jl4.setBounds(15, 370, 108, 30);controlPanel.add(jl1);controlPanel.add(jl2);controlPanel.add(jl3);controlPanel.add(jl4);this.getContentPane().add(controlPanel);JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tPanel,controlPanel);// 水平分隔窗格,左右各添加一个面板split.setDividerLocation(241);// 设置水平分隔条的位置split.setEnabled(false);// 设置分隔条不能变动this.getContentPane().add(split);// 框架内容窗格添加分隔窗格}//添加菜单private void addMenu() {JMenuBar menubar = new JMenuBar();this.setJMenuBar(menubar);JMenu game = new JMenu("Game");JMenu information = new JMenu("Information");JMenuItem informationOne = new JMenuItem("Author:xjj");JMenuItem informationTwo = new JMenuItem("Blog:http://blog.csdn.net/u011479875");information.add(informationOne);information.add(informationTwo);JMenuItem jitemNew = new JMenuItem("New Game");jitemNew.setActionCommand("new");jitemNew.addActionListener(new MenuListener());jitemPause = new JMenuItem("Pause");jitemPause.setActionCommand("pause");jitemPause.addActionListener(new MenuListener());JMenuItem jitemSetBlcokGb = new JMenuItem("BlockColor");jitemSetBlcokGb.setActionCommand("blcokbg");jitemSetBlcokGb.addActionListener(new MenuListener());JMenuItem jitemBg = new JMenuItem("BackgroundColor");jitemBg.setActionCommand("bg");jitemBg.addActionListener(new MenuListener());JMenuItem jitemModel = new JMenuItem("ModelColor");jitemModel.setActionCommand("model");jitemModel.addActionListener(new MenuListener());JMenuItem jitemExit = new JMenuItem("Exit");jitemExit.setActionCommand("exit");jitemExit.addActionListener(new MenuListener());game.add(jitemNew);game.add(jitemPause);game.addSeparator();// 菜单里设置分隔线game.add(jitemSetBlcokGb);game.add(jitemBg);game.add(jitemModel);game.addSeparator();// 菜单里设置分隔线game.add(jitemExit);menubar.add(game);menubar.add(information);}//监听类,这里写成内部类的形式的好处是,能够调用直接调用上面的一下成员变量,和方法,避免传参。class MenuListener implements ActionListener {public MenuListener() {}public void actionPerformed(ActionEvent e) {if(e.getActionCommand().equalsIgnoreCase("exit")){System.exit(EXIT_ON_CLOSE);}if(e.getActionCommand().equalsIgnoreCase("pause")){if(Tetris.isPlay){tPanel.timer.stop();}else{tPanel.timer.start();}setPause(Tetris.isPlay);Tetris.isPlay=!Tetris.isPlay;}if(e.getActionCommand().equalsIgnoreCase("blcokbg")){Color c=JColorChooser.showDialog(tPanel, "颜色", Color.black);if(c.equals(bgColor)){JOptionPane.showMessageDialog(tPanel, "背景色不能和块色相同");return ;}setBlockColor(c);}if(e.getActionCommand().equalsIgnoreCase("bg")){Color c=JColorChooser.showDialog(tPanel, "颜色", Color.black);if(c.equals(blockColor) || c.equals(getModelColor())){JOptionPane.showMessageDialog(tPanel, "背景色不能和块色相同");return ;}setBGColor(c);}if(e.getActionCommand().equalsIgnoreCase("model")){Color c=JColorChooser.showDialog(tPanel, "颜色", Color.black);if(c.equals(bgColor)){JOptionPane.showMessageDialog(tPanel, "背景色不能和块色相同");return ;}setModelColor(c);}if(e.getActionCommand().equalsIgnoreCase("new")){grade = 0;rank = 1;numb = 1;setScore(0);setGrade(1);tPanel.newGame();tPanel.repaint();}}}//<span style="color:#ff0000;">方块面板。这里写成内部类一样是为了实现两个类之间的交流,而且不需要传参,这种结构很好用</span>class Model extends JPanel{public TimeListener listener = new TimeListener();//监听器public int blockType=0,turnState=0,x=0,y,score=0,delay=1000,level=1;Timer timer;//定时器Color ModelColor=Color.red,BlockColor=Color.blue;NextBlock nextBlock;//下一块块public int[][] map = new int[100][100];//地图int[][][] shapes = new int[][][] {//几种图形,这里也可以使用二维数组,只不过要换成16进制形式,然后通过位运算计算// I{ { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 },{ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 } },// S{ { 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },{ 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } },// Z{ { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } },// J{ { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 },{ 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },// O{ { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },// L{ { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 },{ 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },{ 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },// T{ { 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },{ 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },{ 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } };public Model() {nextBlk();newGame();timer = new Timer(delay, listener);timer.start();}//设置堆积块颜色public void setModelColor(Color c) {this.ModelColor=c;repaint();}//设置移动块颜色public void setBlockColor(Color c) {this.BlockColor=c;repaint();}//初始化数据public void newGame() {blockType=0;turnState=0;x=4;y=0;score=0;delay=1000;level=1;map = new int[100][100];//这里将框架向为扩充一行和一列,这样对后面判断是否越界很方便for(int i=0;i<12;i++){map[i][22]=1;}for(int i=0;i<22;i++){map[12][i]=1;}}private void nextBlk() {this.x=4;this.y=0;this.nextBlock=getNextBlock();setNext();if(crash(x, y, blockType, turnState)==0){//如果一出来就撞了,游戏结束JOptionPane.showMessageDialog(null, "Game Over!!!");timer.stop();}}//设置下一块信息public void setNext(){this.blockType=this.nextBlock.getBlockType();this.turnState=this.nextBlock.getTurnState();}//画图protected void paintComponent(Graphics g) {super.paintComponent(g);
//				g.fill3DRect(220, 420, 20, 20, true);//画俄罗斯方块已经“堆积的方块”g.setColor(ModelColor);for(int i=0;i<12;i++){for(int j=0;j<22;j++){if(map[i][j]==1){g.fill3DRect(i*20, j*20, 20, 20, true);}}}//画移动的块g.setColor(BlockColor);for(int j=0;j<16;j++){if(shapes[blockType][turnState][j]==1){g.fill3DRect((j%4+x)*20, (j/4+y)*20, 20, 20,true);}}}//向下运行,如果碰撞,则结束这个块的运行,并生成下一个块,否则继续向下走private void down(){System.out.println(x+"  "+y);if(crash(x,y+1,blockType,turnState)==0){add(x,y,blockType,turnState);setNextBlock();nextBlk();}else{y++;}repaint();}//向左移动public void left() {if(x>=0){x -= crash(x-1,y,blockType,turnState);repaint();}}//向右移动public void right() {if(x<12){x += crash(x+1,y,blockType,turnState);repaint();}}//旋转,为了保证在左右靠墙是都能转动,所以要对下一状态进行预判,要是下一块不安全,则将4*4的块模型整体向后退一不,然后再//旋转,但是要注意,要是横条是 要退3步public void turn() {if(	crash(x,y,blockType,(turnState+1)%4)==0	){if(blockType==0&&crash(x-3,y,blockType,(turnState+1)%4)==1){x-=3;turnState =(turnState+1)%4;}else if(crash(x-1,y,blockType,(turnState+1)%4)==1){x-=1;turnState =(turnState+1)%4;}}else{turnState =(turnState+1)%4;}repaint();}//判断是否碰撞,要是返回0,否则返回1,这里返回1和0是有讲究的,是为了左右运行时,可以直接加上这个返回值就行了,碰撞加0//没有,加1.private int crash(int x, int y, int blockType, int turnState) {for(int a=0;a<4;a++){for(int b=0;b<4;b++){if(x==-1){//这里是判断左移是是否碰壁return 0;}if((shapes[blockType][turnState][a*4+b] & map[x+b][y+a]) ==1){//这里通过位运算可以很快速度得到结果,必须同时为1才算碰撞,即,//是块和块碰撞return 0;}}}return 1;}//向已堆积块添加块private void add(int x, int y, int blockType, int turnState) {for(int a=0;a<4;a++){for(int b=0;b<4;b++){if(shapes[blockType][turnState][a*4+b]==1){map[x+b][y+a]=1;}}}tryDelLine();//分数和等级}//控制分数和等级,同时消的越多,分数加的越多,等差数列,等级的升高,伴随着速度的加快public void tryDelLine() {int count=1;for(int b=0;b<22;b++){int c=1;for(int a=0;a<13;a++){c&=map[a][b];}if(c==1){if(count==1){score +=10;}else{score +=10*count;}count++;setScore(score);for(int d=b;d>0;d--){for(int e=0;e<12;e++){map[e][d]=map[e][d-1];}}//※更改游戏难度(加快下落速度)if(score>100*numb){level++;setGrade(level);delay -= delay;if(delay==100){delay=100;}timer.setDelay(delay);}}}}//这个内部类是实现事件的监听,也是方便类与类之间的联系class TimeListener extends KeyAdapter implements ActionListener{public void actionPerformed(ActionEvent e) {if(!Tetris.isPlay){return ;}down();}public void keyPressed(KeyEvent e) {if(!Tetris.isPlay){return ;}switch(e.getKeyCode()){case KeyEvent.VK_DOWN:down();break;case KeyEvent.VK_LEFT:left();break;case KeyEvent.VK_RIGHT:right();break;case KeyEvent.VK_UP:turn(); break;}}}}public static void main(String[] args) {Tetris te = new Tetris();te.setVisible(true);}}








这篇关于俄罗斯方块(详解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1045288

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

LabVIEW FIFO详解

在LabVIEW的FPGA开发中,FIFO(先入先出队列)是常用的数据传输机制。通过配置FIFO的属性,工程师可以在FPGA和主机之间,或不同FPGA VIs之间进行高效的数据传输。根据具体需求,FIFO有多种类型与实现方式,包括目标范围内FIFO(Target-Scoped)、DMA FIFO以及点对点流(Peer-to-Peer)。 FIFO类型 **目标范围FIFO(Target-Sc

019、JOptionPane类的常用静态方法详解

目录 JOptionPane类的常用静态方法详解 1. showInputDialog()方法 1.1基本用法 1.2带有默认值的输入框 1.3带有选项的输入对话框 1.4自定义图标的输入对话框 2. showConfirmDialog()方法 2.1基本用法 2.2自定义按钮和图标 2.3带有自定义组件的确认对话框 3. showMessageDialog()方法 3.1

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(Buffer Pool)中进行。例如,执行一条 UPDATE 语句修改了某一行数据,对应的缓

OmniGlue论文详解(特征匹配)

OmniGlue论文详解(特征匹配) 摘要1. 引言2. 相关工作2.1. 广义局部特征匹配2.2. 稀疏可学习匹配2.3. 半稠密可学习匹配2.4. 与其他图像表示匹配 3. OmniGlue3.1. 模型概述3.2. OmniGlue 细节3.2.1. 特征提取3.2.2. 利用DINOv2构建图形。3.2.3. 信息传播与新的指导3.2.4. 匹配层和损失函数3.2.5. 与Super

web群集--nginx配置文件location匹配符的优先级顺序详解及验证

文章目录 前言优先级顺序优先级顺序(详解)1. 精确匹配(Exact Match)2. 正则表达式匹配(Regex Match)3. 前缀匹配(Prefix Match) 匹配规则的综合应用验证优先级 前言 location的作用 在 NGINX 中,location 指令用于定义如何处理特定的请求 URI。由于网站往往需要不同的处理方式来适应各种请求,NGINX 提供了多种匹