北邮俄罗斯方块C++课程设计报告.docx
《北邮俄罗斯方块C++课程设计报告.docx》由会员分享,可在线阅读,更多相关《北邮俄罗斯方块C++课程设计报告.docx(26页珍藏版)》请在冰点文库上搜索。
北邮俄罗斯方块C++课程设计报告
俄罗斯方块C++课程设计报告
学院:
专业:
班级:
姓名:
XXX
1、题目
利用C++编写俄罗斯方块游戏,是俄罗斯游戏能够在MicrosoftVisualC++6.0上运行该游戏。
2、实验目的
一方面通过对程序算法的设计和分析提高我们对问题进行文字论述和文字表达的能力并且培养我们进行知识综合,软件开发和软件的调试技术,开发较大程序的能力。
另一方面培养了我们相互合作的精神并培养了我们的创新意识。
3、需求分析
功能需求
随机给出不同的形状下落填充给定的区域,若填满一条便消掉,记分,设计不同的游戏难度,即方块下落的速度不同,若在游戏中各形状填满了给定区域,为输者。
方块及各种变换需求
本游戏需要有7种方块,而每种方块还可以进行旋转。
每种方块每行每列最多只有4个小方块。
可以将它们放在一个n*m的区域内,该区域可以看作是有许多个等面积小方块构成的区域,而这些区域的状态只有两种,被方块占据或空闲。
因此,对于整个游戏区域的空间是占据或空闲,可以用一位数来标识。
对于7种方块和它们旋转后的形态我们可以用不同的标识进行标记。
对于旋转,游戏中所有方块都是按照逆时针旋转的规则进行的,而且在旋转过程中它们不会因为旋转而下降,总会保持在同一高度。
任何方块经过一个旋转周期还会变回原型。
操作的需求
向上键
产生方块旋转操作,方块并非任何情况都能旋转,如果旋转后与小方格矩阵显示的方块有冲突或超出边界时,均不能发生旋转。
因此首先要判断是否有足够的空间进行旋转。
然后选择是否旋转。
向下键
产生方块加速下落操作,如果方块已经到达游戏区域底部或者已经有其他方块遮挡,则方块停止下降。
向左键
产生下落方块左移操作。
首先要判断此方块是否能够发生左移,当越界或被其他显示方块阻挡时,则不能左移。
向右键
产生下落方块右移操作。
首先要判断此方块是否能够发生右移,当越界或被其他显示方块阻挡时,则不能右移。
4、详细设计
主要功能设计
根据分析,俄罗斯方块这个程序一共要实现如下几个功能,开始游戏(F8)、游戏的暂停\继续(S)和退出游戏(Q)。
其中游戏控制最为主要和重要,它控制着整个游戏的画面和有关数据的操作,是游戏的核心部分。
暂停和退出功能做成一体,在退出的提示下不做任何操作即可实现暂停的功能。
程序流程图
根据分析后的程序结构图设计出相应的流程图。
俄罗斯方块的内容主要包括游戏开始,画背景和边框,显示分数等级和下一个方块的预览图;根据速度没隔一定时间方块自动下落,当有按键操作时,根据相应按键执行动作,每次动作前要判断是否动作可以执行。
下落方块满一行时,消去该行,根据消去行数得到相应分数。
分数达到一定程度,等级提升,速度加快。
同时可以响应Esc按键,提示是否退出程序。
游戏界面
俄罗斯方块的游戏界面包括游戏区域边框、下落方块绘制、右部计分和预览图显示等。
游戏区域边框的绘制比较简单,循环中确定光标的位置输出特定字符,即可完成边框绘制。
游戏区方块的绘制,循环从数据数组中依次读出数据,根据读到的数据显示“□”,最后组成方块的形状,完成方块的绘制。
计分和预览图部分先画出一个矩形区域,然后控制光标在其中显示分数、等级、预览图和提示信息。
A
生成方块
本程序中生成的方块有7种形状,每一种方块以shapeindex标记,在程序运行生成方块时,调用next=rand()%7;语句,确定当前要显示的是哪一个方块形状。
而在实际运行中,第一次需要调用两次生成方块函数DrawNext(),将先产生的赋给游戏当前方块,第二个赋给预览图方块。
以后每次产生一个方块,把预览方块赋给当前方块,把新产生的赋给预览方块。
方块变形
俄罗斯方块的特点就在于通过方块的变形拼满整行来消去该行方块从而使游戏可以继续下去,很难想象不能变形的俄罗斯方块是什么样子。
而变形的过程就是根据当前方块形状改变方块的相对位置,这样就可以改变方块的形状了。
在程序中每当按下“↑”键,程序判断可以变形后,根据当前方块的形状序号shapeindex和变化形状序号IsFit调用相应的方块数值赋给draw()函数,通过刷新重画就可以显示变化后的方块了。
方块显示
以上方块的操作都是数据层面的操作,而真正要在游戏窗口中看到数据的变化,还必须把方块不断的绘制出来。
这就是draw()函数的作用。
把当前运动的方块对应节点存储在一个4*4数组里,变形和生成方块的过程就是更新该数组数据的过程。
然后在draw()函数里检测数组的各个值,并控制光标跳到一定位置,画出“□”组成方块。
障碍判断
障碍判断,就是在方块运动中或者变形中判断周围是否有障碍阻碍下落、移位、变形。
当方块下落遇到下面有方块或者到达下边界则应停止下落并记录数据,存入背景数据数组。
变形时应判断这个变形是否可以进行,如果有障碍则不能变形。
例如当方块达到右边界,而若变形则会越过边界,那么这个变形的命令是不应执行的。
所有这些判断都由IsFit()函数进行,根据是否有障碍返回true或false,再由其他函数接收执行相应操作。
消行计分
游戏玩家拼满一行后,程序消去满行,并计分。
中当一个方块下落停止后,程序检查方块是否充满了游戏区域,如果是结束游戏。
不是,则判断是否构成消行条件,从下落方块的最低点依次向上检查是否可以消行,根据消去行数分数增加。
分数达到一定程度,等级提升,分数暂定为每1000升一级。
暂停退出
游戏的友好性在于能考虑用户的需要,随时可以暂停/继续游戏,在不愿继续游戏时退出游戏。
程序调试
经过调试和修改,程序完全实现设计要求,成功模拟了俄罗斯方块的运行过程和游戏效果,只是界面略微简陋,但已从程序层面上实现了游戏,达到了这次实训的要求和目的。
程序正常生成方块,根据速度值每隔一定时间自动下落,如有操作按键按下,根据按键实现位移和变形。
当方块满一行后,可以消除该行,同时记录分数和等级。
软件使用说明
打开俄罗斯方块游戏后,通过控制方向区域的“↑”、“↓”、“←”、“→”来控制,“↑”键代表变形转换,“↓”、“←”、“右”均代表方向键,“Q”代表退出游戏键。
若想暂停游戏,可通过“S”键,当初来询问框是,可不做选择,则可达到暂停的效果
5、实验结果
六、源程序代码(详细的注释)
#include
#include
#include
#include
#include
#include
#pragmacomment(lib,"winmm.lib")
usingnamespacestd;
classConsole
{
public:
Console()
{
hStdOutput=INVALID_HANDLE_VALUE;
hStdError=INVALID_HANDLE_VALUE;
}
boolOpen(void)
{
hStdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
hStdError=GetStdHandle(STD_ERROR_HANDLE);
returnINVALID_HANDLE_VALUE!
=hStdOutput&&INVALID_HANDLE_VALUE!
=hStdError;
}
inlineboolSetTitle(char*title)//设置标题
{
returnTRUE==SetConsoleTitle(title);
}
boolRemoveCursor(void)//去处光标
{
CONSOLE_CURSOR_INFOcci;
if(!
GetConsoleCursorInfo(hStdOutput,&cci))returnfalse;
cci.bVisible=false;
if(!
SetConsoleCursorInfo(hStdOutput,&cci))returnfalse;
if(!
GetConsoleCursorInfo(hStdError,&cci))returnfalse;
cci.bVisible=false;
if(!
SetConsoleCursorInfo(hStdError,&cci))returnfalse;
returntrue;
}
boolSetWindowRect(shortx,shorty)//设置窗体尺寸
{
SMALL_RECTwrt={0,0,x,y};
if(!
SetConsoleWindowInfo(hStdOutput,TRUE,&wrt))returnfalse;
if(!
SetConsoleWindowInfo(hStdError,TRUE,&wrt))returnfalse;
returntrue;
}
boolSetBufSize(shortx,shorty)//设置缓冲尺寸
{
COORDcoord={x,y};
if(!
SetConsoleScreenBufferSize(hStdOutput,coord))returnfalse;
if(!
SetConsoleScreenBufferSize(hStdError,coord))returnfalse;
returntrue;
}
boolGotoXY(shortx,shorty)//移动光标
{
COORDcoord={x,y};
if(!
SetConsoleCursorPosition(hStdOutput,coord))returnfalse;
if(!
SetConsoleCursorPosition(hStdError,coord))returnfalse;
returntrue;
}
boolSetColor(WORDcolor)//设置前景色/背景色
{
if(!
SetConsoleTextAttribute(hStdOutput,color))returnfalse;
if(!
SetConsoleTextAttribute(hStdError,color))returnfalse;
returntrue;
}
boolOutputString(constchar*pstr,size_tlen=0)//输出字符串
{
DWORDn=0;
returnTRUE==WriteConsole(hStdOutput,pstr,len?
len:
strlen(pstr),&n,NULL);
}
boolOutputStringNoMove(shortx,shorty,constchar*pstr,size_tlen=0)//输出字符串
{
COORDcoord={x,y};
DWORDn=0;
returnTRUE==WriteConsoleOutputCharacter(hStdOutput,pstr,len?
len:
strlen(pstr),coord,&n);
}
private:
HANDLEhStdOutput;
HANDLEhStdError;
};
constcharshapeindex[7][4][4][4]=
{
{
{{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}}
}
{
{{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}}
}
{
{{1,1,1,0},{1,0,0,0},{0,0,0,0},{0,0,0,0}},
{{1,0,0,0},{1,0,0,0},{1,1,0,0},{0,0,0,0}},
{{0,0,1,0},{1,1,1,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}}
}
{
{{1,1,1,0},{0,0,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,0,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}},
{{0,1,0,0},{0,1,0,0},{1,1,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}},
{{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}}
}
{
{{0,1,0,0},{1,1,1,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}},
{{1,1,1,0},{0,1,0,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}}
}
{
{{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}}
}
};
constWORDCOLOR_A=FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY;//运动中的颜色
constWORDCOLOR_B=FOREGROUND_RED;//固定不动的颜色
constWORDCOLOR_C=FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_BLUE;//空白处的颜色
intscore=0,level=0;
chardata[19][11]={0};
intnext=-1;
intx=4,y=-2,c=-1,z=0;//x坐标,坐标,当前方块,方向
Consolecsl;//定义控制台对象
voidDrawScoreLevel(void)//绘制得分
{
chartmp[6];
sprintf(tmp,"%05d",score);
csl.OutputStringNoMove(31,19,tmp,5);
sprintf(tmp,"%01d",level);
csl.OutputStringNoMove(35,15,tmp,1);
}
voidDrawNext(void)//绘制"预览框"中的图形
{
for(inti=0;i<2;++i)
{
for(intj=0;j<4;++j)
{
csl.OutputStringNoMove(28+j*2,10+i,shapeindex[next][0][i][j]==0?
" ":
"■",2);
}
}
}
voidDrawOver(void)//游戏结束
{
system("cls");
system("color41");
cout<<"\t\t\t\t\t\tpleaseretry!
!
!
!
"<csl.OutputStringNoMove(10,10,"GAMEOVER");
}
voidDraw(WORDcolor)
{
for(inti=0;i<4;++i)
{
if(y+i<0||y+i>=19)continue;
for(intj=0;j<4;++j)
{
if(shapeindex[c][z][i][j]==1)
{
csl.SetColor(color);
csl.GotoXY(2+x*2+j*2,1+y+i);
csl.OutputString("■",2);
}
}
}
}
boolIsFit(intx,inty,intc,intz)//给定的x,y,c,z是否可行
{
for(inti=0;i<4;++i)
{
for(intj=0;j<4;++j)
{
if(shapeindex[c][z][i][j]==1)
{
if(y+i<0)continue;
if(y+i>=19||x+j<0||x+j>=11||data[y+i][x+j]==1)returnfalse;
}
}
}
returntrue;
}
voidRemoveRow(void)//消行
{
constcharFULLLINE[]={1,1,1,1,1,1,1,1,1,1,1};
intlinecount=0;
for(inti=0;i<19;++i)
{
if(0==memcmp(data[i],FULLLINE,11))
{
++linecount;
for(intm=0;m<11;++m)
{
for(intn=i;n>1;--n)
{
data[n][m]=data[n-1][m];
csl.SetColor(data[n][m]==1?
COLOR_B:
COLOR_C);
csl.GotoXY(2+m*2,1+n);
csl.OutputString("■",2);
}
data[0][m]=0;
csl.OutputStringNoMove(2+m*2,1,"■",2);
}
}
}
chardata[19][11]={0};
if(linecount==0)return;
int_score=0;
switch(linecount)
{
case1:
_score=100;break;
case2:
_score=300;break;
case3:
_score=700;break;
case4:
_score=1500;break;
}
score+=_score;
if(score>99999)score=99999;
level=score/10000;
DrawScoreLevel();
}
voidMoveTrans(void)//逆时针翻转
{
if(IsFit(x,y,c,(z+1)%4))
{
Draw(COLOR_C);
z=(z+1)%4;
Draw(COLOR_A);
}
}
voidMoveLeft(void)//向左移
{
if(IsFit(x-1,y,c,z))
{
Draw(COLOR_C);
--x;
Draw(COLOR_A);
}
}
voidMoveRight(void)//向右移
{
if(IsFit(x+1,y,c,z))
{
Draw(COLOR_C);
++x;
Draw(COLOR_A);
}
}
voidMoveDown(void)//向下移
{
if(IsFit(x,y+1,c,z))
{
Draw(COLOR_C);
++y;
Draw(COLOR_A);
}
elseif(y!
=-2)//触底
{
Draw(COLOR_B);
for(inti=0;i<4;++i)
{
if(y+i<0)continue;
for(intj=0;j<4;++j)
{
if(shapeindex[c][z][i][j]==1)
{
data[y+i][x+j]=1;
}
}
}
RemoveRow();
x=4,y=-2,c=next,z=0;
next=rand()%7;
DrawNext();
}
else//游戏结束
{
DrawOver();
}
}
voidMessageDeal(void)
{
intcycle=9-level;
for(;;)
{
for(inti=0;i{
if(_kbhit())
{
switch(_getch(