zoukankan      html  css  js  c++  java
  • 团队项目结题

    团队项目结题

    小组项目名称:

    俄罗斯方块代码实现

    项目简介:

    我们小组学习的是俄罗斯方块代码的简单实现,在原有代码的基础上,对代码进行理解和测试。我们的代码主要分两部分模块:一部分是图形界面的,一部分是操作界面的代码,对于操作界面的代码,由荆玉茗和史婧瑶同学负责,另一部分图形化的代码由韩昊辰和祁玮同学负责。

    设计思路

    1.界面设计 首先进行游戏区域的设计,主要的游戏功能都在游戏区域显示,比如方块的随机选择,画布的背景显示等等。 其次是系统功能显示区域,这里显示了当前所玩游戏的等级,右方可以选择不同的游戏级别,一共有1、2、3、4、5五种游戏级别的选择;下方是游戏画布背景的选择,一共有浅绿、浅黄、黑色三种背景颜色的选择;最下方有开始游戏、暂停游戏、结束游戏和退出游戏四中功能选项。
    2.游戏功能设计 在无人操作时,游戏开始后会随机产生一个下坠物,先显示在界面右上角的显示区域,然后转到游戏区域,右上角又随机产生一个新的下坠物,当该下坠物下落到底后,新的下坠物再次进入游戏区域,如此循环,直到游戏结束/暂停,这就是游戏的正常工作。 上述过程是在无人操作时游戏自动运行的,当用户进行一定的操作交互的时候,运行程序可以根据用户的操作指示进行当前下坠物的控制。而这些操作都是响应相关的功能键而执行的,所以这里可以把它看成一种“中断”的操作。 在中断过程中,可以通过键盘包括按某些键进行操作。为了便于用户操作,用户可以自主选择操作键,但他们的作用不变。但还是应该设置默认键来方便操作。例如:光标向上键,光标向下键,光标向左键,光标向右键。
    (1)按光标向上键 此事件产生下坠物旋转操作,下坠物并非任何情况都能旋转,如果旋转后与小方格矩阵显示的下坠物有冲突或超出边界时,均不能发生旋转。因此首先要判断是否有足够的空间进行旋转,然后选择是否旋转。
    (2)按光标向下键 此事件产生下坠物加速下落操作,如果下坠物已经到达游戏区域底部或者已经有其他方块遮挡,则下坠物停止下降。
    (3)按光标向左键此事件产生下落下坠物左移操作。首先要判断此下坠物是否能够发生左移,当越界或被其他显示下坠物阻挡时,则不能左移。
    (4)按光标向右键 此事件产生下落下坠物右移操作。首先要判断此下坠物是否能够发生右移,当越界或被其他显示下坠物阻挡时,则不能右移。

    代码注释(图形界面部分)

    package fangkuai;
    
    /**
     * Created by Administrator on 2016/6/5 0005.
     */
    
    
    public class RussionBlockGame
    {
        private int aa=0;
        private int ic=0;
        private final int sp_width=10;                               //游戏界面宽格
        private final int sp_height=20;                              //游戏界面高格
        private final int types[][][]={                              //游戏方块每种ID的方块的形状数据存储好(都是一些固定的数据)
                {{-1,0},{0,0},{1,0},{2,0}},                          //长条
                {{0,-1},{0,0},{0,1},{0,2}},
                {{-1,0},{0,0},{1,0},{1,1}},                          //直角(右)
                {{0,1},{0,0},{0,-1},{1,-1}},
                {{1,0},{0,0},{-1,0},{-1,-1}},
                {{0,-1},{0,0},{0,1},{-1,1}},
                {{-1,0},{0,0},{0,1},{1,0}},                          //直角(中)
                {{0,1},{0,0},{1,0},{0,-1}},
                {{1,0},{0,0},{0,-1},{-1,0}},
                {{0,-1},{0,0},{-1,0},{0,1}},
                {{-1,1},{-1,0},{0,0},{1,0}},                         //直接(左)
                {{1,1},{0,1},{0,0},{0,-1}},
                {{1,-1},{1,0},{0,0},{-1,0}},
                {{-1,-1},{0,-1},{0,0},{0,1}},
                {{0,-1},{0,0},{1,0},{1,1}},
                {{-1,0},{0,0},{0,-1},{1,-1}},
                {{0,1},{0,0},{1,0},{1,-1}},
                {{1,0},{0,0},{0,-1},{-1,-1}},
                {{0,0},{0,1},{1,0},{1,1}}                            //正方形
        };
    
        private int[][] block_box=new int[4][2];                     //四个方块坐标
        private int[][] block_box_tt=new int[4][2];
        private int block_x=0,block_y=0;                             //游戏方块在游戏界面中的坐标
        private int block_type=0;                                    //方块类别
        private int[][] game_space=new int[20][10];                  //空间数据
        private int movetype=0;
        private int scroe=0;
        private int speed=5;
    
        public RussionBlockGame()
        {
            clearspace();
            makenewblock();
        }
    
        public void clearspace()                                     //初始化空间数据
        {
            for(int i=0;i<sp_height;i++)
                for(int j=0;j<sp_width;j++)
                    game_space[i][j]=0;
        }
    
        public void makenewblock()                                   //随机出现方块
        {
            aa=(int)(Math.random()*100%7+1);
            ic=aa*10+1;
            switch(aa)
            {
                case 1:
                    block_type=0;                                 //生成长条
                    break;
                case 2:
                    block_type=2;                                 //生成直角右
                    break;
                case 3:
                    block_type=6;                                 //生成直角中
                    break;
                case 4:
                    block_type=10;                                //生成直角左
                    break;
                case 5:
                    block_type=14;
                    break;
                case 6:
                    block_type=16;
                    break;
                case 7:
                    block_type=18;                                //生成正方形
                    break;
            }
            block_x=1;
            block_y=sp_width/2;                 //产生一个方块时只需要提供其ID即可
            for(int i=0;i<4;i++)
            {
                block_box[i][0]=block_x-types[block_type][i][1];
                block_box[i][1]=block_y+types[block_type][i][0];
            }
        }
    
        public void movedown()         //方块下移
        {
            block_x++;                 //ID的x自加,y不变
            for(int i=0;i<4;i++)
            {
                block_box[i][0]=block_x-types[block_type][i][1];
            }
            movetype=1;
        }
    
        public void moveleft()        //方块左移
        {
            block_y--;                //ID的y自减,x不变
            for(int i=0;i<4;i++)
            {
                block_box[i][1]=block_y+types[block_type][i][0];
            }
            movetype=2;
        }
    
        public void moveright()       //方块右移
        {
            block_y++;                //ID的y自加,x不变
            for(int i=0;i<4;i++)
            {
                block_box[i][1]=block_y+types[block_type][i][0];
            }
            movetype=3;
        }
    
        public void turnright()                                    //方块的旋转
        {
            int[][] block_box_temp=new int[4][2];
            int ic_temp=ic;
            int block_type_temp=block_type;
            int id=ic%10;
            for(int i=0;i<4;i++)
            {
                block_box_temp[i][0]=block_box[i][0];
                block_box_temp[i][1]=block_box[i][1];
            }
            if(aa==7)                                               //如果是正方形,这旋转不变
                return;
            else if(aa==1||aa==5||aa==6)                          //这些方块旋转周期为2
            {
                if(id==2)                                           //id记录旋转次数,满二次就返回最开始形态,同时记录清零
                {
                    block_type--;
                    ic--;
                }
                else
                {
                    block_type++;
                    ic++;
                }
            }
            else                                                  //这些方块旋转次数周期为4
            {
                if(id==4)                                          //旋转周期已满,返回最开始形态,同时记录清零
                {
                    block_type=block_type-3;
                    ic=ic-3;
                }
    
                {
                    block_type++;
                    ic++;
                }
            }
            for(int i=0;i<4;i++)
            {
                block_box[i][0]=block_x-types[block_type][i][1];
                block_box[i][1]=block_y+types[block_type][i][0];
            }
            if(Iscanmoveto()==false)                       //不满足可旋转条件,则不改变值,记录并返回
            {
                ic=ic_temp;
                block_type=block_type_temp;
                for(int i=0;i<4;i++)
                {
                    block_box[i][0]=block_box_temp[i][0];
                    block_box[i][1]=block_box_temp[i][1];
                }
            }
        }
    
        public void moveback()
        {
            if(movetype==1)
            {
                block_x--;
                for(int i=0;i<4;i++)
                {
                    block_box[i][0]=block_x-types[block_type][i][1];
                }
            }
            else if(movetype==2)
            {
                block_y++;
                for(int m=0;m<4;m++)
                {
                    block_box[m][1]=block_y+types[block_type][m][0];
                }
            }
            else if(movetype==3)
            {
                block_y--;
                for(int n=0;n<4;n++)
                {
                    block_box[n][1]=block_y+types[block_type][n][0];
                }
            }
        }
    
        public boolean Iscanmoveto()
        {
            for(int i=0;i<4;i++)
            {
                if(block_box[i][0]<0||block_box[i][0]>19)      //超过游戏空间高度,不可移动
                {
                    moveback();
                    return false;
                }
                else if(block_box[i][1]<0||block_box[i][1]>9)          //超过游戏空间宽度,不可移动
                {
                    moveback();
                    return false;
                }
                else if(game_space[block_box[i][0]][block_box[i][1]]==1)            //碰到已知模块,不可再移动
                {
                    moveback();
                    return false;
                }
            }
            return true;
        }
    
        public boolean Ishitbottom()
        {
            for(int i=0;i<4;i++)//适用游戏高度如果没有变化
            {
                if(block_box[i][0]+1>19)     //方块中任意一个部分满足碰底条件
                {
                    for(int m=0;m<4;m++)
                    {
                        game_space[block_box[m][0]][block_box[m][1]]=1;//改变了游戏原有的空间大小了
                        block_box_tt[m][0]=block_box[m][0];//利用新数组存储碰底的模块
                        block_box_tt[m][1]=block_box[m][1];
                        block_box[m][0]=0;//原模块清零
                        block_box[m][1]=0;
                    }
                    return true;
                }
            }
            for(int i=0;i<4;i++)
            {
                if(game_space[block_box[i][0]+1][block_box[i][1]]==1)//适用游戏高度如果变化了
                {
                    for(int m=0;m<4;m++)
                    {
                        game_space[block_box[m][0]][block_box[m][1]]=1;
                        block_box_tt[m][0]=block_box[m][0];
                        block_box_tt[m][1]=block_box[m][1];
                        block_box[m][0]=0;
                        block_box[m][1]=0;
                    }
                    return true;
                }
            }
            return false;//都不满足,则游戏中的模块还未碰底
        }
    
        public void CheckAndCutLine()
        {
            int a[]={block_box_tt[0][0],block_box_tt[1][0],block_box_tt[2][0],block_box_tt[3][0]};
            int b[]={30,30,30,30};
            int temp=0;
            int temp1=0;
            int count=0;
            int ss=0;
            for(int i=0;i<4;i++)//一次性消去的最高高度
            {
                for(int j=0;j<10;j++)//判断底部是否都为1
                {
                    if(game_space[a[i]][j]==1)
                        temp++;//底部每有一个,记录1
                }
                if(temp==10)//倒数四行中某一行满足都为1的话
                {
                    for(int m=0;m<4;m++)
                        if(b[m]==a[i])
                        {
                            break;
                        }
                        else
                            ss++;
                    if(ss==4)
                    {
                        b[count]=a[i];
                        count++;
                    }
                }
                temp=0;
                ss=0;
            }
            for(int i=0;i<3;i++)
                for(int j=i+1;j<4;j++)
                {
                    if(b[i]>b[j])
                    {
                        temp1=b[i];
                        b[i]=b[j];
                        b[j]=temp1;
                    }
                }
            for(int n=0;n<4;n++)
            {
                if(b[n]==30)
                    break;
                else
                {
                    for(int aa=b[n]-1;aa>=0;aa--)
                    {
                        for(int bb=0;bb<10;bb++)
                        {
                            game_space[aa+1][bb]=game_space[aa][bb];//消行
                        }
                    }
                    for(int cc=0;cc<10;cc++)//保险起见,第一行全部清空
                        game_space[0][cc]=0;
                }
            }
        }
    
        public boolean IsGameOver()
        {
            boolean flag=false;
            for(int i=0;i<sp_width;i++)
            {
                if(game_space[0][i]==1)//bug存在的地方,条件不充分
                {
                    flag=true;
                    break;
                }
            }
            return flag;
        }
    
        public void sure()
        {
            for(int i=0;i<4;i++)
                game_space[block_box[i][0]][block_box[i][1]]=1;
        }
    
        public void notsure()
        {
            for(int i=0;i<4;i++)
                game_space[block_box[i][0]][block_box[i][1]]=0;
        }
    
        public boolean judge(int i,int j)
        {
            if(game_space[i][j]==1)
                return true;
            else
                return false;
        }
    }
    
    

    代码注释(操作部分)

    package afterclass;
    
    import java.awt.*;  //引入AWT包,因为要使用到颜色类
    import java.awt.event.*;
    import java.awt.geom.*;
    import javax.swing.*;
    
    public class Win 
    {
    	public static void main(String[] args) 
    	{
            GameWin frame=new GameWin();  //frame是带有标题和边框的顶层窗口
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //利用JFrame设置单机关闭按钮时执行关闭窗口
            frame.setVisible(true);  //JFrame创建的窗口默认是不可见的,设置为可见的方法,并将入口参数设为true
    	}
    	
    	public static boolean isplaying=true;
    }
    
    class GameWin extends JFrame
    {
    	public GameWin()
    	{
    		this.setFocusable(true);  //将控件设置成可获取焦点状态,设置成true,才能获得控件的点击事件
    		getContentPane().requestFocus();
    		this.setAlwaysOnTop(true);  //将窗口一直处于屏幕的最前端,永远挡住前的窗口
    		setTitle("super russionBlock");
    		setBounds(350,90,Default_X,Default_Y);  //获得边界,前两个参数是窗体左上角在容器中的坐标,后两个参数是窗体的宽度和高度
    		setResizable(false);  //当resizable为false时,表示生成的窗体大小是由程序员决定的,用户不可以自由改变该窗体的大小
    		add(jpy1);  
    		jpy1.setDividerLocation(304);  //设置分隔条的大小
    		jpy1.setDividerSize(4);   //给定一个整数,以像素为单位
    		addKeyListener(jpy2);  //为每个按钮添加消息监听
    		Thread t=new Thread(jpy2);
    		t.start();
    	}
    	
    	public static final int Default_X=500;
    	public static final int Default_Y=630;
        private left jpy2=new left();
        private right jpy3=new right();
    	private JSplitPane jpy1=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,jpy2,jpy3);
    }  //
    
    class right extends JPanel implements ActionListener  //JPanel是java图形化界面中最常用的容器
    {
    	public right()
    	{
    		initialframe();
    		initialListener();
    	}
    	
    	public void initialframe()  //初始化框架
    	{
    		setLayout(null);  // 设置窗体布局为空布局
    		add(jlArray[0]);
    		jlArray[0].setBounds(30,60,70,30);  //前两个参数是组件左上角在容器中的坐标,后两个参数是组件的宽度和高度
    		jlArray[0].setFocusable(false);  //将控件设置成可获取焦点状态,设置成true,才能获得控件的点击事件
    		add(jlArray[1]);
    		jlArray[1].setBounds(30,140,70,30);
    		jlArray[1].setFocusable(false);
    		add(jcArray[0]);
    		jcArray[0].setBounds(100,60,70,30);
    		jcArray[0].setFocusable(false);
    		add(jcArray[1]);
    		jcArray[1].setBounds(100,140,70,30);
    		jcArray[1].setFocusable(false);
    		add(jbArray[0]);
    		jbArray[0].setBounds(50,240,100,35);
    		jbArray[0].setFocusable(false);
    		add(jbArray[1]);
    		jbArray[1].setBounds(50,310,100,35);
    		jbArray[1].setFocusable(false);
    		add(jbArray[2]);
    		jbArray[2].setBounds(50,380,100,35);
    		jbArray[2].setFocusable(false);
    		add(jbArray[3]);
    		jbArray[3].setBounds(50,450,100,35);     
    		jbArray[3].setFocusable(false);
    	}
    
    	public void initialListener()  //初始化监听哨
    	{
    		for(int i=0;i<4;i++)
    		    jbArray[i].addActionListener(this);  //ActionListener是用于接收操作事件的监听器接口
    	}
    	
    	public void actionPerformed(ActionEvent e)  //ActionListener接口里的方法
    	{
    		if(e.getSource()==jbArray[0])  //获取事件中所作用的对象
    		{
    			Win.isplaying=true;
    		}
    		else if(e.getSource()==jbArray[1])
    		{
    			Win.isplaying=false;
    		}
    		else if(e.getSource()==jbArray[2])
    		{
    			Win.isplaying=false;
    		}
    		else if(e.getSource()==jbArray[3])
    		{
    			System.exit(0);
    		}
    	}
    	
    	private String[] level={"1"};
    	private String[] color={"浅黄"};
    	private JComboBox[] jcArray={new JComboBox(level),new JComboBox(color)};  //构造函数
    	private JLabel[] jlArray={new JLabel("游戏等级"),new JLabel("空间背景")};  
    	private JButton[] jbArray={new JButton("开始游戏"),new JButton("暂停游戏")  
    	                          ,new JButton("结束游戏"),new JButton("退出游戏")};
    }
    
    class left extends JComponent implements KeyListener,Runnable  //JComponent类是除容器顶层外所有Swing组件的基类
    {
    	public left()
    	{
    		game=new RussionBlockGame();
    	}
    	
    	public void paintComponent(Graphics g)  //绘制容器中的每个组件
    	{
    		Graphics2D g2=(Graphics2D)g; //抽象类,将paint()方法作为画笔
    		super.paintComponent(g);  //把整个面板用背景色重画一遍,起到清屏的作用
    		double width=300,height=600;
    		Rectangle2D rect=new Rectangle2D.Double(0,0,width,height);  //指定坐标空间的一个区域左上方(0,0)点 ,宽度、高度
    		g2.setColor(Color.black);  //设置颜色
    		g2.draw(rect);
    		g2.setColor(Color.yellow);  //背景为黄色填充
    		g2.fill(rect);
    		g2.setColor(Color.black);  //边框为黑色
    		g2.draw(rect);  //绘制一个矩形
    		for(int i=0;i<20;i++)
    			for(int j=0;j<10;j++)
    			{
    				if(game.judge(i,j)==true)
    				{
    					Rectangle2D rect3=new Rectangle2D.Double(j*boxSize,i*boxSize,boxSize,boxSize);
    					g2.setColor(Color.black);
    					g2.draw(rect3);
    					g2.setColor(Color.red);  //方块为红色
    					g2.fill(rect3);
    					g2.setColor(Color.black);
    					g2.draw(rect3);
    				}
    			}
    		game.notsure();
    	}
    	
    	public void keyTyped(KeyEvent e)  //keyTyped表示键盘按下,然后释放
    	{}
    	
    	public void keyPressed(KeyEvent e)   //keyPressed表示键盘按下,未释放
    	{
    		if(Win.isplaying==false)
    			return;
    		switch(e.getKeyCode())
    		{
    		case KeyEvent.VK_LEFT:                                       //LEFT
    			game.moveleft();
    			movejudge();
    			break;	
    		case KeyEvent.VK_UP:                                         //UP
    			game.turnright();
    			movejudge();
    			break;                                   
    		case KeyEvent.VK_RIGHT:                                      //RIGHT
    			game.moveright();
    			movejudge();
    			break;
    		case KeyEvent.VK_DOWN:                                       //DOWN
    			game.movedown();
    			movejudge();
    			break;
    		}
    	}
    
    	public void keyReleased(KeyEvent e)  //keyReleased表示键盘被释放
    	{}	
    	
    	public void movejudge()  //判断消行的方法
        {
        	if(game.Iscanmoveto()==true)
        	{
        		game.sure();
        		repaint();
        	}
        	else if(game.Ishitbottom()==true)
        	{
        		game.CheckAndCutLine();
        		game.makenewblock();
        		repaint();
        		if(game.IsGameOver()==true)
        			Win.isplaying=false;
        	}
        }
    
    	public void run()  //下落线程
    	{
    		try
    		{
    			while(Win.isplaying)
    			{
    		        Thread.sleep(500);  //通过设置睡眠时间控制下落速度
    	    	    game.movedown();
        		    movejudge();
    			}
    		}
    		catch(Exception e)
    		{
    			e.printStackTrace();
    		}
    	}
    	
    	private RussionBlockGame game;
    	public static final int boxSize=30;
    }
    
    

    程序结果运行

    程序暂停

    俄罗斯方块削行前

    俄罗斯方块削行后

    程序流程图

    小组具体分工

    • 韩昊辰:代码的调试以及前几周博客的编写,以及对图形化代码部分的注释
    • 祁 玮:代码的寻找以及前几周博客的编写,以及对图形化代码部分的注释
    • 荆玉茗:对于代码进行bug测试,以及对操作代码的注释
    • 史婧瑶:对于代码进行bug测试,以及对操作代码的注释

    最后分值分配

    • 韩昊辰:30分
    • 祁 玮:20分
    • 荆玉茗:25分
    • 史婧瑶:25分

    总结体会

    因为之前学的java内容还不是很熟练,所以我们对代码的注释差不多都是一行一行百度到的。通过本次学习我了解到,很多我们看似复杂的程序其实都是有据可循,比如一个小游戏,他是在图形界面里面完成的,将我们以前看见的代码行以图形的界面展示出来,并且很多东西在java的API中都有相应的内容,比如frame类是带有标题和边框的顶层窗口;利用JFrame设置单机关闭按钮时执行关闭窗口......很多很多我们所获取的每一个界面都有相应的程序与之对应,其实掌握并不难,API的东西就像固定的语法,只要知道它是怎么用,用来干什么的就可以。通过本次的学习让我真正的感受到了一个游戏的实现,其实并没有我们想象的那么难,只要找到问题,将问题细化,我们就能得到找到解决的方法。

  • 相关阅读:
    bfs输出路径 && 最短路(迪杰斯特拉)输出路径
    在Ubuntu虚拟机上搭建青岛OJ
    Delphi System.Fillchar 函数
    Delphi 类Class成员介绍 Private、protected、Public、Published
    通过带Flask的REST API在Python中部署PyTorch
    使用ONNX将模型转移至Caffe2和移动端
    AI框架类FAQ
    Paddle Release Note
    如何在框架外部自定义C++ OP
    如何写新的Python OP
  • 原文地址:https://www.cnblogs.com/dky201452/p/5597297.html
Copyright © 2011-2022 走看看