目 录
1. 系统概述……………………………………………… 1 2. 设计说明书…………………………………………… 4 3. 系统操作界面………………………………………… 6 4. 源程序编码…………………………………………… 7 5. 测试计划………………………………………………36 6. 改进意见……………………………………………39 7.课程设计心得体会……………………………… 40 8. 参考书籍、资料…………………………………… 40
1
系统概述
1.1现状分析
在个人电脑日益普及的今天,一些有趣的桌面游戏已经成为人们在使用计算机进行工作或学习之余休闲娱乐的首选,而俄罗斯方块游戏是人们最熟悉的小游戏之一,它以其趣味性强,易上手等诸多特点得到了大众的认可,因此开发此游戏软件可满足人们的一些娱乐的需求。
此俄罗斯方块游戏可以为用户提供一个可在普通个人电脑上运行的,界面美观的,易于控制的俄罗斯方块游戏。
1.2项目要求
俄罗斯方块游戏是一款适合大众的游戏软件,它适合不同年龄的人玩。本软件要实现的功能如下:
(1)游戏区:玩家可以在游戏区中堆积方块,并能够在游戏过程中随时了解
得分情况。
(2)游戏控制:玩家可以通过游戏控制功能来选择开始新的一局游戏,暂停
或退出游戏。
(3) 级别设置:玩家可以根据自己的需要自行设定游戏的开始级别,级别越
高,游戏的速度越快,难度越大。
(4) 1.3系统功能模块示意图
2
显示玩家操作 游戏区 显示操作结果 开始 俄罗斯方块游戏 暂停/继续 提高等级 降低等级 退出 游戏控制
项目开发计划书
项目开发计划书 名称 下达设计任务 收集、分析资料及文档 时间 1天(集中) 释说明。 项目组在项目经理的组织下选题、分析,2天 识别实体,完成《项目开发计划书》及小组人员分工。 各项目组完成系统层次图、用户界面设计、设计 程序编写和测试 编写设计文档 文档提交、答辩 2天 7天 2天 1天 数据库表设计、报表设计,完成《设计说明书》 根据方案进行现场编程、调试。 完成软件测试以及《用户操作手册》的编写。 各小组提交文档,教师根据情况选择是否答辩及答辩方式(抽样答辩或全员答辩)。 工作内容 说明如何着手设计的方法和设计任务的解 设计说明
1.1游戏区模块
3
创建游戏区 游戏区模块 处理玩家游戏操作 显示游戏结果 1.2控制区模块
开始游戏 暂停游戏 游戏控制模块 初始级别设置 退出游戏 系统流程图
4
1.3 开始 设置初始级别 随机选择方块类创建游戏区 是否到顶部 游戏开局 方块下落一行 否 处理玩家操是 游戏结束
1.4模块简介 1. 功能模块 是否到顶部 (1)游戏区模块(创建游戏区,处理玩家操作,显示操作结果) (2)游戏控制模块(开始,暂停继续,提高等级,降低等级,停止,新游戏,帮助)
5
系统操作界面
游戏打开界面
游戏进行中界面
6
源代码编码
#include #include #define _INNER_HELPER /*inner helper method */ /*Scan Codes Define*/ enum KEYCODES { K_ESC =0x011b, K_UP =0x4800, /* upward arrow */ K_LEFT =0x4b00, K_DOWN =0x5000, K_RIGHT =0x4d00, K_SPACE =0x3920, K_P =0x1970 }; 7 /* the data structure of the block */ typedef struct tagBlock { char c[4][4]; /* cell fill info array, 0-empty, 1-filled */ int x; /* block position cx [ 0,BoardWidht -1] */ int y; /* block position cy [-4,BoardHeight-1] */ char color; /* block color */ char size; /* block max size in width or height */ char name; /* block name (the block's shape) */ } Block; /* game's global info */ int FrameTime= 1300; int CellSize= 18; int BoardLeft= 30; int BoardTop= 30; /* next block grid */ int NBBoardLeft= 300; int NBBoardTop= 30; int NBCellSize= 10; /* score board position */ int ScoreBoardLeft= 300; int ScoreBoardTop=100; int ScoreBoardWidth=200; int ScoreBoardHeight=35; int ScoreColor=LIGHTCYAN; /* infor text postion */ int InfoLeft=300; int InfoTop=200; int InfoColor=YELLOW; int BorderColor=DARKGRAY; int BkGndColor=BLACK; int GameRunning=true; int TopLine=BoardHeight-1; /* top empty line */ int TotalScore=100; char info_score[20]; char info_help[255]; char info_common[255]; /* our board, Board[x][y][0]-isFilled, Board[x][y][1]-fillColor */ 8 unsigned char Board[BoardWidth][BoardHeight][2]; char BufferCells[4][4]; /* used to judge if can rotate block */ Block curBlock; /* current moving block */ Block nextBlock; /* next Block to appear */ /* function list */ int GetKeyCode(); int CanMove(int dx,int dy); int CanRotate(); int RotateBlock(Block *block); int MoveBlock(Block *block,int dx,int dy); void DrawBlock(Block *block,int,int,int); void EraseBlock(Block *block,int,int,int); void DisplayScore(); void DisplayInfo(char* text); void GenerateBlock(Block *block); void NextBlock(); void InitGame(); int PauseGame(); void QuitGame(); /*Get Key Code */ int _INNER_HELPER GetKeyCode() { int key=0; if(bioskey(1)) { key=bioskey(0); } return key; } /* display text! */ void _INNER_HELPER DisplayInfo(char *text) { setcolor(BkGndColor); outtextxy(InfoLeft,InfoTop,info_common); strcpy(info_common,text); setcolor(InfoColor); outtextxy(InfoLeft,InfoTop,info_common); } /* create a new block by key number, * the block anchor to the top-left corner of 4*4 cells 9 */ void _INNER_HELPER GenerateBlock(Block *block) { int key=(random(13)*random(17)+random(1000)+random(3000))%7; block->size=3;/* because most blocks' size=3 */ memset(block->c,0,16); switch(key) { case 0: block->name='T'; block->color=RED; block->c[1][0]=1; block->c[1][1]=1, block->c[2][1]=1; block->c[1][2]=1; break; case 1: block->name='L'; block->color=YELLOW; block->c[1][0]=1; block->c[1][1]=1; block->c[1][2]=1, block->c[2][2]=1; break; case 2: block->name='J'; block->color=LIGHTGRAY; block->c[1][0]=1; block->c[1][1]=1; block->c[1][2]=1, block->c[0][2]=1; break; case 3: block->name='z'; block->color=CYAN; block->c[0][0]=1, block->c[1][0]=1; block->c[1][1]=1, block->c[2][1]=1; break; case 4: block->name='5'; block->color=LIGHTBLUE; block->c[1][0]=1, block->c[2][0]=1; block->c[0][1]=1, block->c[1][1]=1; break; case 5: block->name='o'; block->color=BLUE; 10 block->size=2; block->c[0][0]=1, block->c[1][0]=1; block->c[0][1]=1, block->c[1][1]=1; break; case 6: block->name='I'; block->color=GREEN; block->size=4; block->c[1][0]=1; block->c[1][1]=1; block->c[1][2]=1; block->c[1][3]=1; break; } } /* get next block! */ void NextBlock() { /* copy the nextBlock to curBlock */ curBlock.size=nextBlock.size; curBlock.color=nextBlock.color; curBlock.x=(BoardWidth-4)/2; curBlock.y=-curBlock.size; memcpy(curBlock.c,nextBlock.c,16); /* generate nextBlock and show it */ EraseBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize); GenerateBlock(&nextBlock); nextBlock.x=1,nextBlock.y=0; DrawBlock(&nextBlock,NBBoardLeft,NBBoardTop,NBCellSize); } /* rotate the block, update the block struct data */ int _INNER_HELPER RotateCells(char c[4][4],char blockSize) { char temp,i,j; switch(blockSize) { case 3: temp=c[0][0]; c[0][0]=c[2][0], c[2][0]=c[2][2], c[2][2]=c[0][2], c[0][2]=temp; temp=c[0][1]; c[0][1]=c[1][0], c[1][0]=c[2][1], c[2][1]=c[1][2], 11 c[1][2]=temp; break; case 4: /* only 'I' block arived here! */ c[1][0]=1-c[1][0], c[1][2]=1-c[1][2], c[1][3]=1-c[1][3]; c[0][1]=1-c[0][1], c[2][1]=1-c[2][1], c[3][1]=1-c[3][1]; break; } } /* judge if the block can move toward the direction */ int CanMove(int dx,int dy) { int i,j,tempX,tempY; for(i=0;i /* cannot move leftward or rightward */ tempX = curBlock.x + i + dx; if(tempX<0 || tempX>(BoardWidth-1)) return false; /* make sure x is valid! */ /* cannot move downward */ tempY = curBlock.y + j + dy; if(tempY>(BoardHeight-1)) return false; /* y is only checked lower bound, maybe negative */ /* the cell already filled, we must check Y's upper bound before check cell ! */ if(tempY>=0 && Board[tempX][tempY][0]) return false; } } } return true; } /* judge if the block can rotate */ int CanRotate() { int i,j,tempX,tempY; /* update buffer */ memcpy(BufferCells, curBlock.c, 16); RotateCells(BufferCells,curBlock.size); 12 for(i=0;i tempX=curBlock.x+i; tempY=curBlock.y+j; if(tempX<0 || tempX>(BoardWidth-1)) return false; if(tempY>(BoardHeight-1)) return false; if(tempY>=0 && Board[tempX][tempY][0]) return false; } } } return true; } /* draw the block */ void _INNER_HELPER DrawBlock(Block *block,int bdLeft,int bdTop,int cellSize) { int i,j; setfillstyle(SOLID_FILL,block->color); for(i=0;i for(j=0;j if(block->c[i][j] && (block->y+j)>=0) { floodfill( bdLeft+cellSize*(i+block->x)+cellSize/2, bdTop+cellSize*(j+block->y)+cellSize/2, BorderColor); } } } } /* Rotate the block, if success, return true */ int RotateBlock(Block *block) { 13 char temp,i,j; int b_success; if(block->size==2) return true; if(( b_success=CanRotate())) { EraseBlock(block,BoardLeft,BoardTop,CellSize); memcpy(curBlock.c,BufferCells,16); DrawBlock(block,BoardLeft,BoardTop,CellSize); } return b_success; } /* erase a block, only fill the filled cell with background color */ void _INNER_HELPER EraseBlock(Block *block,int bdLeft,int bdTop,int cellSize) { int i,j; setfillstyle(SOLID_FILL,BkGndColor); for(i=0;i for(j=0;j if(block->c[i][j] && (block->y+j>=0)) { floodfill( bdLeft+cellSize*(i+block->x)+cellSize/2, bdTop+cellSize*(j+block->y)+cellSize/2, BorderColor); } } } } /* move by the direction if can, donothing if cannot * return value: true - success, false - cannot move toward this direction */ int MoveBlock(Block *block,int dx,int dy) { int b_canmove=CanMove(dx,dy); if(b_canmove) { EraseBlock(block,BoardLeft,BoardTop,CellSize); 14 curBlock.x+=dx; curBlock.y+=dy; DrawBlock(block,BoardLeft,BoardTop,CellSize); } return b_canmove; } /* drop the block to the bottom! */ int DropBlock(Block *block) { EraseBlock(block,BoardLeft,BoardTop,CellSize); while(CanMove(0,1)) { curBlock.y++; } DrawBlock(block,BoardLeft,BoardTop,CellSize); return 0;/* return value is assign to the block's alive */ } /* init the graphics mode, draw the board grid */ void InitGame() { int i,j,gdriver=DETECT,gmode; struct time sysTime; /* draw board cells */ memset(Board,0,BoardWidth*BoardHeight*2); memset(nextBlock.c,0,16); strcpy(info_help,\"P: Pause Game. --by hoodlum1980\"); initgraph(&gdriver,&gmode,\"\"); setcolor(BorderColor); for(i=0;i<=BoardWidth;i++) { line(BoardLeft+i*CellSize, BoardTop, BoardLeft+i*CellSize, BoardTop+ BoardHeight*CellSize); } for(i=0;i<=BoardHeight;i++) { line(BoardLeft, BoardTop+i*CellSize, BoardLeft+BoardWidth*CellSize, BoardTop+ i*CellSize); } /* draw board outer border rect */ rectangle(BoardLeft-CellSize/4, BoardTop-CellSize/4, BoardLeft+BoardWidth*CellSize+CellSize/4, 15 BoardTop+BoardHeight*CellSize+CellSize/4); /* draw next block grids */ for(i=0;i<=4;i++) { line(NBBoardLeft+i*NBCellSize, NBBoardTop, NBBoardLeft+i*NBCellSize, NBBoardTop+4*NBCellSize); line(NBBoardLeft, NBBoardTop+i*NBCellSize, NBBoardLeft+4*NBCellSize, NBBoardTop+ i*NBCellSize); } /* draw score rect */ rectangle(ScoreBoardLeft,ScoreBoardTop,ScoreBoardLeft+ScoreBoardWidth,ScoreBoardTop+ScoreBoardHeight); DisplayScore(); /* set new seed! */ gettime(&sysTime); srand(sysTime.ti_hour*3600+sysTime.ti_min*60+sysTime.ti_sec); GenerateBlock(&nextBlock); NextBlock(); /* create first block */ setcolor(DARKGRAY); outtextxy(InfoLeft,InfoTop+20,\"Up -rotate Space-drop\"); outtextxy(InfoLeft,InfoTop+35,\"Left-left Right-right\"); outtextxy(InfoLeft,InfoTop+50,\"Esc -exit\"); DisplayInfo(info_help); } /* set the isFilled and fillcolor data to the board */ void _INNER_HELPER FillBoardData() { int i,j; for(i=0;i Board[curBlock.x+i][curBlock.y+j][0]=1; Board[curBlock.x+i][curBlock.y+j][1]=curBlock.color; } } 16 } } /* draw one line of the board */ void _INNER_HELPER PaintBoard() { int i,j,fillcolor; for(j=max((TopLine-4),0);j floodfill(BoardLeft+i*CellSize+CellSize/2,BoardTop+j*CellSize+CellSize/2,BorderColor); } } } /* check if one line if filled full and increase the totalScore! */ void _INNER_HELPER CheckBoard() { int i,j,k,score=10,sum=0,topy,lines=0; /* we find the top empty line! */ j=topy=BoardHeight-1; do { sum=0; for(i=0;i< BoardWidth; i++) { sum+=Board[i][topy][0]; } topy--; } while(sum>0 && topy>0); /* remove the full filled line (max remove lines count = 4) */ do { sum=0; for(i=0;i< BoardWidth; i++) sum+=Board[i][j][0]; if(sum==BoardWidth)/* we find this line is full filled, remove 17 it! */ { /* move the cells data down one line */ for(k=j; k > topy;k--) { for(i=0;i /*make the top line empty! */ for(i=0;i topy++; /* move the topline downward one line! */ lines++; /* lines <=4 */ TotalScore+=score; score*=2; /* adding: 10, 30, 70, 150 */ } else j--; } while(sum>0 && j>topy && lines<4); /* speed up the game when score is high, minimum is 400 */ FrameTime=max(1200-100*(TotalScore/200), 400); TopLine=topy;/* update the top line */ /* if no lines remove, only add 1: */ if(lines==0) TotalScore++; } /* display the score */ void _INNER_HELPER DisplayScore() { setcolor(BkGndColor); outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score); setcolor(ScoreColor); sprintf(info_score,\"Score: %d\ outtextxy(ScoreBoardLeft+5,ScoreBoardTop+5,info_score); } /* we call this function when a block is inactive. */ 18 void UpdateBoard() { FillBoardData(); CheckBoard(); PaintBoard(); DisplayScore(); } /* pause the game, and timer handler stop move down the block! */ int PauseGame() { int key=0; DisplayInfo(\"Press P to Start or Resume!\"); while(key!=K_P && key!=K_ESC) { while(!(key=GetKeyCode())){} } DisplayInfo(info_help); return key; } /* quit the game and do cleaning work. */ void QuitGame() { closegraph(); } /* the entry point function. */ void main() { int i,flag=1,j,key=0,tick=0; InitGame(); if(PauseGame()==K_ESC) goto GameOver; /* wait until a key pressed */ while(key!=K_ESC) { /* wait until a key pressed */ while(!(key=GetKeyCode())) { tick++; if(tick>=FrameTime) { /* our block has dead! (can't move down), we get next 19 block */ if(!MoveBlock(&curBlock,0,1)) { UpdateBoard(); NextBlock(); if(!CanMove(0,1)) goto GameOver; } tick=0; } delay(100); } switch(key) { case K_LEFT: MoveBlock(&curBlock,-1,0); break; case K_RIGHT: MoveBlock(&curBlock,1,0); break; case K_DOWN: MoveBlock(&curBlock,0,1); break; case K_UP: RotateBlock(&curBlock); break; case K_SPACE: DropBlock(&curBlock); break; case K_P: PauseGame(); break; } } GameOver: DisplayInfo(\"GAME OVER! Press any key to exit!\"); getch(); /* wait the user Press any key. */ QuitGame(); } 20 测试计划 1.1 测试方案 本游戏的测试方法采用检查各个功能能否实现的方法 1.2测试项目及功能 控制区 开始:实现游戏的开始 暂停:实现游戏暂停 继续:实现游戏继续 提高级数:提高级数增加游戏的难度 降低级数:降低级数减小游戏的难度 菜单区 新游戏:游戏结束从新开始新一轮的游戏 提高级数:提高游戏难度 降低级数:减小游戏难度 退出:退出游戏 21 开始:开始游戏 暂停:暂停正在进行的游戏 从新开始:重新开始游戏 停止:停止正在进行的游戏 帮助信息: 游戏控制键 显示区:显示俄罗斯方块 提前显示窗口:显示下一个方块的样式 测试进度:本游戏在我和同组李帅同学的辛苦努力下用了半天的时间完成了 1.3测试准备 编写相应的驱动模块,并精心设计测试用例 1.4 测试机构 测试人员: 王新勃 职责:找出程序中的错误,实现游戏的功能 1.5 测试项目说明 测试1:名称:控制区功能测试 目的:测试控制区各个功能的按钮。 内容: 包括游戏开始,暂停,继续,停止,提高级数,降低级数的功 能 步骤:打开游戏窗口,按下开始按钮,看游戏区是否有方块下落,若有 则在按暂停按钮看其是否暂停,若暂停,则按继续看其是否继续下落。按停止按钮方块观察方块是否停止不动,按提高级数,降低级数看显示区级数是否在变化,并观察游戏中方块的下落书读是否变化,按提高级数按钮,方块的下落速度应加快;按降低级数按钮,方块的速度应减慢。 测试2:名称:菜单区功能测试 目的:测试菜单区各个子菜单的功能 22 内容:游戏菜单下的子菜单:新游戏,提高级数,降低级数,退出 按钮的功能实现,控制菜单下的子菜单:开始,暂停,重新开始,停止的功能实现。 步骤:打开游戏窗口,按下控制菜单下的开始按钮,看游戏区是否有方块下落, 预显区是否显示下一个方块的样式。在按测试控制区的功能一样分别测试各个子菜单的功能。 测试3:名称:显示区功能测试 目的:测试玩家操作的功能 内容:实现方块的左右移动,快速下落,翻转变化,满行消除,游戏 升级等。 测试步骤:打开游戏窗口,按开始按钮,接着测试J,K,L,I能否实现 方块的左右移动,翻转变化,快速下落。当堆满一行看其能否消除满行,消除后得分栏是否加分。当累积分超过2000分时看其是否升级。 1.6评介 一,范围 此测试计划说明书中的测试用例能基本上包括所有的情况,基本上 能反映此软件是否存在错误。其局限性是用例比较多,比较花时间。 二,准则 以能发现错误为准则 三,目标 以实现游戏功能为目标 改进意见 系统中还存在一些不足之处,可以对本系统做如下修改: 1.做进一步地功能扩展和研究,如添加音效等 2. 设计玩家进入游戏的见面 3.对软件进行进一步更详细的测试,以保证软件的可用性和适应性。 4.利用internet 进行用户意见的收集,以加强对软件的及时更新。 《C课程设计》心得体会 C是一种面向过程的编程语言,具有可移植性高,安全,可靠等优点,最初设计时就是本着一次编写到处执行设计的。可以开发各种应用程序和游戏,不 23 过速度没有c++快,所以一般是不用C来编写应用程序和电脑游戏。 经过一学期的C课程设计学习,使我对C有了深入的了解,让我知道了C是如何使用,如何来开发系统等等。 C的功能比较完善,这使我很有兴趣来学习C,在学习中虽然有很多地方不理解,刚开始时觉得很乱,总是找不到头绪,让自己不知所措, 而且在学习中遇到了不少的麻烦,上课的时候总是有一些问题使自己跟不上老师所讲的的课程,这样使自己少学了不少的知识,还好学校安排了课程设计这门课,在这个时候我算是又重新学了C程序设计。在这次课程设计的过程中有很多的地方不会,但通过问老师问同学、和查阅书籍来完成的了。虽然自己遇到了少的困难,但是我很认真的学习,来对待自己。 刚开始和同学合作开发这个俄罗斯方块作品的时候,存在不少分歧,虽然我们是参照参考书籍来做的,但还是有许多地方不合逻辑,最后通过我们不懈的努力,多次的研究,一一攻破,解决每一个问题,使我们的作品更加的完善。在开发作品的时候,游戏整体遇到了许多的麻烦,但是通过老师的辅导和同学的帮助使作品逐步完成 。通过这次课程设计让自己更加了解一下自己,充分的感觉到自身的不足,还有待进一步的学习。在这其中我还学习到了团队的精神,使我懂得了一个团队的重要性。一个人的力量终归没有一个团队的力量大。 C的功能是比较强大的,在和同学合作开发系统的时候还吃了不少的苦头,因为有很多地方我们还是不懂的,需要去学习,去向别人请教。 本次的系统开发是模拟软件开发过程来实施的。在这其中使我们学习到了软件开发所需要的知识,同时让我们更加了解了现在社会上软件行业所需要的知识, 我们在学校里所学的知识远远是不够的,我们要充分利用我们的课余时间来深入学习专业知识。 参考书籍,资料 1,《C课程设计》黄明 梁旭 周绍斌编著,电子工业出版社出版。 2,《C课程设计案例精编》黄晓东编著,中国水利水电出版社出版 3,《C程序设计实用教程》张永常主编,电子工业出版社出版 24 因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igat.cn 版权所有 赣ICP备2024042791号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务