资源描述
学号
10212816207
武汉华夏理工学院
课 程 设 计
课程名称 C语言课程设计
题 目 俄罗斯方块游戏的设计
课程设计任务书
设计题目:俄罗斯方块的设计
要求完成的主要任务:
1. 任务描述
俄罗斯方块是一款风靡全球的掌上游戏机和PC游戏,它造成的轰动与创造的经济价值可以说是游戏史上的一件大事。相信大多数用户都还记得为它痴迷得茶不思饭不想的那个俄罗斯方块时代。现在,要求你自己编程,使用自己亲手编写的俄罗斯方块游戏。
2. 本课程涉及的知识点
数组、结构体、绘图、时钟中断等,通过本程序的训练,进一步加深对C语言的了解,掌握游戏开发基本原理,为开发出高质量的游戏软件打下坚实基础。
3. 要求完成的任务
⑴ 完成整个规定任务的设计及调试,且一定要画出程序流程图,最后得出正确结果,并经教师检查及答辩;
⑵ 写出规范的课程设计说明书;
⑶ 课程设计结束后交设计说明书等文档和设计内容:
⑷ 从2月27日起,学生每天至少要到设计教室半天以上;
设计报告撰写格式要求:
设计报告的主要内容是详细写出在设计过程中所用到的主要技术或方法;
课程设计报告按国际通用格式书写,具体格式要求请见资料:“课程设计说明书的书写内容与格式”
时间安排:
第一天: 学生先在实验室集中,由指导教师介绍课程设计的目的、布置任务后选题;
第二天-第四天:学生在实验室完成设计,经教师检查并回答提问,确认设计完成;
第五天: 教师在计算机上先检查设计报告、学生修改后打印提交
指 导 教 师 签 字: 2017年2月 24日
系 主 任 签 字: 2017年2月 24日
目录
1.设计题目 2
2.开发环境 4
3.开发工具 4
4.完成时间 4
5.设计思想 4
6.设计过程及设计步骤 5
7.测试运行 7
8.评价与修订 10
8.1算法上的优点 10
8.2功能上的优点 10
8.3程序的缺点 10
9设计体会 11
10.参考文献 12
l 1 设计题目
n 俄罗斯方块设计
l 2 开发环境
n 硬件环境:微机系列,内存在1G以上,软件环境:Microsoft Windows XP
l 3 开发工具
n TC、Win-tc或者Visual C++6.0
l 4 完成时间
n 2017-2 –27----2017.3.3
l 5 设计思想
先设计出6大类19种状态变化的俄罗斯方块,制作游戏窗口,制作俄罗斯方块与状态判断图形是否可动,随机产生俄罗斯方块类型的序号打印俄罗斯方块清除俄罗斯方块的痕迹判断是否满行并删除满行的俄罗斯方块。
l 6 设计过程及设计步骤
■ 制定游戏的边框大小,与方块的中心落下位置,按照设计思想做出来,加上难度随下落个数每次增加下落速度,不懂的程序上网搜索(这也增强了对C++的了解)。
附图下一面(图1.1)
俄罗斯方块排序流程图(图1.1)
开始
结束
游戏继续继续产生随机方块
输出分数
分数加1
是
否
方块是否成行?
否
是
随着俄罗斯方块数量增加,下落速度增加
++
方块下落或者移动
是否遇见结束条件?
随机生成方块形状
程序源代码头文件
俄罗斯方块程序
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
做俄罗斯方块形状与变化用了数组(如下相应程序源代码为17种形状之一的Z字形)
case 8: //Z字方块
{
a[tetris->x][tetris->y+1]=b[1];
a[tetris->x-2][tetris->y]=b[2];
a[tetris->x+2][tetris->y+1]=b[3];
break;
}
case 9: //Z字顺时针转90度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x-2][tetris->y]=b[2];
a[tetris->x-2][tetris->y+1]=b[3];
break;
}
case 10: //Z字顺时针转180度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x-2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 11: //Z字顺时针转270度方块
{
a[tetris->x][tetris->y+1]=b[1];
a[tetris->x+2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;}
l 7 测试运行
n 附图1.2与1.3
程序游戏开始图(1.2) 程序运行图(1.3)
l 8 评价与修订
自己参考了很多先人最初做的程序,虽然许多东西不是很会,但大致看得懂,自己修改了别样的方块,但自己加不进去颜色,图中那个加颜色的程序命令不知道怎么运行不了,以后可以优化背景颜色与方块颜色。这个做出来比较卡顿,希望下次会更流畅一些。
l 9设计体会
总算把课程设计给完成了,这是一个坚苦而又漫长的过程,。是啊,读了那么多年的书,课程设计可是第一次。看着劳动成果,很欣慰!虽然这不是我一个人做的,是和另一个的共同努力得来的。
“这怎么可能完成的了!”4个天前我们这样说,现在我们可以说:“哈哈,完成啦”!
刚开始,可以说是没有头绪,于是就去图书馆找资料,找到了一些关于画图方面的,可是这点小进展远远不够,这只是一个小小的开始。下一步是上网查,找到了些与我们题目相似的,那时我们每个人都很高兴,可是那还不是我们要的,于是又上网查到了些有关的函数等等,终于在我们大家的努力下,完成了这个程序。
虽然对着电脑做程序,有点累有点热,可是当看到劳动成果时,真是别有一番滋味在心头啊!世上无难事,只怕有心人,的确如此。做完这个程序最大的收获就是感受到了集体的力量,当然个人的智慧也是很重要的哦!
尽管不是自己独立完成,但仍然很高兴,因为在设计的过程中,让我了解到要设计一个大型程序,查找资料是至关重要的,在他人的基础上,再根据自己所学进行修改与调试,最后设计出自己想要的程序,这过程艰辛,但只要你持之以恒,成功指日可待。
另外平时扎实的基础也很关键,因为如果你平时学得就不怎么样,那么你面对这么一个比较有难度的程序,你可能会望而却步,看他人的程序都是个难点,更别说让你自己去设计。为了解决此。
l 10 参考文献
(1)罗伟坚 《Visual C++经典游戏程序设计》
(2)刘长明 《Visual C++实践与提高—多媒体篇》
(3)王晓峰 《Visual C++实践与提高 ActiveX篇》
设计过程中现场提问(或答辩)记载:
问:这个俄罗斯方块程序运用了什么程序做出来的?
答:运用了数组、结构体、绘图、时钟等。
问:运行起来有什么毛病没?
答:有点卡顿,可能是我下落速度设定的有点过快,游戏进城过快导致卡顿。
问:如果再要你优化你的游戏你该怎么做?
答:运用system("pause");加上颜色,优化后游戏设定有选择难度选项界面,游戏修改相应部分更加流畅。
指导教师评语:
成绩评定等级:
指导教师(签名):
2017 年 3月 6 日
俄罗斯方块程序
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
//游戏窗口
#define FrameX 4 //游戏窗口左上角的X轴坐标
#define FrameY 4 //游戏窗口左上角的Y轴坐标
#define Frame_height 20 //游戏窗口的高度
#define Frame_width 18 //游戏窗口的宽度
//定义全局变量
int i,j,temp,temp1,temp2; //temp,temp1,temp2用于记住和转换方块变量的值
int a[80][80]={0}; //标记游戏屏幕的图案:2,1,0分别表示该位置为游戏边框、方块、无图案;初始化为无图案
int b[4]; //标记4个"口"方块:1表示有方块,0表示无方块
//声明俄罗斯方块的结构体
struct Tetris
{
int x; //中心方块的x轴坐标
int y; //中心方块的y轴坐标
int flag; //标记方块类型的序号
int next; //下一个俄罗斯方块类型的序号
int speed; //俄罗斯方块移动的速度
int count; //产生俄罗斯方块的个数
int score; //游戏的分数
int level; //游戏的等级
};
//函数原型声明
//光标移到指定位置
void gotoxy(HANDLE hOut, int x, int y);
//制作游戏窗口
void make_frame();
//随机产生方块类型的序号
void get_flag(struct Tetris *);
//制作俄罗斯方块
void make_tetris(struct Tetris *);
//打印俄罗斯方块
void print_tetris(HANDLE hOut,struct Tetris *);
//清除俄罗斯方块的痕迹
void clear_tetris(HANDLE hOut,struct Tetris *);
//判断是否能移动,返回值为1,能移动,否则,不动
int if_moveable(struct Tetris *);
//判断是否满行,并删除满行的俄罗斯方块
void del_full(HANDLE hOut,struct Tetris *);
//开始游戏
void start_game();
void main()
{
//制作游戏窗口
make_frame();
//开始游戏
start_game();
}
/******光标移到指定位置**************************************************************/
void gotoxy(HANDLE hOut, int x, int y)
{
COORD pos;
pos.X = x; //横坐标
pos.Y = y; //纵坐标
SetConsoleCursorPosition(hOut, pos);
}
/******制作游戏窗口******************************************************************/
void make_frame()
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量
gotoxy(hOut,FrameX+Frame_width-5,FrameY-2); //打印游戏名称
printf("俄罗斯方块");
gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+7); //打印选择菜单
printf("**********下一个方块:");
gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+13);
printf("**********");
gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+17);
printf("↑键:变体");
gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+19);
printf("空格:暂停游戏");
gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+15);
printf("Esc :退出游戏");
gotoxy(hOut,FrameX,FrameY); //打印框角并记住该处已有图案
printf("╔");
gotoxy(hOut,FrameX+2*Frame_width-2,FrameY);
printf("╗");
gotoxy(hOut,FrameX,FrameY+Frame_height);
printf("╚");
gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+Frame_height);
printf("╝");
a[FrameX][FrameY+Frame_height]=2;
a[FrameX+2*Frame_width-2][FrameY+Frame_height]=2;
for(i=2;i<2*Frame_width-2;i+=2)
{
gotoxy(hOut,FrameX+i,FrameY);
printf("︻"); //打印上横框
}
for(i=2;i<2*Frame_width-2;i+=2)
{
gotoxy(hOut,FrameX+i,FrameY+Frame_height);
printf("︼"); //打印下横框
a[FrameX+i][FrameY+Frame_height]=2; //记住下横框有图案
}
for(i=1;i<Frame_height;i++)
{
gotoxy(hOut,FrameX,FrameY+i);
printf("【"); //打印左竖框
a[FrameX][FrameY+i]=2; //记住左竖框有图案
}
for(i=1;i<Frame_height;i++)
{
gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+i);
printf("】"); //打印右竖框
a[FrameX+2*Frame_width-2][FrameY+i]=2; //记住右竖框有图案
}
}
/******制作俄罗斯方块********************************************************************/
void make_tetris(struct Tetris *tetris)
{
a[tetris->x][tetris->y]=b[0]; //中心方块位置的图形状态:1-有,0-无
switch(tetris->flag) //共6大类,19种类型
{
case 1: //田字方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x+2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 2: //直线方块:----
{
a[tetris->x-2][tetris->y]=b[1];
a[tetris->x+2][tetris->y]=b[2];
a[tetris->x+4][tetris->y]=b[3];
break;
}
case 3: //直线方块: |
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x][tetris->y-2]=b[2];
a[tetris->x][tetris->y+1]=b[3];
break;
}
case 4: //T字方块
{
a[tetris->x-2][tetris->y]=b[1];
a[tetris->x+2][tetris->y]=b[2];
a[tetris->x][tetris->y+1]=b[3];
break;
}
case 5: //T字顺时针转90度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x][tetris->y+1]=b[2];
a[tetris->x-2][tetris->y]=b[3];
break;
}
case 6: //T字顺时针转180度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x-2][tetris->y]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 7: //T字顺时针转270度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x][tetris->y+1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 8: //Z字方块
{
a[tetris->x][tetris->y+1]=b[1];
a[tetris->x-2][tetris->y]=b[2];
a[tetris->x+2][tetris->y+1]=b[3];
break;
}
case 9: //Z字顺时针转90度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x-2][tetris->y]=b[2];
a[tetris->x-2][tetris->y+1]=b[3];
break;
}
case 10: //Z字顺时针转180度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x-2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 11: //Z字顺时针转270度方块
{
a[tetris->x][tetris->y+1]=b[1];
a[tetris->x+2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 12: //7字方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x][tetris->y+1]=b[2];
a[tetris->x-2][tetris->y-1]=b[3];
break;
}
case 13: //7字顺时针转90度方块
{
a[tetris->x-2][tetris->y]=b[1];
a[tetris->x-2][tetris->y+1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 14: //7字顺时针转180度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x][tetris->y+1]=b[2];
a[tetris->x+2][tetris->y+1]=b[3];
break;
}
case 15: //7字顺时针转270度方块
{
a[tetris->x-2][tetris->y]=b[1];
a[tetris->x+2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 16: //倒7字方块
{
a[tetris->x][tetris->y+1]=b[1];
a[tetris->x][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y-1]=b[3];
break;
}
case 17: //倒7字顺指针转90度方块
{
a[tetris->x-2][tetris->y]=b[1];
a[tetris->x-2][tetris->y-1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
case 18: //倒7字顺时针转180度方块
{
a[tetris->x][tetris->y-1]=b[1];
a[tetris->x][tetris->y+1]=b[2];
a[tetris->x-2][tetris->y+1]=b[3];
break;
}
case 19: //倒7字顺时针转270度方块
{
a[tetris->x-2][tetris->y]=b[1];
a[tetris->x+2][tetris->y+1]=b[2];
a[tetris->x+2][tetris->y]=b[3];
break;
}
}
}
//******判断是否可动*************************************************************************/
int if_moveable(struct Tetris *tetris)
{
if(a[tetris->x][tetris->y]!=0)//当中心方块位置上有图案时,返回值为0,即不可移动
{
return 0;
}
else
{
if( //当为田字方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动
( tetris->flag==1 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
//或为直线方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动
( tetris->flag==2 && ( a[tetris->x-2][tetris->y]==0 &&
a[tetris->x+2][tetris->y]==0 && a[tetris->x+4][tetris->y]==0 ) ) ||
( tetris->flag==3 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x][tetris->y-2]==0 && a[tetris->x][tetris->y+1]==0 ) ) ||
( tetris->flag==4 && ( a[tetris->x-2][tetris->y]==0 &&
a[tetris->x+2][tetris->y]==0 && a[tetris->x][tetris->y+1]==0 ) ) ||
( tetris->flag==5 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y]==0 ) ) ||
( tetris->flag==6 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==7 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==8 && ( a[tetris->x][tetris->y+1]==0 &&
a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) ||
( tetris->flag==9 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x-2][tetris->y]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) ||
( tetris->flag==10 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==11 && ( a[tetris->x][tetris->y+1]==0 &&
a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==12 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y-1]==0 ) ) ||
( tetris->flag==13 && ( a[tetris->x-2][tetris->y]==0 &&
a[tetris->x-2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==14 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) ||
( tetris->flag==15 && ( a[tetris->x-2][tetris->y]==0 &&
a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==16 && ( a[tetris->x][tetris->y+1]==0 &&
a[tetris->x][tetris->y-1]==0 && a[tetris->x+2][tetris->y-1]==0 ) ) ||
( tetris->flag==17 && ( a[tetris->x-2][tetris->y]==0 &&
a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
( tetris->flag==18 && ( a[tetris->x][tetris->y-1]==0 &&
a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) ||
( tetris->flag==19 && ( a[tetris->x-2][tetris->y]==0 &&
a[tetris->x+2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) )
{
return 1;
}
}
return 0;
}
/******随机产生俄罗斯方块类型的序号**********************************************************/
void get_flag(struct Tetris *tetris)
{
tetris->count++; //记住产生方块的个数
srand((unsigned)time(NULL)); //初始化随机数
if(tetris->count==1)
{
tetris->flag = rand()%19+1; //记住第一个方块的序号
}
tetris->next = rand()%19+1; //记住下一个方块的序号
}
/******打印俄罗斯方块**********************************************************************/
void print_tetris(HANDLE hOut,struct Tetris *tetris)
{
for(i=0;i<4;i++)
{
b[i]=1; //数组b[4]的每个元素的值都为1
}
make_tetris(tetris); //制作俄罗斯方块
for( i=tetris->x-2; i<=tetris->x+4; i+=2 )
{
for(j=tetris->y-2;j<=tetris->y+1;j++)
{
if( a[i][j]==1 && j>FrameY )
{
gotoxy(hOut,i,j);
printf("○"); //打印边框内的方块
}
}
}
}
/******清除俄罗斯方块的痕迹****************************************************************/
void clear_tetris(HANDLE hOut,struct Tetris *tetris)
{
for(i=0;i<4;i++)
{
b[i]=0; //数组b[4]的每个元素的值都为0
}
make_tetris(tetris); //制作俄罗斯方块
for( i=tetris->x-2; i<=tetris->x+4; i+=2 )
{
for(j=tetris->y-2;j<=tetris->y+1;j++)
{
if( a[i][j]==0 && j>FrameY )
{
gotoxy(hOut,i,j);
printf(" "); //清除方块
}
}
}
}
/******判断是否满行并删除满行的俄罗斯方块****************************************************/
void del_full(HANDLE hOut,struct Tetris *tetris)
{ //当某行有Frame_width-2个方块时,则满行
int k,del_count=0; //分别用于记录某行方块的个数和删除方块的行数的变量
for(j=FrameY+Frame_height-1;j>=FrameY+1;j--)
{
k=0;
for(i=FrameX+2;i<FrameX+2*Frame_width-2;i+=2)
{
if(a[i][j]==1) //竖坐标依次从下往上,横坐标依次由左至右判断是否满行
{
k++; //记录此行方块的个数
展开阅读全文