• 猿创征文|JAVA 实现《俄罗斯方块升级版》游戏


    前言

    俄罗斯方块是一款风靡全球,从一开始到现在都一直经久不衰的电脑、手机、掌上游戏机产品,是一款游戏规则简单,但又不缺乏乐趣的简单经典小游戏,上手容易,适用范围广泛,人所共知。俄罗斯方块游戏简单的基本规则是有小方块组成的7种不同的规则图形陆续从屏幕上落下,玩家操作移动使其下落拼出一条完整的横条,随即会消失,玩家得分,游戏等级提高,当没有被消除的图形堆积到屏幕顶端时,游戏结束。

    俄罗斯方块游戏最初是由俄罗斯人阿列克谢·帕基特诺夫在1984年开发的休闲小游戏,曾几何时它创造了无可匹敌的商业价值,影响了一代休闲小游戏的开发与产业链。随着信息时代科技时代的不断发展和变化,计算机已经普及到每一个人的生活中,在繁忙的工作生活中,这一类休闲小游戏给人们带来了些许的放松。

    《俄罗斯方块升级版》游戏用java语言实现,采用了swing技术进行了界面化处理,设计思路用了面向对象思想。

    主要需求

    整个游戏系统会随机产生7种由四个小方块组成的不同形状的方块,经过旋转后得到28种状态,如果增加游戏难度,会增加六种不同形状的方块形状,同样经过旋转后增加24种状态。方块按一定的速度自由下落,玩家通过键盘上的上下左右按键控制方块的左右移动和旋转,将方块落下后放在合适的位置。当方块落下后,如果方块落下后有一整行被方块填满,那么该一整行消去。当一行被消去时,玩家得分增加10分,当得分达到100分后,玩家等级增加一级,速度加快一级,难度加大。如果当方块落下后整个游戏画布界面被占满,则方块不再下落,游戏宣告失败。游戏具体的功能需求有如下几个:

    • 游戏界面需求:游戏的良好的界面会让玩家眼前一亮,更加能充分的感受到游戏带来的娱乐性,放松性。本游戏的默认背景色是深绿色,游戏主界面画面自定义为自己的所喜欢的图片,并可以更改,主界面方块默认用橘黄色,预显方块颜色默认为淡紫色。背景色、前景色对比鲜明,以达到让玩家眼前一亮的感觉,并能在游戏达到高等级状态,方块下落速度渐高的情况下使玩家能够清楚的分辨出下落方块的形状,增加游戏的刺激性。
    • 游戏形状需求:用数组作为存储方块52种状态的数据结构,即初级等级长条形、Z字形、反Z形、田字形、7字形、反7形、T字型一共7种形状的向4个方向的旋转变形,和中级等级的三种方块12种不同的状态,高级等级的三种方块12种不同的状态。各个方块可以实现按逆时针的旋转方式旋转,并且方块能否旋转需要用条件加以判断,如果旋转后可能发生越界,则不能旋转,需要调整位置来保证他可以旋转。

    主要设计

    以下该游戏中类的设计:
    MyFrame类:继承自JFrame类,作为游戏的主类,负责对游戏的主体全局进行控制,连接与指挥各个类的枢纽。
    PreView类:继承自JPanel类,作为操作面板类,负责安放主游戏窗口,积分板,级别控制按钮等窗口用以控制游戏进程。
    GameCanvas类:继承自JPanel类,ChangeBlockColor线程类动态改变画布类的方格颜色,画布类通过检查方格颜色来体现ChangeBlockColor方块的移动情况与消去状况。
    Box类:方格类,组成方块的基本元素,主要表达方式为颜色。
    Block类:作为操控方块的类,控制方块的移动,下落以及变形。

    • 游戏主界面显示模块:
      游戏主界面采用Swing组件开发,并且向其注册监听器,以实现各种控制功能,综合游戏窗体的设计,其上至少需要注册三个监听器,分别是动作监听器(ActionListener)、键盘监听器(KeyListener)、选项监听器(ItemListener)。
      根据初步设计,可以确定客户端上所要用到的Swing组件对象有JFrame对象、JPanel对象,JLabel对象、JButton对象、JMenuBar对象、JMenu对象、JMenuItem对象、JTextField对象、JTextArea对象、JDialog对象等,至少十个Swing组件对象。

    • 背景画布模块设计:该游戏的主背景画布是一个20行、12列的二维数组,方块显示是由相应颜色变化来标识,主窗体用颜色填充后可形成呈现出来背景样式和方块。本游戏用继承自JPanel的GameCanvas类控制背景画布的显示,用rows代表画布的行数,cols代表画布的列数,行数和列数决定着画布拥有方格的数目。

    • 预览方块模块设计:方块和数据信息是游戏中最基本的功能模块。Box这个类方格类,是组成块的基本元素,用自己的颜色来表示块的外观 ,MyTask继承TimerTask类用来定时下落,用计数方式来实现速度的改变,MyListener类继承KeyAdapter类用来实现按键监听,控制方块的上下左右。定义一个4x4方阵,共16个小格。用“0”和“1”来表示每个方格是绘制新颜色还是保留底色。

    • 方块移动、旋转模块设计:方块的翻转与移动比较容易实现,方块移动只需要改变方块的横坐标或纵坐标,然后重新绘制方块即可。方块翻转也只需要改变背景数组的值,重新绘制方
      即可。
      本游戏方块下落时,进行动态绘制,实现Cloneable接口, 以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。方块的操作类BlockOperation继承Thread类,重写run()方法,以实现方块的动态正确下落。当然,在线程中要判定方块是处于moving状态还是pausing状态

    功能截图

    游戏开始主界面:
    在这里插入图片描述
    游戏菜单:
    在这里插入图片描述
    设计方块颜色:

    在这里插入图片描述

    代码实现

    MyFrame

    
    public class MyFrame extends JFrame{
    	JPanel jp_pan=new JPanel();
    	JPanel jp_pre=new JPanel();
    	JPanel jp_ctrl=new JPanel();
    	JPanel jp_scor=new JPanel();
    	Zidingyi zi;
    	JRadioButtonMenuItem jr1=new JRadioButtonMenuItem("初级",true);
    	JRadioButtonMenuItem jr2=new JRadioButtonMenuItem("中级");
    	JRadioButtonMenuItem jr3=new JRadioButtonMenuItem("高级");
    	JLabel jt9=new JLabel("得分:0" );
    	static JLabel jt10=new JLabel("等级:1" );
    	JMenu m1=new JMenu("游戏");
    	JMenu m2=new JMenu("帮助");
    	JCheckBox jc1;
    	JSlider jsl;
    //	Dialog dia;//创建对话框
    	static ImageIcon  background = new ImageIcon(Constant.backGround1);
    	// 把背景图片加到label
    	static JLabel label = new JLabel(background);
    //	Dialog dia=new Dialog(this, "自定义", false);
    	int scor=0;//初始化分数为0
    	static int rank=0;//初始化等级为0
    	int highC=0;
    	boolean upspeed=false;
    	boolean isTime=true;
    	boolean runstop;
    	static boolean isRank=false;
    	static boolean changeBack=false;
    	public static boolean playing=false;
    	static boolean isMusic=true;
    	static boolean high=false;
    	PreView pv=new PreView();
    	JMenuItem ji1=new JMenuItem("开局");
    	GameCanvas gc=new GameCanvas(20, 12);//画出20行12列
    	private Block block=new Block();//当前块
    	private int newspeed=1000;//默认当前等级为1
    	MusicPlayer mp=new MusicPlayer();
    	Timer time=new Timer();
    	MyTask mytask;
    	int temp=1;
    //	游戏主构造函数
    	public MyFrame(String str){
    		super(str);
    		this.setSize(450, 570);
    		Dimension scrSize = 
    	               Toolkit.getDefaultToolkit().getScreenSize();//获取屏幕尺寸
    		setLocation((scrSize.width - getSize().width) / 2,
    		        (scrSize.height - getSize().height) / 2);//设置屏幕居中
    		this.setLayout(null);
    		//label的大小为jframe的大小
    		label.setBounds(0, 0, this.getWidth(), this.getHeight());
    		//把label加到jframe的最底层,比jframe上的那个panel还下面
    		this.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));
    		//label比jframe上的那个panel还下面,那需要把那个panel设为透明的,不然就盖住背景了
    		JPanel imagePanel = (JPanel) this.getContentPane();
    		imagePanel.setOpaque(false);
    		addMenu();
    		//游戏开始按钮
    		ji1.addActionListener(new ActionListener() {
    
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				// TODO Auto-generated method stub
    				// 如果游戏已经开始,再按一次即显示游戏结束
    					
    			
    				if (playing == true) {
    					ji1.setText("开局");
    					if(isMusic==true)
    					{mp.playStart();}
    					gc.setGameOver(true);
    					gc.repaint();
    					MyFrame.rank=11-Constant.step;
    					MyFrame.jt10.setText("等级:"+MyFrame.rank);
    					 runstop=true;
    					 block.isAlive=false;
    					 block=new Block();
    					 mytask.cancel();
    
    					playing = false;
    				} else {
    					reset();
    					if(isMusic==true)
    					{mp.playStart();}
    					MyFrame.rank=11-Constant.step;
    					MyFrame.jt10.setText("等级:"+MyFrame.rank);
    					ji1.setText("结束游戏");
    					playing = true;
    					mytask=new MyTask();
    					time.schedule(mytask, 0, 100);//100毫秒执行一次
    					Thread thread = new Thread(new play());// 调用开始游戏的方法
    					thread.start();
    
    				}
    			};
    		});
    		this.add(gc);//添加游戏画布
    		
    		addRight();//添加右边
    		this.setFocusable(true);//设置可获得焦点
    		this.requestFocus();//设置焦点
    		this.addKeyListener(new MyListener());
    		this.setVisible(true);
    		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	}
    public static void setBackGround(){
    	label.setIcon(background);
    }
    	/**
    	 * 定时下落,用计数方式来实现速度的改变
    	 * 
    	 */
    	private class MyTask extends TimerTask {
    
    		@Override
    		public void run() {
    			temp++;
    			if (temp % Constant.step == 0) {
    				block.newL = block.x;
    				block.newH = block.y + 1;
    //				block.yy();
    				if (block.pausing == true)
    					return;
    				if (high == true) {
    					block.earse();
    					highC++;
    					if (highC == 4) {
    						gc.addRow();
    						highC = 0;
    					}
    				}
    				if (block.isMoveAble(block.newH, block.newL)) {
    					block.earse();
    					block.y++;
    					block.display();
    					gc.repaint();
    
    				} else {
    					block.isAlive = false;
    					gc.repaint();
    					// cancel();
    				} // 取消定时器任务
    				temp = 1;
    			}
    		
    		}
    	}
    
    	private class play implements Runnable {
    		public void run() {
    /*			if(killThread==true)
    				return;*/
    			int col = (int) (Math.random() * (gc.getCols() - 3));//随即位置生成列
    			int style = Constant.STYLES[(int) (Math.random() * Block.get_addl())][(int) (Math
    					.random() * 4)];
    			while (playing) {
    				if (block != null) {
    					//判断当前方块是否死亡
    					if (block.isAlive) {
    						try {
    							Thread.currentThread().sleep(100);
    						} catch (InterruptedException ie) {
    							ie.printStackTrace();
    						}
    						continue;
    					}
    				}
    				isFullLine();
    //				if(upspeed)//判断是否加速,是的话则进行调用
    //				upLevel();
    				if(isGameOver()){
    					if(isMusic==true)
    					{mp.playGameOver();}
    					gc.setGameOver(true);
    					gc.repaint();
    					ji1.setText("开局");
    					mytask.cancel();
    					playing=false;
    					return;
    					
    				}
    				block = new Block(style, -1, col, gc);
    				block.jixu();//防止在暂停时候重新开始游戏,暂停字还不消失
    				gc.repaint();// 将创建出来的方块显示出来
    				block.isAlive = true;
    				col = (int) (Math.random() * (gc.getCols() - 3));//随即位置生成列
    				style = Constant.STYLES[(int) (Math.random() * Block.get_addl())][(int) (Math
    						.random() * 4)];
    				pv.setStyle(style);
    			}
    		}
    		/**
    		 * 增加速度
    		 */
    		private void upLevel() {
    			if(Constant.step-1<1){
    				return;}
    			Constant.step=Constant.step-1;	//速度增加一级
    				rank++;					
    				jt10.setText("等级:"+rank);
    				
    				upspeed=false;//将标志位至为false		
    			
    		}
    
    		/**
    		 * 判断是否满行,满行则调用消行方法。
    		 */
    		private void isFullLine() {
    			// TODO Auto-generated method stub
    
    			for (int i = 0; i < 20; i++) {
    				int row = 0;
    				boolean flag = true;
    				for (int j = 0; j < 12; j++) {
    					if (!gc.getBox(i, j).isColorBox()) {
    						flag = false;
    						break;
    					}
    				}
    
    				if (flag == true) {
    					row = i;
    					gc.delete(row);//删除行
    					if(isMusic==true)
    					{mp.playEraseSound();}
    					addScor();//增加分数
    					if(scor%10==0)//设置为10分增加一个等级
    					upspeed=true;//将速度增加标志位至为true
    					if(upspeed==true)
    						upLevel();
    				}
    			}
    
    		}
    
    		/**
    		 * 得分的计算方法
    		 */
    		private void addScor() {
    			scor=scor+10;
    			jt9.setText("得分:"+scor);
    		}
    	
    	}
    	/**
    	 * 判断最顶层是否有被占用,游戏是否结束
    	 */
    	private boolean isGameOver() {
    		for (int i = 0; i < 12; i++) {
    			Box box = gc.getBox(0, i);
    			if (box.isColorBox())
    				return true;
    			
    		}return false;
    	}
    
    	private void reset() {
    		scor=0;
    		rank=0;
    		jt10.setText("等级:"+rank);
    		jt9.setText("得分:"+scor);
    		upspeed=false;
    		playing=true;
    		runstop=false;
    //		block.pausing=false;
    //		isTime=true;
    //		block=new Block();
    //		block.isAlive=false;
    		gc.setGameOver(false);
    		gc.repaint();
    		gc.reset();
    	}
    /*	private class MenuKeyListener extends KeyAdapter{
    		public void keyPressed(KeyEvent e) {
    			int i = e.getKeyCode();
    			switch (i) {
    			case KeyEvent.VK_C:
    				System.out.println("111");;
    				break;
    			case KeyEvent.VK_DOWN:
    				block.moveDown();
    				break;
    			case KeyEvent.VK_LEFT:
    				block.moveLeft();
    				break;
    		}
    	}
    		}*/
    	/**
    	 * 
    	 *按键监听,上下左右。
    	 */
    	private class MyListener extends KeyAdapter{
    
    
    		@Override
    		public void keyPressed(KeyEvent e) {
    			// TODO Auto-generated method stub
    			int i = e.getKeyCode();
    			switch (i) {
    			case KeyEvent.VK_UP:
    				block.moveUp();
    				break;
    			case KeyEvent.VK_DOWN:
    				block.moveDown();
    				break;
    			case KeyEvent.VK_LEFT:
    				block.moveLeft();
    				break;
    			case KeyEvent.VK_RIGHT:
    				block.moveRight();
    				break;
    			case KeyEvent.VK_SPACE:
    				block.quickDown();
    				break;
    			case KeyEvent.VK_P:
    				block.pause();
    				break;
    			case KeyEvent.VK_C:
    				block.jixu();
    				break;
    
    			}
    		}
    		
    	}
    
    	
    		
    		/**
    		 * 菜单添加方法
    		 */
    		private void addMenu() {
    		// TODO Auto-generated method stub
    		JMenuBar jb1=new JMenuBar();
    //		m1.addKeyListener(new MenuKeyListener());
    		//监听Dialog对话框,如果有等级改变则改变选择
    		m1.addChangeListener(new ChangeListener() {
    			
    			@Override
    			public void stateChanged(ChangeEvent e) {
    				// TODO Auto-generated method stub
    				int i=Block.get_addl();
    				if(i==7)
    					jr1.setSelected(true);
    				else if(i==10)
    					jr2.setSelected(true);
    				else
    					jr3.setSelected(true);
    			}
    			
    		});
    		
    			
    //		JMenuItem ji1=new JMenuItem("开局(O)");
    		
    		jr1.addActionListener(new MenuActionListener());
    		
    		jr2.addActionListener(new MenuActionListener());
    		
    		jr3.addActionListener(new MenuActionListener());
    		ButtonGroup bg=new ButtonGroup();
    		bg.add(jr1);
    		bg.add(jr2);
    		bg.add(jr3);
    		
    		  JMenuItem ji2=new JMenuItem("自定义");
    		  
    		ji2.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				// TODO Auto-generated method stub
    				zi=new Zidingyi(MyFrame.this,"自定义",false,block,gc);
    				zi.setVisible(true);
    				if(playing==true)
    				block.pause();
    			}
    		});
    		JMenuItem ji3=new JMenuItem("退出");
    		ji3.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				// TODO Auto-generated method stub
    				System.exit(1);//退出程序
    			}
    		});
    		JMenuItem ji4=new JMenuItem("关于");
    		ji4.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				// TODO Auto-generated method stub
    				JDialog dl=new Version(MyFrame.this,"版本信息",false);
    
    			}
    		});
    		//调用颜色对话框设置方块颜色
    		JMenuItem ji_color=new JMenuItem("方块颜色");
    		ji_color.addActionListener(new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				// TODO Auto-generated method stub
    				Color newFrontColor = JColorChooser.showDialog(
    					    MyFrame.this,"设置方块颜色",
    	                 gc.getBlockColor());
    					if (newFrontColor != null)
    						gc.setBlockColor(newFrontColor);
    				}
    			}
    		);
    		MyFrame.this.setJMenuBar(jb1);
    		jb1.add(m1);
    		jb1.add(m2);
    		m1.add(ji1);
    		m1.add(jr1);
    		m1.add(jr2);
    		m1.add(jr3);
    		m1.add(ji2);
    		m1.add(ji_color);
    		m1.add(ji3);
    		
    		m2.add(ji4);	
    	}
    	/**
    	 * 右界面的添加
    	 */
    	private void addRight() {
    		// TODO Auto-generated method stub
    //		JTextField jt1=new JTextField("下一块");
    		JLabel jt1=new JLabel("下一块");
    		jt1.setFont(new Font("华文行楷", Font.BOLD, 18));
    		jt1.setOpaque(false);
    //		jt1.setEditable(false);
    		jp_pre.setLayout(null);
    		jt1.setBounds(5, 0, 80, 20);
    		jp_pre.add(jt1);
    		pv.setBounds(10, 20, 102, 102);
    		jp_pre.add(pv);//添加预览窗口
    		jp_pre.setBounds(308, 5, 120, 125);//设置坐标
    		jp_pre.setOpaque(false);//设置背景为透明
    		MyFrame.this.add(jp_pre);
    //		JTextField jt2=new JTextField("功能键盘" );
    		JLabel jt2=new JLabel("功能键盘");
    		jt2.setFont(new Font("华文行楷", Font.BOLD, 23));
    //		jt2.setEditable(false);
    		jt2.setOpaque(false);
    //		JTextField jt3=new JTextField("快速向下:↓" );
    		JLabel jt3=new JLabel("快速向下:↓");
    		jt3.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt3.setEditable(false);
    		jt3.setOpaque(false);
    //		JTextField jt4=new JTextField("旋转:↑" );
    		JLabel jt4=new JLabel("旋转:↑");
    		jt4.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt4.setEditable(false);
    		jt4.setOpaque(false);
    //		JTextField jt5=new JTextField("向左:←" );
    		JLabel jt5=new JLabel("向左:←");
    		jt5.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt5.setEditable(false);
    		jt5.setOpaque(false);
    //		JTextField jt6=new JTextField("向右:→" );
    		JLabel jt6=new JLabel("向右:→");
    		jt6.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt6.setEditable(false);
    		jt6.setOpaque(false);
    		JLabel jt11=new JLabel("一键下落:空格");
    		jt11.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt6.setEditable(false);
    		jt6.setOpaque(false);
    //		JTextField jt7=new JTextField("暂停:P" );
    		JLabel jt7=new JLabel("暂停:P");
    		jt7.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt7.setEditable(false);
    		jt7.setOpaque(false);
    //		JTextField jt8=new JTextField("继续:C" );
    		JLabel jt8=new JLabel("继续:C");
    		jt8.setFont(new Font("华文行楷", Font.BOLD, 15));
    //		jt8.setEditable(false);
    		jt8.setOpaque(false);
    		jp_ctrl.setLayout(new GridLayout(8, 1, 0, 0));
    //		jp_ctrl.setBorder(BorderFactory.createBevelBorder(EtchedBorder.LOWERED));
    		jp_ctrl.add(jt2);
    		jp_ctrl.add(jt3);
    		jp_ctrl.add(jt4);
    		jp_ctrl.add(jt5);
    		jp_ctrl.add(jt6);
    		jp_ctrl.add(jt11);
    		jp_ctrl.add(jt7);
    		jp_ctrl.add(jt8);
    		jp_ctrl.setOpaque(false);
    		jp_ctrl.setBounds(310, 145, 120, 200);
    		MyFrame.this.add(jp_ctrl);
    //		jt9.setEditable(false);
    		jt9.setOpaque(false);
    		jt9.setForeground(Color.BLACK);
    //		jt10.setEditable(false);
    		jt10.setOpaque(false);
    		jt10.setForeground(Color.BLACK);
    		jp_scor.setLayout(new GridLayout(2, 1, 0, 20));
    		jp_scor.add(jt9);
    		jt9.setFont(new Font("华文行楷", Font.BOLD, 26));
    		jt10.setFont(new Font("华文行楷", Font.BOLD, 26));
    		jp_scor.add(jt10);
    		jt9.setBackground(Color.LIGHT_GRAY);
    		jt10.setBackground(Color.LIGHT_GRAY);
    		jp_scor.setOpaque(false);
    		jp_scor.setBounds(320, 360, 100, 140);
    		MyFrame.this.add(jp_scor);
    	}
    	
    	/**
    	 * 菜单等级的监听
    	 *
    	 */
    	private class MenuActionListener implements ActionListener {
    
    		@Override
    		public void actionPerformed(ActionEvent e) {
    			//获取JMenuItem对象
    			JMenuItem j=((JMenuItem)e.getSource());
    			if(j==jr1){
    //				newLevel=Constant.LEVEL_1;
    				Block.set_addl(7);
    			}
    			if(j==jr2){
    				Block.set_addl(10);
    			}
    			if(j==jr3){
    //				high=true;
    				Block.set_addl(13);
    			}
    				
    		}
    		
    	}
    	public static void main(String[] args) {
    		new MyFrame("俄罗斯方块");
    	}
    	
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548

    GameCanvas

    public class GameCanvas extends JPanel {
    	private Color backColor = Color.GRAY, frontColor = Color.orange;
    	private int rows, cols, score = 0, scoreForLevelUpdate = 0;
    	private Box[][] boxes;
    	private int boxWidth=25, boxHeight=25;
    	private boolean gameOver=false;
    	public boolean pau=false;
    
    	/**
    	 * 画布类的构造函数
    	 * @param rows int, 画布的行数
    	 * @param cols int, 画布的列数
    	 * 行数和列数决定着画布拥有方格的数目
    	 */
    	public GameCanvas(int rows, int cols) {
    		this.rows = rows;
    		this.cols = cols;
    		this.setOpaque(false);
    		boxes = new Box[rows][cols];
    		for (int i = 0; i < boxes.length; i++) {
    			for (int j = 0; j < boxes[i].length; j++) {
    				boxes[i][j] = new Box(false);
    			}
    		}
    		setBounds(0, 0, 300, 500);//设置相对位置坐标
    		setBorder(new EtchedBorder(
    		        EtchedBorder.RAISED, Color.white, new Color(148, 145, 140)));
    	}
    
    	/**
    	 * 画布类的构造函数
    	 * @param rows 与public GameCanvas(int rows, int cols)同
    	 * @param cols 与public GameCanvas(int rows, int cols)同
    	 * @param backColor Color, 背景色
    	 * @param frontColor Color, 前景色
    	 */
    	public GameCanvas(int rows, int cols,
    	                  Color backColor, Color frontColor) {
    		this(rows, cols);
    		this.backColor = backColor;
    		this.frontColor = frontColor;
    	}
    
    	/**
    	 * 设置游戏背景色彩
     	 * @param backColor Color, 背景色彩
    	 */
    	public void setBackgroundColor(Color backColor) {
    		this.backColor = backColor;
    	}
    
    	/**
    	 * 取得游戏背景色彩
     	 * @return Color, 背景色彩
    	 */
    	public Color getBackgroundColor() {
    		return backColor;
    	}
    
    	/**
    	 * 设置游戏方块色彩
     	 * @param frontColor Color, 方块色彩
    	 */
    	public void setBlockColor(Color frontColor) {
    		this.frontColor = frontColor;
    	}
    
    	/**
    	 * 取得游戏方块色彩
     	 * @return Color, 方块色彩
    	 */
    	public Color getBlockColor() {
    		return frontColor;
    	}
    
    	/**
    	 * 取得画布中方格的行数
    	 * @return int, 方格的行数
    	 */
    	public int getRows() {
    		return rows;
    	}
    
    	/**
    	 * 取得画布中方格的列数
    	 * @return int, 方格的列数
    	 */
    	public int getCols() {
    		return cols;
    	}
    
    	/**
    	 * 取得游戏成绩
    	 * @return int, 分数
    	 */
    	public int getScore() {
    		return score;
    	}
    
    	/**
    	 * 取得自上一次升级后的积分
    	 * @return int, 上一次升级后的积分
    	 */
    	public int getScoreForLevelUpdate() {
    		return scoreForLevelUpdate;
    	}
    
    
    	/**
    	 * 得到某一行某一列的方格引用。
    	 * @param row int, 要引用的方格所在的行
    	 * @param col int, 要引用的方格所在的列
    	 * @return ErsBox, 在row行col列的方格的引用
    	 */
    	public Box getBox(int row, int col) {
    		if (row < 0 || row > boxes.length - 1
    		        || col < 0 || col > boxes[0].length - 1)
    			return null;
    		return boxes[row][col];
    	}
    	/**
    	 * 消行
    	 */
    	public void delete(int row) {
    		//创建新Box存储新状态,不能直接赋值,赋值只是指向同一个对象
    		for (int i = row; i > 0; i--) {
    			for (int j = 0; j < 12; j++)
    				boxes[i][j] = new Box(boxes[i - 1][j].isColorBox());
    		}
    		repaint();
    	}
    
    	/**
    	 * 自动上涨
    	 */
    	public void addRow() {
    		for (int i = 0; i <19 ; i++) {
    			for (int j = 0; j < 12; j++) {
    				boxes[i][j] = new Box(boxes[i + 1][j].isColorBox());
    			}
    		}
    		for (int i = 0; i < 12; i++) {
    			int a = (int) (Math.random() * 2);
    			if (a == 1)
    				boxes[19][i] = new Box(true);
    			else
    				boxes[19][i] = new Box(false);
    		}
    		repaint();
    	}
    	/**
    	 * 画组件。
    	 * @param g 图形设备环境
    	 */
    	public void paint(Graphics g) {
    		super.paint(g);
    		if (gameOver) {
    	
    			paintGame(g);
    			g.setColor(Color.RED);
    			g.setFont(new Font("黑体", Font.BOLD, 80));
    			// g.drawString("GAME\nOVER",10, 220);
    			g.drawString("GAME", 50, 220);
    			g.drawString("OVER", 50, 310);
    		} else if(pau==true){
    		
    			paintGame(g);
    			g.setColor(Color.BLUE);
    			g.setFont(new Font("华文行楷", Font.BOLD, 40));
    			// g.drawString("GAME\nOVER",10, 220);
    			g.drawString("暂停", 100, 200);
    			g.drawString("按C继续!", 60, 310);
    
    		}else
    			paintGame(g);
    	}
    
    	public void paintGame(Graphics g) {
    		g.setColor(Color.BLUE);
    		g.draw3DRect(0, 0, 298, 498, true);
    		g.setColor(frontColor);
    //		int a;
    //		int key=0x8000;
    //		int y1=0;
    		for (int i = 0; i < boxes.length; i++) {
    			for (int j = 0; j < boxes[i].length; j++) {
    			
    				
    				if (boxes[i][j].isColorBox() == true) {
    					
    					g.setColor(frontColor);// 获取方格颜色
    					g.fill3DRect(j * boxWidth, i * boxHeight, boxWidth,
    							boxHeight, true);// j,i是相反过来的}
    			}
    		}}
    		
    	}
    	/**
    	 * 设置游戏结束
    	 */
    	public boolean setGameOver(boolean go){
    		gameOver=go;
    		return gameOver;
    	}
    
    	/**
    	 * 重置画布
    	 */
    	public void reset() {
    		for (int i = 0; i < boxes.length; i++) {
    			for (int j = 0; j < boxes[i].length; j++)
    				boxes[i][j].setColor(false);
    		}
    
    		repaint();
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219

    总结

    通过此次的《俄罗斯方块升级版》游戏实现,让我对swing的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。

    java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。

    源码获取

    源码下载地址:传送门------->

    可关注博主后,私聊博主免费获取
    需要技术指导,写项目程序,等更多服务请联系博主

    今天是持续写作的第 31 / 100 天。
    可以关注我,点赞我、评论我、收藏我啦。

  • 相关阅读:
    基于邻接矩阵的克鲁斯卡尔算法和普利姆算法
    单例模式之懒汉式和饿汉式
    Spring Initailizr (spring boot 项目初始化向导)
    查找算法【哈希表】 - 处理冲突的方法:开放地址法-二次探测法 & 随机探测法 & 再散列法
    (转)富文本编辑器——Vue2Editor
    Linux系统连接华为oceanstor数据存储
    C++ 之字符串、字符数组与字符指针(*、**)
    git代码管理 分支相关 新建dev、hot分支,分支协同操作
    (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
    深度学习踩坑笔记:载入内存,数据分配与重启问题,安装R
  • 原文地址:https://blog.csdn.net/qq_40869977/article/details/126713639