本游戏软件的初始要求是这样定义的: 用 Turbo-C 语言在DOS环境下设计实现一个模拟WINDOWS环境下同色相溶游戏的程序。
需求:
关于界面 1.在图形模式下建立一个图形化菜单,可用上、下箭头移动光标,按回车键则执行菜单功能。 菜单选项:进入游戏、查看最高分、显示游戏规则、退出等。 选择退出是结束执行的唯一方式。 2.选择“进入游戏”后,进入一个图形画面,画面分为A、B两个区域:区域A划分为m*n个小区域,每一小区域随机地填充k中颜色中的一种,B区域用于显示操作过程的积分,时钟(可选)。 3.选择“查看最高分”后,读取保存最高分的文件,显示最高的10次得分(此文件可清空)。 4.选择“查看游戏规则 ”后,显示游戏规则文件的内容。
关于操作 1.生成初始画面,图形显示光标. 2.用→、←、↑等键移动光标选择一个小区域,要求用颜色标明光标位置,按Enter键确定后,寻找与此区域同色且相连(上、下、左、右)的所有小区域,删除所有选出的小区域(删除前闪烁),若删除后某列为空,则后序各列均左移,使画面连通。 3.根据此次选择的小区域的个数n,将本次操作的得分n*(n-1)加入积分中,并显示。重复执行操作2,3,直至A区为空或每一个小区域的上、下、左、右四个位置均无同色区域。 4.若此次积分高于最高分文件中的某条记录,或文件的记录不足10个,则将它记入最高分文件。
扩展要求 1.显示时钟,游戏计时; 2.A区的大小,区域填色的颜色数可变; 3.根据游戏的初始值, 给出合理的奖励分; 4.画面设计美观,合理, 方便。
实现功能及程序亮点: 实现了全部的基本要求和扩展要求,还实现了一个图形的石英钟表,并且设计了一个菜蛋—即可以通过输入秘技来使用其它的主题。 本游戏使用SVGA256色640*480显示模式,支持中英数混合输出,使用大量的256色BMP贴图,通过修改色彩寄存器实现。淡入淡出效果。
参考书目:本年级C语言教科书 模块划分
 |
模块接口设计:
函数名称 |
函数原型 |
功能 |
传入参数 |
返回值 |
显示菜单函数 |
Void fnDrawMenu(void) |
显示菜单 |
无 |
无 |
菜单控制函数 |
int fnMenu(void) |
控制菜单 |
无 |
int |
游戏设置函数 |
Void fnSetting(void) |
设置游戏的各项参数 |
无 |
无 |
生成新数组函数 |
Void fnIndex_New(void) |
生成新的游戏数组 |
无 |
无 |
算法核心函数 |
Int fnKernel(void) |
算法的核心,判断哪些色块应被消去 |
无 |
int |
算分函数 |
Void fnScore(int ) |
计算游戏得分 |
int m(消去的色块数) |
无 |
算法数组清空函数 |
Void fnCleanUP(void) |
清空游戏数组中的临时数 |
无 |
无 |
游戏结束函数 |
Int fnGameOver(void) |
判断游戏是否结束 |
无 |
int (返回1为游戏结束) |
算法数组刷函数 |
int fnShua(int ,const int ,const int ) |
刷游戏数组 |
无 |
无 |
游戏控制函数 |
int fnGame_Key(void) |
控制游戏,包括游戏时的按键判断 |
无 |
int |
画游戏色块函数 |
void fnHua(void) |
画游戏区的游戏色块 |
无 |
无 |
高手榜函数 |
void fnHigh(const int ,const long) |
生成,控制,显示高手榜 |
Const int c_nYouMark(游戏得分) const long youtime(游戏历时) |
无 |
显示BMP函数 |
void fnDisplayBmp(int nBMP_X,int nBMP_Y,FILE *fp) |
显示256色BMP |
int nBMP_X,int nBMP_Y(图片左上角的X和Y坐标) FILE *fp (BMP文件的指针) |
无 |
SVGA换页模式 |
void selectpage(register char) |
SVGA换页 |
register char page(要换到的页号) |
无 |
设置SVGA屏幕模式 |
Unsigned char set_SVGA(int) |
无条件硬件初始化SVGA模式 |
int Vmode(模式的子功能号) |
unsigned char |
获取当前SVGA屏幕模式 |
unsigned int get_mode(void) |
获取当前SVGA屏幕模式 |
无 |
unsigned char |
关闭SVGA模式函数 |
unsigned char close_SVGA(void) |
关闭SVGA色模式函数 |
无 |
unsigned char |
获取调色盘函数 |
void fnGet_Palette(FILE *) |
获取BMP文件中的调色盘 |
FILE *fp(指向BMP文件的指针,如果为NULL就读取默认调色盘) |
无 |
画点函数 |
void point(int ,int ,unsigned char ,unsigned char ) |
画点 |
传入参数:int x,int y(点的X和Y坐标) unsigned char color (颜色),unsigned char mode(贴图模式) |
无 |
画线函数 |
void fdyline(int ,int , int ,int, unsigned char , unsigned char ) |
画线 |
int x1,int y1(起始点X和Y坐标),int x2,int y2(终点X和Y坐标) unsigned char color(颜色),unsigned char mode(贴图模式) |
无 |
画实心矩形函数 |
void fdybar(int ,int ,int , int ,int ,unsigned char ) |
画实心矩形 |
int x1,int y1(左顶点X和Y坐标),int x2,int y2(右顶点X和Y坐标) int color(颜色),unsigned char mode(贴图模式) |
无 |
画圆函数 |
void fdycircle(int ,int ,int ,unsigned char ,unsigned char ) |
画圆 |
int centrex,int centrey(圆心的X和Y坐标),int r(半径) unsigned char color(颜色),unsigned char mode(贴图模式) |
无 |
存位图函数 |
void fnGetBmp(int ) |
将BMP以位图形式存入远堆 |
int nIndexNum(位图的索引号) |
无 |
画位图函数(1) |
void fnPutImg(int ,int ,int ) |
将存入的位图画出来 |
int nBitM_X,int nBitM_Y(图片左上角的X和Y坐标) int nIndexNum(位图的索引号) |
无 |
画位图函数(2) |
void fnPutBmp(int nBitM_X,int nBitM_Y,int nIndexNum,unsigned char mode) |
将存入的位图画出来 |
int nBitM_X,int nBitM_Y(图片左上角的X和Y坐标) int nIndexNum(位图的索引号) unsigned char mode(贴图的模式) |
|
获得ROM字符集首址函数 |
Char far* get_ascii_rom(unsigned int ) |
获得ROM字符集首址 |
unsigned int reg_bx(将寄存器BX置的值) |
char far* (返回8*16 ASCII字符ROM指针) |
中英数混合输出函数 |
void textoutxy(int ,int , unsigned char *,unsigned char ,unsigned char ) |
图形模式下的中英数混合输出 |
无 |
无 |
画表函数 |
void fnWatch(void) |
画表 |
无 |
无 |
画表针函数 |
void fnWatchHand(int ,int , int ,unsigned char ) |
画表针 |
int nLong(表针长) int nTime(时间位置) int nWalk(每一动走的度数) unsigned char color(针的颜色) |
无 |
游戏历时函数 |
void fnClock(void) |
显示游戏历时 |
无 |
无 |
显示片头画面函数 |
void fnOP(void) |
显示片头画面 |
无 |
无 |
DAC置黑函数 |
void fnBlack(void) |
将DAC(色彩寄存器)置黑 |
无 |
无 |
淡出函数 |
void fnFadeOut(void) |
淡出 |
无 |
无 |
淡入函数 |
void fnFadeIn(void) |
淡入 |
无 |
无 |
显示帮助函数 |
void fnShowHelp(void) |
显示帮助 |
无 |
无 |
退出函数 |
void quit(void) |
退出后的处理 |
无 |
无 |
闪烁函数 |
void fnFlash(void) |
游戏色块消除闪烁 |
无 |
无 |
闪烁数组清空函数 |
void fnFlashClear(void) |
闪烁数组清空 |
无 |
无 |
内存释放函数 |
void fnFree(void) |
释放内存 |
无 |
无 | 核心模块流程图: /*==============主函数====================*/ /*功能:主函数 */ /*传入参数:无 */ /*返回值:无 */ /*========================================*/

|
使用说明: 可在菜单与游戏区之间切换,在菜单区用上下选项,确认。在游戏区用上、下、左、右键移动光标选择一小区块,确认后,与此区域同样图标且相连(上、下、左、右)的所有小区域将被消除,
并得分数:
消除区域 X(消除区域-1)
1.若没有相连小区域,则此区域不被消除 2.若有区域消除,则其上方的小区域下落填补其位,若整列均被消除,则右方各列向左移动填补其位 3.游戏得分与结束游戏后所剩方块数无关,完全消除方块无奖励分 4.游戏时间与游戏得分无关,也不使游戏得分作废,只是在排名时如果得分相同用时短的排名更高 5.中途重新开始或退出游戏其本局得分无效 在游戏开始时或者在游戏中都可看见此帮助
总结: 第一次作课程设计,对作品不是很满意。但这却是我在完全独立的环境下制作的作品。其中饱含着我的热情和心血。 在这次的制作过程中,既有艰辛,又有欢乐。艰辛是在制作过程中所遇到的层层困难;而欢乐则来自于每次解决困难后的喜悦。
在非典长假之前,我便开始着手准备制作课设了。先是对所作课设的题目进行了深刻的分析,并看了FreeBSD下的SameGame游戏。所以到了非典长假刚开始,我已经对我所要做的课设有了一个大致的构思。
但到了真正要开始做的时候,又有一个个困难出现了,本来我想做VGA16色的模式,后来使用BMP贴图后就觉得颜色明显不够了。查了SVGA的相关资料(全是英文的),后来决定用SVGA256色640*480模式。
从一个难题一个难题的解决,到一个页面一个页面的设计制作,那种过程的确是一种考验,但更是一种享受。在这过程我发现了自己在知识掌握中很多的不足,像上面提到的几点。在众多困难中最为困扰我的是内存的问题,近堆的64K早就不够用了,远堆也渐渐不够了,本来想用EMS的,不过后来因为太麻烦放弃了,最后只好部分太大的和使用频率不大的每次都从文件里调,大大影响了速度。我在这个问题上思考了很长时间,但却始终没有找就更好的解决方案了。我还会继续探索下去,以使这个游戏更为完善。
在设计游戏的过程中,有很多想法是好的,新颖的,但不是因为考虑不周,就是算法不精,要么没有实现,要么就是实现后效果不够理想。现在想起来深感遗憾。今后要熟练掌握C或其他语言的算法精髓。
这是一个独立完成的作业,我也得到了不少同学和朋友的帮助,其间更是因为自己思维的偏差而走了不少弯路,而自己其他各方面知识的困乏更是限制了自己的发挥。也给了我不少中肯的建议,比如我在一开始设计游戏计时的时候用的事中断1ch,不少朋友到和我说这样做很不妥,一开始我没有听,后来在这上面吃了亏,才放弃中断改用while(1)+kbhit()来实现单用户的得多线程,要是早听他们的也不至于走了那么多的弯路。这次的制作过程,我觉得更像是一次生活的体验。使我感受到了很多以前所没有感受到的生活哲理。我热爱计算机这个行业。今后有可能从事软件开发的工作,就算从事喜欢的计算机安全等其他计算机方面的事也离不开良好的编程能力。这需要庞大的知识内涵作为后盾。但不是所以东西都是老师教的。老师教的只是一种学习的方法,更多的知识是靠自己的努力自学而得来的。所以,提高自学能力,丰富实践经验,做到学用结合则是拓宽知识面,提高个人素养所必须的。
以上就是我对完成这次作业的颇多感受。这仅仅是一个开始。在今后的编程学习中,我将不断完善自己。为实现自己的梦想而不懈努力!
部分重要部分的源代码:
/*==============主函数====================*/ /*功能:主函数 */ /*传入参数:无 */ /*返回值:无 */ /*========================================*/
void fnHigh(const int c_nYouMark,const long youtime) { time_t t; int len,write=0; FILE *fp,*bkp; int i,j,k; char puthigh[100]; char ch[2],chs[16]=""; struct tm *gt; struct high p[12]; ch[1]='\0';
if ((gt=malloc(sizeof(struct tm)))==NULL) exit(0);
time(&t);
if ((fp=fopen("dat\\high","r"))==NULL) return;
for (i=0;i<=10;i++) { fread(&p[i],sizeof(struct high),1,fp); }
fclose(fp); Keyclear;
for (i=10;i>=0;i--) { if ((c_nYouMark>p[i].m_nMark&&c_nYouMarkp[i].m_nMark&&c_nYouMark==p[i-1].m_nMark)&&youtime>=p[i-1].m_lGameTime)) { write=1; for(j=11;j>i;j--) { p[j]=p[j-1]; } if ((bkp=fopen("img\\input.bmp","rb"))==NULL) {printf("NO!!!");exit(0);} fnDisplayBmp(100,100,bkp); fclose(bkp); ch[0]=1; while(ch[0]!=13) { while (1) { ch[0]=getch(); if (ch[0]!=13&&ch[0]!=8&&(ch[0]<33||ch[0]>126)) {if (ch[0]==0) getch();} else break; } if (8==ch[0]&&chs[0]!='\0') { len=strlen(chs); chs[len-1]='\0'; for (k=len;k<15;k++) chs[k]=' '; } else if (13==ch[0]); else if (14==strlen(chs)); else strcat(chs,ch); fdybar(135,280,300,300,0,0); textoutxy(135,280,chs,255,0); } sprintf(p[i].m_strName,chs); p[i].m_nMark=c_nYouMark; p[i].m_lGameTime=youtime; break; } else if ((c_nYouMark>p[i].m_nMark&&c_nYouMark==p[i-1].m_nMark)&&youtime { write=1; for(j=11;j>i-1;j--) { p[j]=p[j-1]; } if ((bkp=fopen("img\\input.bmp","rb"))==NULL) {printf("NO!!!");exit(0);} fnDisplayBmp(100,100,bkp); fclose(bkp); ch[0]=1; while(ch[0]!=13) { while (1) { ch[0]=getch(); if (ch[0]!=13&&ch[0]!=8&&(ch[0]<33||ch[0]>126)) {if (ch[0]==0) getch();} else break; } if (8==ch[0]&&chs[0]!='\0') { len=strlen(chs); chs[len-1]='\0'; for (k=len;k<15;k++) chs[k]=' '; } else if (13==ch[0]); else if (14==strlen(chs)); else strcat(chs,ch); fdybar(135,280,300,300,0,0); textoutxy(135,280,chs,255,0); } sprintf(p[i-1].m_strName,chs); p[i-1].m_nMark=c_nYouMark; p[i-1].m_lGameTime=youtime; break; } } if (1==write) { if ((fp=fopen("dat\\high","w"))==NULL) exit(0); fwrite(&p[0],sizeof(struct high),1,fp); for(i=1;i<=10;i++) { p[i].m_nNo=i; fwrite(&p[i],sizeof(struct high),1,fp); } fclose(fp); } if ((bkp=fopen("img\\bk.bmp","rb"))==NULL) {printf("NO!!!");exit(0);} fnGet_Palette(bkp); fnDisplayBmp(0,0,bkp); fclose(bkp); textoutxy(60,100,"NO. NAME MARK GAMETIME ",0,0); for (i=1;i<=10;i++) { gt=gmtime(&p[i].m_lGameTime); sprintf(puthigh,"%2d %16s %4d %02d:%02d ",p[i].m_nNo,p[i].m_strName,p[i].m_nMark,gt->tm_min,gt->tm_sec); textoutxy(60,i*20+100,puthigh,0,COPY_PUT); } textoutxy(130,380,"键清空高手榜 键退出",66,COPY_PUT); while(1) { k=bioskey(0); if (k==KEY_F6) { if ((bkp=fopen("img\\bk.bmp","rb"))==NULL) {printf("NO!!!");exit(0);} fnGet_Palette(bkp); fnDisplayBmp(0,0,bkp); fclose(bkp); textoutxy(130,380,"键清空高手榜 键退出",66,COPY_PUT); p[11].m_nNo=0; sprintf(p[11].m_strName,"NONAME"); p[11].m_nMark=0; p[11].m_lGameTime=0; if ((fp=fopen("dat\\high","w"))==NULL) {printf("NO!!!");exit(0);} p[0].m_nNo=0; sprintf(p[0].m_strName,"Slayers_fdy"); p[0].m_nMark=30000; p[0].m_lGameTime=0; fwrite(&p[0],sizeof(struct high),1,fp); textoutxy(60,100,"NO. NAME MARK GAMETIME ",0,0); for(i=1;i<=10;i++) { p[i]=p[11]; p[i].m_nNo=i; gt=gmtime(&p[i].m_lGameTime); sprintf(puthigh,"%2d %16s %4d %02d:%02d ",p[i].m_nNo,p[i].m_strName,p[i].m_nMark,gt->tm_min,gt->tm_sec); textoutxy(60,i*20+100,puthigh,0,0); fwrite(&p[i],sizeof(struct high),1,fp); } fclose(fp); } if (k==KEY_ESC) {return;} } }
|