您当前的位置: 首页 >  c#

C#之四十八 俄罗斯方块设计

发布时间:2016-06-07 05:46:25 ,浏览量:0

1        系统设计要求

1.1   需求分析

本系统为一个用C#实现的为我们所熟悉的简单的俄罗斯方块游戏,该系统的具体功能如下:

1).       能简便的开始游戏,游戏中的方块的功能与日常我们所熟悉的游戏的功能一致,各种块的设置也一致,包括块的旋转,加速下降,平移,满行消去,到顶游戏结束功能;

2).       能够自定义游戏中功能键的具体按键,显示下一方块提示信息,以及游戏数据的统计;

3).       考虑需要解决的问题:怎么样设置图形显示;怎样获取鍵盘输入;怎样控制方块的移动;怎样控制时间间隔(用于游戏中控制形状的下落);游戏中的各种形状及整个游戏空间怎么用数据表示;游戏中怎么判断左右及向下移动的可能性;游戏中怎么判断某一形状旋转的可能性;按向下方向键时加速某一形状下落速度的处理;怎么判断某一形状已经到底;怎么判断某一已经被填满;怎么消去已经被填满的一行;怎么消去某一形状落到底后能够消去的所有的行;(如长条最多可以消去四行)怎样判断游戏结束,关于“下一个”形状取法的问题。

2        设计思路

2.1   用面向对象的方法分析系统

从游戏的基本玩法出发,主要就是俄罗斯方块的形状和旋转,在设计中在一个图片框中构造了一个20*20(像素)的小块,由这些小块组合成新的形状,每四个小块连接在一起就可以构造出一种造型,总共设计了7中造型,每种造型又可以通过旋转而变化出2到4种形状,在游戏窗体中用户就可以使用键盘的方向键来控制方块的运动,然后对每一行进行判断,如果有某行的方块是满的,则消除这行的方块,并且使上面的方块自由下落,其中,方块向下的速度是有时钟控件控制的。俄罗斯方块游戏设计主要包括以下10个方面:

1).         游戏界面的设计。

2).         俄罗斯方块的实现。

3).         键盘输入信息的获取。

4).         俄罗斯方块的移动(向左,向右和向下)。

5).         俄罗斯方块的变换。

6).         方块自动下落与速度的选择。

7).         慢行的判断与消行。

8).         游戏结束判断。

9).         用户配置保存。

在主窗口中,通过调用俄罗斯方块类来实现程序的表示层,在该窗口中通过两个Panel控件来实现方块叠放窗口和下一方块信息窗口;调用设置窗口,保存设计窗口类传回的信息,并设置到游戏中去,保存在配置文件中;

在设置窗口中,以良好的界面提供用户自定义快捷键的接口,保存相应设置参数,以提供给调用窗口。

2.2运用的控件和主要对象

在设计过程中主要用到的控件有:PictureBox控件,MenuStrip控件,Button控件,Label控件,Timer控件,winmm组件,DirectSound等等。

3        系统功能实现

3.1   屏幕信息初始化

用来显示状态信息的框

privateSystem.Windows.Forms.GroupBox statusBox;

开始按钮

privateSystem.Windows.Forms.Button btnStart;

显示“下一块”的标签

privateSystem.Windows.Forms.Label label3;

显示“分数”的标签

privateSystem.Windows.Forms.Label label2;

显示“等级”的标签

privateSystem.Windows.Forms.Label label1;

用来画下一块方块的区域

privateSystem.Windows.Forms.PictureBox panel1;

游戏区域

privateSystem.Windows.Forms.PictureBox gameArea;

实现如下主界面效果图(图3-1):

1.1   方块的实现

在程序中每一个方块都是一个Block类的实例。Block包括的参数有方块的宽度,高度,最左端横坐标,最上端纵坐标,方块的数组表示。其中一共有7中形状的方块,以数组表示为:

     11     11    1       11     010    10     01

01     10    1       11     111     11    11

01     10    1                      01     10

                   1

方块的7种形状分别以数字0-6来代表,在构造函数中,随机生成0-6中数字,以此来随机生成方块的形状。用来在界面上显示方块的贴图也以0-6的数字来代表,同样以随机数的形式来随机的现实方块的颜色。

1.2   键盘输入事件处理

因为在界面上有一个按钮,并且只有一个按钮,所以该按钮在通常情况下都是默认为焦点。在这种情况下按下某些键,比如空格,就会产生出发按钮事件的情况。因此必须重载整个WinForm的ProcessCmdKey来避免这样的问题。

当按向左,向右及旋转按钮时,只要相应的处理方块的位置或者形状即可,但是当按向下或者立即下落时,需要不同的处理。向下移动时,如果移动到最底部但还未固定,则需要重新设置计时器间隔时间,从而使自动下落时,底部未固定的方块到固定的时间相同。如果方块在最底部而未固定的时候,向下移动,则立即固定。这两种情况,当方块固定后,都需要判断是否消行,立即下落时,需要判断是否消行。

1.3   方块的移动

游戏中方块的移动分为向左移动,向右移动,向下移动和立即落下。

        向左移动:

        public void MoveLeft() {

            int xPos =runBlock.XPos-1;

            intyPos = runBlock.YPos;

            for(int i = 0; i < runBlock.Length; i++)

            {

                if(xPos + runBlock[i].X <0)//如果超出左边界则失败

                {

                    return;

                }

                if(!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果左边有东西挡则失败

                {

                    return;

                }

            }

            runBlock.erase(gpPaltte);//擦除原来位置的转块

            runBlock.XPos--;

            runBlock.Paint(gpPaltte);//在新位置上画转块

}

向右移动:

public void MoveRight()

        {

            intxPos = runBlock.XPos + 1;

            intyPos = runBlock.YPos;

            for(int i = 0; i < runBlock.Length; i++)

            {

                if(xPos + runBlock[i].X >_width-1)//如果超出右边界则失败

                {

                    return;

                }

                if(!coorArr[xPos + runBlock[i].X, yPos - runBlock[i].Y].IsEmpty)//如果右边有东西挡则失败

                {

                    return;

                }

            }

            runBlock.erase(gpPaltte);//擦除原来位置的转块

            runBlock.XPos++;

            runBlock.Paint(gpPaltte);//在新位置上画转块

        }

向下移动:

public void Drop() {

            timerBlock.Stop();

            while(Down()) ;

            timerBlock.Start();

        }

1.4   方块的变换

        public voidDeasilRotate() //顺时针旋转

        {

            for (int i = 0; i< runBlock.Length;i++ )

            {

                int x = runBlock.XPos + runBlock[i].Y;

                int y = runBlock.YPos + runBlock[i].X;

                if (x < 0 || x > _width - 1)//如果超出左右边界,则失败

                   return;

                if (y < 0 || y > _height - 1)//如果超出上下边界,则失败

                   return;

                if (!coorArr[x, y].IsEmpty)//如果旋转后的位置上有转块,则失败

                    return;

            }

           runBlock.erase(gpPaltte);//擦除原来位置的转块

           runBlock.DeasilRotate();

           runBlock.Paint(gpPaltte);//在新位置上画转块

        }

        public voidContraRotate() //逆时针旋转

        {

            for (int i = 0; i< runBlock.Length; i++)

            {

                int x = runBlock.XPos - runBlock[i].Y;

                int y = runBlock.YPos - runBlock[i].X;

               if (x < 0 || x > _width - 1)//如果超出左右边界,则失败

                   return;

                if (y < 0|| y > _height - 1)//如果超出上下边界,则失败

                   return;

                if (!coorArr[x, y].IsEmpty)//如果旋转后的位置上有转块,则失败

                   return;

            }

           runBlock.erase(gpPaltte);//擦除原来位置的转块

           runBlock.ContraRotate();

           runBlock.Paint(gpPaltte);//在新位置上画转块

        }

1.5   判断方块是否到底

public voidCheckAndOverBlock()//检查转块是否到底,如果到底则把当前转块归入coorArr,并产生新的转块

        {

            boolover = false;//设置一个当前运行转块是否到底的标志

            for(int i = 0; i < runBlock.Length;i++ )//遍历当前运行转块的所有小方块

            {

                intx = runBlock.XPos + runBlock[i].X;

                inty = runBlock.YPos - runBlock[i].Y;

                if(y == _height - 1)//如果到达下边界,则结束当前转块

                {

                   over = true;

                    break;

                }

                if(!coorArr[x, y+1].IsEmpty) //如果下面有转块,则当前转块结束

                {

                   over = true;

                   break;

                }

            }

            if(over)

            {

                for(int i = 0; i < runBlock.Length; i++)//把当前转块归入coordinateArr

               {

                    coorArr[runBlock.XPos +runBlock[i].X, runBlock.YPos - runBlock[i].Y] = runBlock.BlockColor;

               }

               //检查是否有满行情况,如果有则删除

               CheckAndDelFullRow();

               //产生新转块

               runBlock = readyBlock;//新的转块为准备好的转块

               runBlock.XPos = _width / 2;//确定当前运行转块的出生位置

               int y = 0;//确定转块Ypos,确定刚出生的转块顶上没空行

               for (int i = 0; i < runBlock.Length; i++)

               {

                    if (runBlock[i].Y > y)

                        y = runBlock[i].Y;

               }

               runBlock.YPos = y;

               //检查新生成的转块所占用的地方是否已经有转块存在,如果有,游戏结束

               for (int i = 0; i

关注
打赏
1688896170
查看更多评论

暂无认证

  • 0浏览

    0关注

    115984博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.0950s