C++课程设计实验报告(俄罗斯方块)_第1页
C++课程设计实验报告(俄罗斯方块)_第2页
C++课程设计实验报告(俄罗斯方块)_第3页
C++课程设计实验报告(俄罗斯方块)_第4页
C++课程设计实验报告(俄罗斯方块)_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

一、需求分析1.1系统概述该游戏在DOS下为玩家提供传统俄罗斯方块游戏的基本功能,玩家可以通过键盘控制在游戏区中堆积软件随机提供的由四个小方块不同组合的7种类型不同颜色的方块,每个小方格的颜色也是随机的,并且在整个下落的过程中,其颜色也呈动态变化。游戏过程中,每在游戏区堆满一行后,自动消除并记分。同时消去的行数越多,那一次性所加的分数也就越多。一行是100,两行是200,三行是400,四行是500分。为了得到更多的分,那么我们游戏者就要想办法一次尽可能多的消去方块。当游戏区不能再堆积新来的方块时,游戏结束。游戏设定3个级别,初级,中级和高级,每个级别有分三个小的级别,级别越高,方块下降的速度越快、难度越大。为了避免游戏频发枯燥,增加游戏的趣味性,该游戏为游戏者插入了音乐,对该功能有实现暂停的控制。该游戏的以“英雄榜”来判断玩家水平的高低,如果玩家的得分大于了保存的最高分,则将玩家的的得分写入文件,如果得分不大于最高分,则保持不变。游戏以最终玩家获得的分数来判断玩家水平的高低。1.2功能需求描述这次实验以及部分功能的实现都是一次小小的尝试,获得不错的效果。这个游戏,不仅可以满足游戏爱好者对游戏的要求,同时我们增加了趣味性,让游戏有一个比较好听的背景音乐,在玩游戏的同时,让玩家饱享视听大宴。这有别于常规的俄罗斯方块算法,游戏中,玩家依靠自己消层来得分,而且保证了玩家对游戏趣味性的追求,并且游戏的英雄榜功能为玩家提供了一个良好的测试水平的平台。当玩家游戏池中的砖块累积到顶端时游戏失败。二、系统设计2.1数据流程图数据流图是对系统数据流向的一种描述,并从本质上让程序的使用者,大致了解系统的使用方法。本俄罗斯游戏的大致流程图如下:界界面处理分配及实现命令数据集(方块和游戏信心)对方块进行操作以及对游戏的信息进行操作从键盘接受命令并返回给控制模块将数据结果返回至界面VCM2.2程序功能模块俄罗斯方块游戏俄罗斯方块游戏界面处理响应命令处理游戏进程处理方块初始化窗口和游戏区绘制方块显示游戏信息获得命令分配命令新游戏开始游戏结束退出整个系统产生和获取方块方块左、右移动及旋转、下沉2.3程序流程图开始开始显示窗口和游戏区新的游戏开始从键盘读命令操作游戏是否可以消行标记并消除该行方块是否到顶再来一局?退出游戏三、关键代码描述3.1程序模块详细设计3.1.1界面初始化程序界面程序在启动运行时,系统会通过调用视图类中的重绘图函数对界面进行界面的初始化。其界面如图所示:实现该功能的代码如下:voidViewWindows::draw(){ initgraph(640,480); srand((unsigned)time(NULL)); //显示操作说明 setfont(14,0,_T("宋体")); outtextxy(20,330,_T("操作说明")); outtextxy(20,350,_T("上:旋转")); outtextxy(20,370,_T("左:左移")); outtextxy(20,390,_T("右:右移")); outtextxy(20,410,_T("下:下移")); outtextxy(20,430,_T("空格:沉底")); outtextxy(20,450,_T("ESC:退出")); //设置坐标原点 setorigin(220,20); //绘制游戏区边界 rectangle(-1,-1,WIDTH*SIZE,HEIGHT*SIZE); rectangle((WIDTH+1)*SIZE-1,-1,(WIDTH+5)*SIZE,4*SIZE);}voidViewGameinfo::draw(intScore,intLevel,intHigest_score){ charsc[10],sl[10],sr[10]; intHigest_num; ifstreamfile_in("d:\\Higest_score.txt"); if(!file_in) { ofstreamfile_ou("d:\\Higest_score.txt"); file_ou<<0<<endl; return; } file_in>>Higest_num; Higest_score=Higest_num; sprintf(sc,"%4d",Score); sprintf(sl,"%4d",Level); sprintf(sr,"%4d",Higest_score); outtextxy(-200,100,_T("Score")); outtextxy(-200,120,sc); outtextxy(-200,140,_T("Level")); outtextxy(-200,160,sl); outtextxy(-200,180,_T("Higest_score")); outtextxy(-200,200,sr);}voidViewBlock::DrawBlock(BLOCKINFO_block,DRAW_draw){ WORDb=g_Blocks[_block.getID()].dir[_block.getDir()]; intx,y; intcolor=BLACK; switch(_draw) { caseSHOW:color=g_Blocks[_block.getID()].color;break; caseHIDE:color=BLACK; break; caseFIX:color=g_Blocks[_block.getID()].color/3;break; } setfillstyle(color); for(inti=0;i<16;i++) { if(b&0x8000) { x=_block.getX()+i%4; y=_block.getY()-i/4; if(y<HEIGHT) { if(_draw!=HIDE) bar3d(x*SIZE+2,(HEIGHT-y-1)*SIZE+2,(x+1)*SIZE-4,(HEIGHT-y)*SIZE-4,3,true); else bar(x*SIZE,(HEIGHT-y-1)*SIZE,(x+1)*SIZE-1,(HEIGHT-y)*SIZE-1); } } b<<=1; } }3.1.2游戏随机获取新方块的实现如下:voidControl::NewGame(){ //清空游戏区 setfillstyle(BLACK); bar(0,0,WIDTH*SIZE-1,HEIGHT*SIZE-1); ZeroMemory(g_World,WIDTH*HEIGHT); Level=0; ViewGameinfov; v.draw(Score,Level,Higest_score); g_NextBlock.setID(rand()%9); g_NextBlock.setDir(rand()%4); //获取新方块 NewBlock();}voidControl::NewBlock(){ //生成下一个方块 g_NextBlock.setX(WIDTH+1); g_NextBlock.setY(HEIGHT-1); g_CurBlock.setID(g_NextBlock.getID()), g_NextBlock.setID(rand()%9); g_CurBlock.setDir(g_NextBlock.getDir()), g_NextBlock.setDir(rand()%4); g_CurBlock.setX((WIDTH-4)/2); g_CurBlock.setY(HEIGHT+2); //下移新方块直到有局部显示 WORDc=g_Blocks[g_CurBlock.getID()].dir[g_CurBlock.getDir()]; while((c&0xF)==0) { g_CurBlock.setY(g_CurBlock.getY()-1); c>>=4; } //绘制新方块 ViewBlockv; v.DrawBlock(g_CurBlock); //绘制下一个方块 setfillstyle(BLACK); bar((WIDTH+1)*SIZE,0,(WIDTH+5)*SIZE-1,4*SIZE-1); v.DrawBlock(g_NextBlock);}3.1.3游戏接收命令的实现如下:CTRLControl::GetControl(intLevel,bool_onlyresettimer){ intflag; switch(Rank) { case1:flag=800;break; case2:flag=400;break; case3:flag=200;break; default:flag=800; } staticDWORDoldtime=GetTickCount(); //重置计时器 if(_onlyresettimer) { oldtime=GetTickCount(); returnCTRL_DOWN;//仅仅为了重置计时器,随便返回一个值 } flag=flag/(Level+Rank); //获取控制值 while(true) { //如果超时,自动下落一格 DWORDnewtime=GetTickCount(); if(newtime-oldtime>=flag) { oldtime=newtime; returnCTRL_DOWN; } //如果有按键,返回按键对应的功能 if(kbhit()) { switch(getch()) { case'w': case'W': returnCTRL_ROTATE; case'a': case'A': returnCTRL_LEFT; case'd': case'D': returnCTRL_RIGHT; case's': case'S': returnCTRL_DOWN; case'p': case'P': returnCTRL_PAUSE; case27: returnCTRL_QUIT; case'': returnCTRL_SINK; case0: case0xE0: switch(getch()) { case72: returnCTRL_ROTATE; case75: returnCTRL_LEFT; case77: returnCTRL_RIGHT; case80: returnCTRL_DOWN; } } } }}3.1.4程序分配命令的实现如下://分发控制命令voidGAME::DispatchControl(CTRL_ctrl){ switch(_ctrl) { caseCTRL_ROTATE: g_CurBlock.OnRotate(); break; caseCTRL_LEFT: g_CurBlock.OnLeft(); break; caseCTRL_RIGHT: g_CurBlock.OnRight(); break; caseCTRL_DOWN: OnDown(); break; caseCTRL_SINK: OnSink(); break; caseCTRL_PAUSE: Gamepause();break; caseCTRL_QUIT: break; }}3.1.5方块左右移动和旋转的实现如下:voidBLOCKINFO::OnLeft(){ BLOCKINFOtmp=*this; tmp.setX(tmp.getX()-1); if(CheckBlock(tmp)) { v1.DrawBlock(*this,HIDE); x--; v1.DrawBlock(*this); }}voidBLOCKINFO::OnRight(){ BLOCKINFOtmp=*this; tmp.setX(tmp.getX()+1); if(CheckBlock(tmp)) { v1.DrawBlock(*this,HIDE); x++; v1.DrawBlock(*this); }}voidBLOCKINFO::OnRotate(){ //获取可以旋转的x偏移量 intdx; BLOCKINFOtmp=*this; tmp.setDir(tmp.getDir()+1); if(CheckBlock(tmp)) { dx=0; gotorotate; } tmp.setX(x-1); if(CheckBlock(tmp)) { dx=-1; gotorotate; } tmp.setX(x+1); if(CheckBlock(tmp)) { dx=1; gotorotate; } tmp.setX(x-2); if(CheckBlock(tmp)) { dx=-2; gotorotate; } tmp.setX(x+2); if(CheckBlock(tmp)) { dx=2; gotorotate; } return;rotate: //旋转 v1.DrawBlock(*this,HIDE); dir++; x+=dx; v1.DrawBlock(*this);}3.1.6方块下落和沉底的实现如下:voidGAME::OnDown(){ ViewBlockv; BLOCKINFOtmp=g_CurBlock; tmp.setY(tmp.getY()-1); if(g_CurBlock.CheckBlock(tmp)) { v.DrawBlock(g_CurBlock,HIDE); g_CurBlock.setY(g_CurBlock.getY()-1); v.DrawBlock(g_CurBlock); } else OnSink(); //不可下移时,执行“沉底方块”操作}voidGAME::OnSink(){ inti,x,y; intcount=0; ViewBlockv1; ViewGameinfov2; //连续下移方块 v1.DrawBlock(g_CurBlock,HIDE); BLOCKINFOtmp=g_CurBlock; tmp.setY(tmp.getY()-1); while(g_CurBlock.CheckBlock(tmp)) { g_CurBlock.setY(g_CurBlock.getY()-1); tmp.setY(tmp.getY()-1); } v1.DrawBlock(g_CurBlock,FIX); //固定方块在游戏区 WORDb=g_Blocks[g_CurBlock.getID()].dir[g_CurBlock.getDir()]; for(i=0;i<16;i++) { if(b&0x8000) { if(g_CurBlock.getY()-i/4>=HEIGHT) { //如果方块的固定位置超出高度,结束游戏 Gameover(); return; } else g_World[g_CurBlock.getX()+i%4][g_CurBlock.getY()-i/4]=1; } b<<=1; } //检查是否需要消掉行,并标记 introw[4]={0}; boolbRow=false; for(y=g_CurBlock.getY();y>=max(g_CurBlock.getY()-3,0);y--) { i=0; for(x=0;x<WIDTH;x++) if(g_World[x][y]==1) i++; if(i==WIDTH) { bRow=true; count++; row[g_CurBlock.getY()-y]=1; setfillstyle(WHITE,DIAGCROSS2_FILL); bar(0,(HEIGHT-y-1)*SIZE+SIZE/2-2,WIDTH*SIZE-1,(HEIGHT-y-1)*SIZE+SIZE/2+2); } } if(bRow) { //延时200毫秒 Sleep(200); //擦掉刚才标记的行 IMAGEimg; for(i=0;i<4;i++) { if(row[i]) { for(y=g_CurBlock.getY()-i+1;y<HEIGHT;y++) for(x=0;x<WIDTH;x++) { g_World[x][y-1]=g_World[x][y]; g_World[x][y]=0; } getimage(&img,0,0,WIDTH*SIZE,(HEIGHT-(g_CurBlock.getY()-i+1))*SIZE); putimage(0,SIZE,&img); } } if(count==4) { count=5; } if(count==3) { count=4; } Score+=100*count; Level=(Score-(Rank-1)*1500)/500; if(Level>=3) { Rank++; if(Rank>3) { HWNDwnd=GetHWnd(); if(MessageBox(wnd,_T("恭喜你,你已经征服该游戏!"),_T("提醒"),MB_OK)) Quit(); } else { HWNDwnd=GetHWnd(); if(MessageBox(wnd,_T("恭喜你,进入下一关!"),_T("提醒"),MB_OKCANCEL|MB_ICONQUESTION)==IDOK) NewGame(); else { Quit(); } } } v2.draw(Score,Level,Higest_score); } //重新计算延时 NewBlock(); GetControl(Level,true);}消行瞬间3.1.7结束和退出实现如下:voidControl::Gameover(){ HWNDwnd=GetHWnd(); ofstreamfile_out("d:\\Higest_score.txt"); if(!file_out) return; if(Higest_score<=Score) { file_out<<Score<<endl; } file_out.close(); if(MessageBox(wnd,_T("游戏结束。\n您想重新来一局吗?"),_T("游戏结束"),MB_YESNO|MB_ICONQUESTION)==IDYES) { Rank=1; Score=0; NewGame(); } else Quit();}//退出游戏voidControl::Quit(){ closegraph(); exit(0);}3.2附加功能的实现3.2.1计分功能模块:1).classControl{public: voidNewGame(); voidNewBlock(); CTRLGetControl(intLevel,bool_onlyresettimer=false); voidGameover(); voidQuit();protected: BLOCKINFOg_CurBlock,g_NextBlock; staticintScore; staticintLevel;intRank;在Control类中,定义了Score,Level,Rank几个静态的成员变量,并且给它们进行初始化操作。intGAME::Score=0;intGAME::Level=0;2).对计分方式的具体的操作。(1) intflag; switch(Rank) { case1:flag=800;break; case2:flag=400;break; case3:flag=200;break; default:flag=800; } flag=flag/(Level+Rank);(2). Score+=100*count; Level=(Score-(Rank-1)*1500)/500; if(Level>=3) { Rank++; if(Rank>3) { HWNDwnd=GetHWnd(); if(MessageBox(wnd,_T("恭喜你,你已经征服该游戏!"),_T("提醒"),MB_OK)) Quit(); } else { HWNDwnd=GetHWnd(); if(MessageBox(wnd,_T("恭喜你,进入下一关!"),_T("提醒"),MB_OKCANCEL|MB_ICONQUESTION)==IDOK) NewGame(); else { Quit(); } } }3.2.2暂停功能的实现voidGAME::Gamepause(){ do { Sleep(100); PlaySound(NULL,NULL,SND_FILENAME); //停止播放音乐 } while(!kbhit()); PlaySound((char*)"C:\\peter.wav",NULL,SND_ASYNC|SND_LOOP);//播放音乐}3.2.3“英雄榜”功能的实现在Control类中定义了成员staticintHigest_score;对最高分的保存操作(采用文件的形式) ofstreamfile_out("d:\\Higest_score.txt"); if(!file_out) return; if(Higest_score<=Score) { file_out<<Score<<endl; } file_out.close();对最高分的读取操作。 if

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论