c语言俄罗斯方块Word文档格式.docx
《c语言俄罗斯方块Word文档格式.docx》由会员分享,可在线阅读,更多相关《c语言俄罗斯方块Word文档格式.docx(29页珍藏版)》请在冰豆网上搜索。
指导教师评语及成绩
成绩:
指导教师签字:
2011年12月22日
第1章课程设计的目的与要求
1.1课程设计目的
本课程设计是计算机科学与技术专业重要的实践性环节之一,是在学生学习完《程序设计语言(C)》课程后进行的一次全面的综合练习。
本课程设计的目的和任务:
1.巩固和加深学生对C语言课程的基本知识的理解和掌握
2.掌握C语言编程和程序调试的基本技能
3.利用C语言进行基本的软件设计
4.掌握书写程序设计说明文档的能力
5.提高运用C语言解决实际问题的能力
1.2课程设计的实验环境
硬件要求能运行Windows2000/XP操作系统的微机系统。
C语言程序设计及相应的开发环境。
1.3课程设计的预备知识
熟悉C语言及C语言开发工具。
1.4课程设计要求
1.分析课程设计题目的要求
2.写出详细设计说明
3.编写程序代码,调试程序使其能正确运行
4.设计完成的软件要便于操作和使用
5.设计完成后提交课程设计报告
第2章课程设计内容
2.1程序功能介绍
俄罗斯方块游戏功能描述图
(1)游戏方块预览功能。
在游戏过程中,当在游戏底板中出现一个游戏方块时,必须在游戏方块预览区域中出现下一个游戏方块,这样有利于游戏玩家控制游戏的策略。
由于在此游戏中存在19种不同的游戏方块,所以在游戏方块预览区域中需要显示随机生成的游戏方块。
(2)游戏方块控制功能。
通过各种条件的判断,实现对游戏方块的左移、右移、快速下移、自由下落、旋转功能,以及行满消除行的功能。
(3)游戏显示更新功能。
当游戏方块左右移动、下落、旋转时,要清除先前的游戏方块,用新坐标重绘游戏方块。
当消除满行时,要重绘游戏底板的当前状态。
(4)游戏速度分数更新功能。
在游戏玩家进行游戏过程中,需要按照一定的游戏规则给玩家计算游戏分数。
比如,消除一行加10分。
当游戏分数达到一定数量之后,需要给游戏者进行等级的上升,每上升一个等级,游戏方块的下落速度将加快,游戏的难度将增加。
(5)游戏帮助功能。
玩家进入游戏后,将有对本游戏如何操作的友情提示。
2.2程序整体设计说明
2.2.1设计思路
新游戏方块将在如图3.2所示的4×
4的正方形小方块中预览。
使用随机函数rand()来产生1~19之间的游戏方块编号,并作为预览的方块编号。
其中的正方形小方块的大小为BSIZE×
BSIZE。
BSIZE为设定的像素大小。
游戏方块预览图
2.2.2数据结构设计及用法说明
游戏底板BOARD结构体
StructBOARD
{
Intvar;
Intcolor;
}Table_board[Vertical_boxs][Horizontal_boxs];
BOARD结构体表示游戏底板中每个小方块所具有的属性。
其中var表示小方块当前状态,只有0与1两个值,表示此小方块已被占用,0表示未被占用。
Color表示小方块的颜色,游戏底板的每个小方块可以拥有不同的颜色,以增强美观。
Vertical_boxs为游戏底板上垂直的方向上小方块的个数,Horizontal_boxs为游戏底板上水平的方向上小方块的个数。
游戏方块SHAPE结构体
structSHAPE
charbox[2];
intcolor;
/*每个方块的颜色*/
intnext;
/*下个方块的编号*/
};
SHAPE结构体表示某个游戏方块具有的属性。
其中,charbox[2]表示用2个字节来表示这个游戏方块的形状。
每4位来表示一个游戏方块的一行。
Color表示每个游戏方块的颜色,颜色可设为BLACK、BLUE、GREEN、CYAN、RE、MAGENTA、BROWN、LIGHTGRAY、DARKGRAY、LIGHTBLUE、LIGHTCYAN、LIGHTRED、LIGHTMAGENTA、YELLOW和WHITE。
next表示下个游戏方块的编号,在旋转时需要用到此编号。
如box[0]="
0x88"
box[1]="
0xc0"
其中0x88和0xc0为十六进制表示形式,具体表现的含义如图3.3所示。
SHAPE结构示意图
2.2.3程序结构(流程图)
2.2.4各模块的功能及程序说明
左移的实现过程如下:
(1)判断在当前的游戏底板中能否左移。
这一判断必须满足如下两条件:
游戏方块整体左移一位后,游戏方块不能超越游戏底板的左边线,否则越界;
并且在游戏方块有值(值为1)的位置,游戏底板必须是没有被占用的(占用时,值为1)。
若满足这两个条件,则执行下面的左移动作。
否则不执行左移动作。
(2)清除左移前的游戏方块。
(3)在左移一位的位置,重新显示此游戏方块。
右移的实现过程如下:
(1)判断在当前游戏底板中能否右移。
这一判断必须满足如下两个条件:
游戏方块整体右移一位后,游戏方块不能超越游戏底板的右边线,否则越界;
若满足这两个条件,则执行下面的右移动作。
否则不只执行右移动作。
(2)清除右移前的游戏方块。
(3)在右移一位的位置,重新显示此游戏方块。
下移的实现过程如下:
(1)判断在当前游戏底板中能否下移。
游戏方块整体下移一位后,游戏方块不能超越游戏底板的底边线,否则越界;
若满足这两个条件,则执行下面的下移动作。
否则,将flag_newbox标志置1,主循环中会判断此标志,若为1,则会生成下一个游戏方块,并更新预览游戏方块。
(2)清除下移前的游戏方块。
(3)在下移一位的位置,重新显示此游戏方块。
旋转的实现过程如下:
(1)判断在当前游戏底板中能否旋转。
这一判断必须满足如下条件:
游戏方块整旋转后,游戏方块不能超越游戏底板的左边线、右边线和底边线,否则越界;
若满足这些条件,则执行下面的旋转动作。
否则不只执行旋转动作。
(2)清除旋转前的游戏方块。
(3)在游戏方块显示区域(4×
4)不变的位置,利用保存当前游戏方块的数据结构中的next值作为旋转后形成的新游戏方块的编号,并重新显示这个编号的游戏方块。
当生成新的游戏方块前,执行行满的检查,判断行满的过程为:
一次从下到上扫描游戏底板中的各行,若某行中1的个数等于游戏底板水平方向上的小方块的个数,则表示此行是满的。
找到满行后,立即将游戏底板中的数据往下顺移一行,直到游戏底板逐行扫描完毕。
2.2.5程序结果
当用户刚进入游戏时,如图4.2所示。
此时,分数初始化为0,等级默认为1。
游戏当前设置为成绩每增加30分等级就升一级,升级后游戏方块在原来基础上下落速度有所加快,这主要是变化了定时器的时间间隔的缘故。
用户可使用键盘左移键、右移键、上移键和下移键,分别进行左移、右移、旋转和下落操作。
用户可按ESC键退出游戏。
游戏初始状态
下图为游戏等级提升了一级后的状态,级别越高,游戏方块下落速度越快。
图4.3游戏进行状态
2.3程序源代码及注释
/*加载头文件*/
#include<
stdio.h>
stdlib.h>
dos.h>
graphics.h>
/*图形函数库*/
/*定义按键码*/
#defineVK_LEFT0x4b00
#defineVK_RIGHT0x4d00
#defineVK_DOWN0x5000
#defineVK_UP0x4800
#defineVK_ESC0x011b
#defineTIMER0x1c/*设置中断号*/
/*定义常量*/
#defineMAX_BOX19/*总共有19种各形态的方块*/
#defineBSIZE20/*方块的边长是20个象素*/
#defineSys_x160/*显示方块界面的左上角x座标*/
#defineSys_y25/*显示方块界面的左上角y座标*/
#defineHorizontal_boxs10/*水平的方向以方块为单位的长度*/
#defineVertical_boxs15/*垂直的方向以方块为单位的长度*/
#defineBegin_boxs_xHorizontal_boxs/2/*产生第一个方块时出现的起始位置*/
#defineFgColor3/*前景颜色,如文字.2-green*/
#defineBgColor0/*背景颜色.0-blac*/
#defineLeftWin_xSys_x+Horizontal_boxs*BSIZE+46/*右边状态栏的x座标*/
#definefalse0
#definetrue1
/*移动的方向*/
#defineMoveLeft1
#defineMoveRight2
#defineMoveDown3
#defineMoveRoll4
/*以后坐标的每个方块可以看作是像素点是BSIZE*BSIZE的正方形*/
/*定义全局变量*/
intcurrent_box_numb;
/*保存当前方块编号*/
intCurbox_x=Sys_x+Begin_boxs_x*BSIZE,Curbox_y=Sys_y;
/*x,y是保存方块的当前坐标的*/
intflag_newbox=false;
/*是否要产生新方块的标记0*/
intspeed=0;
/*下落速度*/
intscore=0;
/*总分*/
intspeed_step=30;
/*每等级所需要分数*/
voidinterrupt(*oldtimer)(void);
/*指向原来时钟中断处理过程入口的中断处理函数指针*/
structBOARD/*游戏底板结构,表示每个点所具有的属性*/
{
intvar;
/*当前状态只有0和1,1表示此点已被占用*/
/*颜色,游戏底板的每个点可以拥有不同的颜色.增强美观*/
}Table_board[Vertical_boxs][Horizontal_boxs];
/*方块结构*/
structSHAPE
/*一个字节等于8位,每4位来表示一个方块的一行
如:
box[0]="
表示的是:
1000
1100
0000*/
};
/*初始化方块内容.即定义MAX_BOX个SHAPE类型的结构数组,并初始化*/
structSHAPEshapes[MAX_BOX]=
/*
*口口口口口口口
*口口口口口口
*口口口
*/
{0x88,0xc0,CYAN,1},
{0xe8,0x0,CYAN,2},
{0xc4,0x40,CYAN,3},
{0x2e,0x0,CYAN,0},
*口口口口口口
*口口口口
*口口口口口口
{0x44,0xc0,MAGENTA,5},
{0x8e,0x0,MAGENTA,6},
{0xc8,0x80,MAGENTA,7},
{0xe2,0x0,MAGENTA,4},
*口
*口口口口
*口口口
{0x8c,0x40,YELLOW,9},
{0x6c,0x0,YELLOW,8},
{0x4c,0x80,BROWN,11},
{0xc6,0x0,BROWN,10},
*口口口
*口口口口口口口口口口
{0x4e,0x0,WHITE,13},
{0x8c,0x80,WHITE,14},
{0xe4,0x0,WHITE,15},
{0x4c,0x40,WHITE,12},
/*口
*口口口口口
{0x88,0x88,RED,17},
{0xf0,0x0,RED,16},
*口口
{0xcc,0x0,BLUE,18}
unsignedintTimerCounter=0;
/*定时计数器变量*/
voidmain()
intGameOver=0;
intkey,nextbox;
intCurrentaction=0;
/*标记当前动作状态*/
intgd=VGA,gm=VGAHI,errorcode;
initgraph(&
gd,&
gm,"
"
);
errorcode=graphresult();
if(errorcode!
=grOk)
printf("
\nNotice:
Graphicserror:
%s\n"
grapherrormsg(errorcode));
Pressanykeytoquit!
getch();
exit
(1);
}
setbkcolor(BgColor);
setcolor(FgColor);
randomize();
SetTimer(newtimer);
initialize(Sys_x,Sys_y,Horizontal_boxs,Vertical_boxs);
/*初始化*/
nextbox=MkNextBox(-1);
show_box(Curbox_x,Curbox_y,current_box_numb,shapes[current_box_numb].color);
show_box(LeftWin_x,Curbox_y+200,nextbox,shapes[nextbox].color);
show_intro(Sys_x,Curbox_y+320);
while
(1)
/*Currentaction=0;
flag_newbox=false;
检测是否有按键*/
if(bioskey
(1)){key=bioskey(0);
else{key=0;
switch(key)
caseVK_LEFT:
if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveLeft))
{EraseBox(Curbox_x,Curbox_y,current_box_numb);
Curbox_x-=BSIZE;
Currentaction=MoveLeft;
}
break;
caseVK_RIGHT:
if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveRight))
Curbox_x+=BSIZE;
Currentaction=MoveRight;
caseVK_DOWN:
if(MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown))
Curbox_y+=BSIZE;
Currentaction=MoveDown;
elseflag_newbox=true;
caseVK_UP:
/*旋转方块*/
if(MoveAble(Curbox_x,Curbox_y,shapes[current_box_numb].next,MoveRoll))
current_box_numb=shapes[current_box_numb].next;
Currentaction=MoveRoll;
caseVK_ESC:
GameOver=1;
default:
if(Currentaction)
{/*表示当前有动作,移动或转动*/
Currentaction=0;
/*按了往下键,但不能下移,就产生新方块*/
if(flag_newbox)
/*这时相当于方块到底部了,把其中出现点满一行的清去,置0*/
ErasePreBox(LeftWin_x,Sys_y+200,nextbox);
nextbox=MkNextBox(nextbox);
if(!
MoveAble(Curbox_x,Curbox_y,current_box_numb,MoveDown))/*刚一开始,游戏结束*/
else
else/*自由下落*/
if(Currentaction==MoveDown||TimerCounter>
(20-speed*2))
EraseBox(Curbox_x,Curbox_y,current_box_numb);
TimerCounter=0;
if(GameOver)/*||flag_newbox==-1*/
gameover,thankyou!
yourscoreis%d"
score);
KillTimer();
closegraph();
voidinitialize(intx,inty,intm,intn)
inti,j,oldx;
oldx=x;
for(j=0;
j<
n;
j++)
for(i=0;
i<
m;
i++)
Table_board[j][i].var=0;
Table_board[j][i].color=BgColor;
line(x,y,x+BSIZE,y);
line(x,y,x,y+BSIZE);
line(x,y+BSIZE,x+BSIZE,y+BSIZE);
line(x+BSIZE,y,x+BSIZE,y+BSIZE);
x+=BSIZE;
y+=BSIZE;
x=oldx;
Curbox_x=x;
Curbox_y=y;
/*x,y是保存方块的当前坐标的*/
speed=0;
score=0;
ShowScore(score);
ShowSpeed(speed);
voidinterruptnewtimer(void)
(*oldtimer)();
/*calltheoldroutine*/
TimerCounter++;
/*increasetheglobalcounter*/
/*设置新的时钟中断处理过程*/
voidSetTimer(voidinterrupt(*IntProc)(void))
oldtimer=getvect(TIMER);
/*获取中断号为TIMER的中断处理函数的入口地址*/
disable();
/*设置新的时钟中断处理过程时,禁止所有中断*/
setvect(TIMER,IntProc);
/*将中断号为TIMER的中断处理函数的入口地址改为IntProc()函数的入口地址
即中断发生时,将调用IntProc()函数。
*/
enable();
/*开启中断*/
/*恢复原有的时钟中断处理过程*/
voidKillTimer()
setvect(TIMER,oldtimer);
voidShowScore(intscore)
intx,y;
charscore_str[5];
/*保存游戏得分*/
setfillstyle(SOLID_FILL,BgCo