《贪吃蛇游戏课程设计》报告

贪吃蛇游戏课程设计报告

         课程名称:  计算机软件技术基础    

         学    院   电气与信息工程学院    

         专业班级:                      

         姓    名:                     

         学    号                        

         指导教师:                       

         完成时间:                      

         报告成绩:                       

                

贪吃蛇游戏程序设计

一、设计要求

通过游戏程序设计,提高编程兴趣与编程思路,巩固C语言中所学的知识,合理的运用资料,实现理论与实际相结合。

(1).收集资料,分析课题,分解问题,形成总体设计思路;

(2).深入分析各个小问题,列出大纲,编写各部分程序模块;

(3).对于设计中用到的关键函数,要学会通过查资料,弄懂其用法,要联系问题进行具体介绍;

(4).上机调试,查错,逐步分析不能正常运行的原因,确保所设计的程序正确,并且能正常运行;

(5).完成课程设计报告,并进行答辩

。二.设计的作用、目的

C语言是一种易学易懂的通用程序设计语言,由于它具有功能性强,运用简洁,灵活兼有高级语言与低级语言的优点,以及“目标程序效率高”可移植性和能在各种系统上普遍实现等特点使它成为当今世界上的主流程序设计语言之一,同时被选作目前全世界广泛应用,同时也是大学生必修的科目。作为一位当代的大学生更要很好的利用它,学好一门设计语言,实现学以至用。

    制作C程序报告,可以巩固和加深自己对C语言课程的基本知识的理解和掌握,并且能够掌握C语言编程和程序调试的基本技能。

通过游戏程序的设计训练可以提高自己的基本技能,更好地掌握字符串的表示方法和字符串函数的功能、Tc图形操作的基本知识、键盘上特殊键的获取以及图形方式下光标的显示,提高自己编程兴趣与编程水平,学会如何正确的书写程序设计说明文档,提高运用C语言解决实际问题的能力,巩固C语言语法规则的理解和掌握,学会通过源程序写出流程图,提高自学以及查阅资料的能力。

三、所用仪器设备

1、能正常工作的计算机一台;    2、WindowsXP;

3、TC程序;                   4、Microsoft Word2003;

四、具体设计过程

4.1、程序功能 

贪吃蛇游戏是一个经典小游戏,一条蛇在封闭围墙里,围墙里随机出现一个食物,通过按键盘四个光标键控制蛇向上下左右四个方向移动,蛇头撞倒食物,则食物被吃掉,蛇身体长一节,同时记10分,接着又出现食物,等待蛇来吃,如果蛇在移动中撞到墙或身体交叉蛇头撞倒自己身体游戏结束。

4.2、设计思想

程序关键在于表示蛇的图形及蛇的移动。用一个小矩形快表示蛇的一节身体,身体每长一节,增加一个矩形块,蛇头用俩节表示。移动时必须从蛇头开始,所以蛇不能向相反的方向移动,如果不按任意键,蛇自行在当前方向上前移,但按下有效方向键后,蛇头朝着该方向移动,一步移动一节身体,所以按下有效方向键后,先确定蛇头的位置,而后蛇的身体随蛇头移动,图形的实现是从蛇头新位置开始画出蛇,这时,由于未清屏的原因,原来的蛇的位置和新蛇的位置差一个单位,所以看起来蛇多一节身体,所以将蛇的最后一节用背景色覆盖。食物的出现与消失也是画矩形块和覆盖矩形块。为了便于理解,定义两个结构体:食物与蛇。

4.3.设计的具体实现

(1)函数定义 

函数定义是对各个基础函数的定义,并且设置需要运用的信息,便于调用

#define N 200

#include <graphics.h>/*图形头文件*/

#include <stdlib.h>/*包含rand等函数*/

#include <dos.h>/*包含bios函数*/

#define LEFT 0x4b00/*光标左键值*/

#define RIGHT 0x4d00/*光标右键值*/

#define DOWN 0x5000/*光标下键值*/

#define UP 0x4800/*光标上键值*/

#define ESC 0x011b/*ESC的ASCII码*/

int i,key;/*图形坐标变量及按键变量*/

int score=0;/*得分*/

int gamespeed=10000;/*游戏速度自己调整*/

struct Food

{

   int x;/*食物的横坐标*/

   int y;/*食物的纵坐标*/

   int yes;/*判断是否要出现食物的变量*/

}food;/*食物的结构体*/                                                       

struct Snake

{

   int x[];/*蛇的横坐标*/

   int y[];/*蛇的纵坐标*/

   int node;/*蛇的节数*/

   int direction;/*蛇移动方向*/

   int life;/* 蛇的生命,0活着,1死亡*/

}snake;

void Init(void);/*图形驱动*/

void Close(void);/*图形结束*/

void DrawK(void);/*画界面函数*/

void GameOver(void);/*结束游戏*/                       

void GamePlay(void);/*玩游戏具体过程*/

void PrScore(void);/*输出成绩*/

void main(void)/*主函数*/

(2)主函数main( ) 

主函数是程序的主流程,首先定义使用到的常数、全局变量及函数原型说明,然后初始化图形系统,调用函数DrawK()画出开始画面,调用函数GamePlay(),即玩游戏的具体过程,游戏结束后调用Close()关闭图形系统,结束程序

void main(void)/*主函数*/

{

   Init();/*图形驱动*/

   DrawK();/*开始画面*/

   GamePlay();/*玩游戏具体过程*/

   Close();/*图形结束*/

}

void Init(void)/*图形驱动*/

{

   int gd=DETECT,gm;

   initgraph(&gd,&gm,"c:\\tc"); /*第一个参数表示图形适配器的类型,第二个为在该类型下图形的显示模式,第三个参数指定驱动程序所在目录。*/

   cleardevice();

}

(3) 画界面函数DrawK( ) 

主界面是一个封闭的围墙,用两个循环语句分别在水平和垂直方向输出连续的宽度和高度均的矩形方块,表示围墙,为了醒目,设置为白色。

void DrawK(void)/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*/

{

   setbkcolor(0);/*设置当前背景颜色*/

   setcolor(YELLOW);/*设置当前画线颜色*/

   setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*设置线型*/

   for(i=50;i<=600;i+=10)/*画围墙*/

   {

      rectangle(i,40,i+10,49); /*上边*/

      rectangle(i,451,i+10,460);/*下边*/

   }

  for(i=40;i<=450;i+=10)

  {

     rectangle(50,i,59,i+10); /*左边*/

     rectangle(601,i,610,i+10);/*右边*/

  }

}

(4)游戏具体过程函数GamePlay( ) 

这是游戏的主要组成部分,他采用将前一节的坐标赋给后一节,用背景颜色将最后节去除,当蛇头的坐标与食物的坐标相等时,表示食物被吃掉了。

void GamePlay(void)/*玩游戏具体过程*/

{

   randomize();/*随机数发生器*/

   food.yes=1;/*1表示需要出现新食物,0表示已经存在食物*/

   snake.life=0;/*活着*/

   snake.direction=1;/*方向往右*/

   snake.x[0]=100;snake.y[0]=100;/*蛇头*/

   snake.x[1]=110;snake.y[1]=100;/*蛇第二节*/

   snake.node=2;/*节数*/

   PrScore();/*输出得分*/                                             

   while(1)/*可以重复玩游戏,压ESC键结束*/

   {

      while(!kbhit())/*在没有按键的情况下,蛇自己移动身体*/

      {

  if(food.yes==1)/*需要出现新食物*/

  {

      food.x=rand()%400+60;

      food.y=rand()%350+60;

      while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到*/

  food.x++;

      while(food.y%10!=0)

  food.y++;

  food.yes=0;/*画面上有食物了*/

  }

  if(food.yes==0)/*画面上有食物了就要显示*/

  {

              setcolor(GREEN);/*食物的颜色*/

              rectangle(food.x,food.y,food.x+10,food.y-10);

  }

         for(i=snake.node-1;i>0;i--)/*蛇的每个环节往前移动,贪吃蛇的关键算法*/

         {

            snake.x[i]=snake.x[i-1];

     snake.y[i]=snake.y[i-1];

  }                                             

 switch(snake.direction) /*定义1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/

  {

     case 1:snake.x[0]+=10;break;

     case 2: snake.x[0]-=10;break;

     case 3: snake.y[0]-=10;break;

     case 4: snake.y[0]+=10;break;

  }

for(i=3;i<snake.node;i++)/*从蛇的第四节开始判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来*/

  {

     if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0])

     {

               GameOver();/*显示失败*/

               snake.life=1;

               break;

     }

        }

 if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||snake.y[0]>455)/*蛇是否撞到墙壁*/

 {

     GameOver();/*本次游戏结束*/

     snake.life=1; /*蛇死*/

 }

 if(snake.life==1)/*以上两种判断以后,如果蛇死就跳出内循环,重新开始*/

           break;

 if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以后*/

 {

           setcolor(0);/*把画面上的食物东西去掉*/

           rectangle(food.x,food.y,food.x+10,food.y-10);

    snake.x[snake.node]=-20;snake.y[snake.node]=-20; /*-20表示尾巴长一节*/

          /*新的一节先放在看不见的位置,下次循环就取前一节的位置*/

    snake.node++;/*蛇的身体长一节*/

    food.yes=1;/*画面上需要出现新的食物*/

    score+=10;

    PrScore();/*输出新得分*/

 }

 setcolor(4);                                                                                                 

 for(i=0;i<snake.node;i++)/*画出蛇*/

    rectangle(snake.x[i],snake.y[i],snake.x[i]+10,

               snake.y[i]-10);

 delay(gamespeed);

 setcolor(0);/*用黑色去除蛇的的最后一节*/

 rectangle(snake.x[snake.node-1],snake.y[snake.node-1],

 snake.x[snake.node-1]+10,snake.y[snake.node-1]-10);

     }  /*endwhile(!kbhit)*/

    if(snake.life==1)/*如果蛇死就跳出循环*/

        break;

    key=bioskey(0);/*接收按键*/

    if(key==ESC)/*按ESC键退出*/

       break;

    else

       if(key==UP&&snake.direction!=4)

/*判断是否往相反的方向移动*/

   snake.direction=3;

       else

   if(key==RIGHT&&snake.direction!=2)

      snake.direction=1;

   else

      if(key==LEFT&&snake.direction!=1)

  snake.direction=2;

      else

  if(key==DOWN&&snake.direction!=3)

     snake.direction=4;

   }/*endwhile(1)*/

}

(5)游戏结束函数GameOver( ) 

游戏结束,清除屏幕,输出分数,显示游戏结束信息。

void GameOver(void)/*游戏结束*/

{

    cleardevice();

    PrScore();

   setcolor(RED);

   settextstyle(0,0,4);

   outtextxy(200,200,"guojian");

   getch();

}

void PrScore(void)/*输出成绩*/

{  

   char str[10];

   setfillstyle(SOLID_FILL, WHITE);

   bar(50,15,200,35);

   setcolor(6);

   settextstyle(0,0,2);

   sprintf(str,"score:%d",score);

   outtextxy(55,20,str);

}

void Close(void)/*图形结束*/

{  

    getch();

closegraph();

}

4.4、 总体流程图

}

4.5、程序代码编写及注释

#define N 200

#include <graphics.h>

#include <stdlib.h>

#include <dos.h>

#define LEFT 0x4b00

#define RIGHT 0x4d00

#define DOWN 0x5000

#define UP 0x4800

#define ESC 0x011b

int i,key;

int score=0;/*得分*/

int gamespeed=50000;/*游戏速度自己调整*/

struct Food

{

   int x;/*食物的横坐标*/

   int y;/*食物的纵坐标*/

   int yes;/*判断是否要出现食物的变量*/

}food;/*食物的结构体*/

struct Snake

{

   int x[N];

   int y[N];

   int node;/*蛇的节数*/

   int direction;/*蛇移动方向*/

   int life;/* 蛇的生命,0活着,1死亡*/

}snake;

void Init(void);/*图形驱动*/

void Close(void);/*图形结束*/

void DrawK(void);/*开始画面*/

void GameOver(void);/*结束游戏*/

void GamePlay(void);/*玩游戏具体过程*/

void PrScore(void);/*输出成绩*/

/*主函数*/

void main(void)

{

   Init();/*图形驱动*/

   DrawK();/*开始画面*/

   GamePlay();/*玩游戏具体过程*/

   Close();/*图形结束*/

}

/*图形驱动*/

void Init(void)

{

   int gd=DETECT,gm;

   initgraph(&gd,&gm,"c:\\tc");

   cleardevice();

}

/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*/

void DrawK(void)

{

/*setbkcolor(LIGHTGREEN);*/

   setcolor(11);

   setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*设置线型*/

   for(i=50;i<=600;i+=10)/*画围墙*/

   {

      rectangle(i,40,i+10,49); /*上边*/

      rectangle(i,451,i+10,460);/*下边*/

   }

  for(i=40;i<=450;i+=10)

  {

     rectangle(50,i,59,i+10); /*左边*/

     rectangle(601,i,610,i+10);/*右边*/

  }

}

/*玩游戏具体过程*/

void GamePlay(void)

{

   randomize();/*随机数发生器*/

   food.yes=1;/*1表示需要出现新食物,0表示已经存在食物*/

   snake.life=0;/*活着*/

   snake.direction=1;/*方向往右*/

   snake.x[0]=100;snake.y[0]=100;/*蛇头*/

   snake.x[1]=110;snake.y[1]=100;

   snake.node=2;/*节数*/

   PrScore();/*输出得分*/

   while(1)/*可以重复玩游戏,压ESC键结束*/

   {

      while(!kbhit())/*在没有按键的情况下,蛇自己移动身体*/

      {

     if(food.yes==1)/*需要出现新食物*/

     {

         food.x=rand()%400+60;

         food.y=rand()%350+60;

         while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到*/

       food.x++;

         while(food.y%10!=0)

       food.y++;

       food.yes=0;/*画面上有食物了*/

     }

     if(food.yes==0)/*画面上有食物了就要显示*/

     {

              setcolor(GREEN);

              rectangle(food.x,food.y,food.x+10,food.y-10);

     }

         for(i=snake.node-1;i>0;i--)/*蛇的每个环节往前移动,也就是贪吃蛇的关键算法*/

         {

            snake.x[i]=snake.x[i-1];

        snake.y[i]=snake.y[i-1];

     }

       /*1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/

     switch(snake.direction)

     {

        case 1:snake.x[0]+=10;break;

        case 2: snake.x[0]-=10;break;

        case 3: snake.y[0]-=10;break;

        case 4: snake.y[0]+=10;break;

     }

     for(i=3;i<snake.node;i++)/*从蛇的第四节开始判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来*/

     {

        if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0])

        {

               GameOver();/*显示失败*/

               snake.life=1;

               break;

        }

        }

    if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||

       snake.y[0]>455)/*蛇是否撞到墙壁*/

    {

        GameOver();/*本次游戏结束*/

        snake.life=1; /*蛇死*/

    }

    if(snake.life==1)/*以上两种判断以后,如果蛇死就跳出内循环,重新开始*/

           break;

    if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以后*/

    {

           setcolor(0);/*把画面上的食物东西去掉*/

           rectangle(food.x,food.y,food.x+10,food.y-10);

       snake.x[snake.node]=-20;snake.y[snake.node]=-20;

          /*新的一节先放在看不见的位置,下次循环就取前一节的位置*/

       snake.node++;/*蛇的身体长一节*/

       food.yes=1;/*画面上需要出现新的食物*/

       score+=10;

       PrScore();/*输出新得分*/

    }

    setcolor(4);/*画出蛇*/

    for(i=0;i<snake.node;i++)

       rectangle(snake.x[i],snake.y[i],snake.x[i]+10,

               snake.y[i]-10);

    delay(gamespeed);

    setcolor(0);/*用黑色去除蛇的的最后一节*/

    rectangle(snake.x[snake.node-1],snake.y[snake.node-1],

    snake.x[snake.node-1]+10,snake.y[snake.node-1]-10);

     }  /*endwhile(!kbhit)*/

    if(snake.life==1)/*如果蛇死就跳出循环*/

        break;

    key=bioskey(0);/*接收按键*/

    if(key==ESC)/*按ESC键退出*/

       break;

    else

       if(key==UP&&snake.direction!=4)

/*判断是否往相反的方向移动*/

      snake.direction=3;

       else

      if(key==RIGHT&&snake.direction!=2)

         snake.direction=1;

      else

         if(key==LEFT&&snake.direction!=1)

       snake.direction=2;

         else

       if(key==DOWN&&snake.direction!=3)

          snake.direction=4;

   }/*endwhile(1)*/

}

/*游戏结束*/

void GameOver(void)

{

    cleardevice();

    PrScore();

   setcolor(RED);

   settextstyle(0,0,4);

   outtextxy(200,200,"GAME OVER");

   getch();

}

/*输出成绩*/

void PrScore(void)

{  

   char str[10];

   setfillstyle(SOLID_FILL,YELLOW);

   bar(50,15,220,35);

   setcolor(6);

   settextstyle(0,0,2);

   sprintf(str,"score:%d",score);

   outtextxy(55,20,str);

}

/*图形结束*/

void Close(void)

{  

    getch();

    closegraph();

}

4.6、调试问题及解决方法

将已改好的程序复制到Turbo C时,由于软件的内容过多会出现右移,以致大部分的内容无法复制到Turbo C的界面上,最后导致软件无法运行。解决方法:在改程序时应该把格式设置好,注意左对齐,同时一行的语句尽量的短,最好是一个语句占一行。

在将程序输入到TC中,对源程序进行编译、运行,发现程序存在的多处错误, 如下图所示:

可以按照程序运行的错误提示对原程序进行修改,在调试过程中有时也会遇到不懂的问题,我去图书馆或上网查阅一些资料或者是向老师请教也解决了对源程序一一修改直到运行成功。

4.7、调试结果

1.  下图为程序调试编译结果:

2下图为程序调试运行结果(即贪吃蛇游戏界面)

5设计心得体会

经过短短两星期的计算机软件技术实习,让我对C程序有了一个更深的了解,以前总认为C语言很枯燥,认为那些我们所设计的程序没有什么用处,但现在通过设计贪吃蛇游戏这个程序使我懂得了如何将所学的知识运用于生活当中。虽然在刚开始设计程序时不太明白如何去设计这程序,但当我看完《C语言课程设计案例精编》并用C语言做出这个贪吃蛇程序后,让我深深感受到C程序的神奇。

在设计这个程序中我主要学会了如何运用以下有关C语言的知识

1) 函数定义是要做到顾名思义是很重要的,它对读程序的人正确认识程序  

十分重要,在修改这个程序的过程中也能很快找到程序各模块的作用,大大增

加了程序的可读性。

2) 分析函数先从main()函数入手。Main()函数是C源程序编译时的开始,    

从main()函数开始读函数可将其他函数的功能理解得更透彻。

3) 在做程序的时候先列框架,将这个程序所要达到的目的(功能)分析出 

来,选择正确的数据结构然后在将程序模块化,按照模块编写函数更加简单合理。

4) 我还了解了很多的库函数的作用,如字符串函数中有很多对字符串进行

处理的函数,起功能我都有所了解。

    同时我也获得了许多宝贵的经验:

1) 在设计程序之前,务必要对你所设计的题目和内容有一个系统的了解,

知道所设计的题目和内容包含那些资源。

2) 设计程序采用什么编程语言并不是非常重要,关键要有一个清晰的思路

和一个完整的软件流程图,因而,要先把设计原理与思路搞清楚,再把流程图画出来,这样设计起来就简单多了。

3) 在设计程序时,不能妄想一次就将整个程序设计好,“反复修改,不断改

进”是程序设计的必经之路,发现错误也是取得成绩的一种。

4) 要养成注释程序的好习惯,一个程序的完美与否不仅仅是实现功能,而

应该让人一看就能明白你的思路,这样也为资料的保存和交流提供了方便。

5) 在设计程序过程中遇到问题是很正常的,但我们应该将每次遇到的问题

记录下来,并分析清楚,以免下次再碰到同样的问题。

6、参考文献

1.郭翠英,《C语言课程设计案例精编》,中国水利水电出版社,2004.3

2徐金梧,杨德斌等,《TURBO C实用大全》,机械工程出版社,1996.5

3李丽娟   《C语言程序设计教程》        人民邮电出版社

4林华聪   《C语言程序设计思想与实践》  冶金工业出版社

5张继温   《C语言程序设计教程》        高等教育出版社

相关推荐