贪吃蛇程序设计报告

贪吃蛇游戏程序设计

一、课程设计任务

    贪吃蛇小游戏程序设计

二、设计要求

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

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

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

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

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

三、需求分析

3.1程序功能 

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

3.2、设计思想

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

3.3、流程图

开始

初始化界面和蛇身

放置食物

蛇开始运动

蛇吃到食?

蛇长大

蛇死亡?

继续?

退出界面

N

 

N

Y

N

Y

 

游戏者按键选择

 

Y

四、设计的具体实现

1)函数定义 

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


#define N 200

#define M 200

#include"graphics.h"

#include<stdlib.h>

#include<stdio.h>

#include<string.h>

#include<iostream.h>

#include<dos.h>

#include<conio.h>

#include <windows.h>

#define LEFT 97//A

#define RIGHT 100//D

#define DOWN 115//S

#define UP 119//W

#define Esc 0x011b

int i,key;

int score=0;

int gamespeed=250;//游戏速度可根据实际情况自行调整

struct Food

{

    int x;//食物的横坐标

    int y;//食物的纵坐标

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

}food;//食物的结构体

struct Snake

{

    int x[M];

    int y[M];

    int node;//蛇的节数

    int direction;//蛇的移动方向

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

}snake;

void Init();//图形驱动

void Close();//图形结束

void DrawK();//开始画面

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

void GameOver();//游戏结束

void PrScore();//输出成绩


2)主函数main( ) 

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

void main()//主函数

{

Init();//图形驱动

DrawK();//开始画面

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

Close();//图形结束

}

void Init()//图形驱动

{

int gd=DETECT,gm;

initgraph(&gd,&gm," ");/*此处为turboc的路径,读者可以根据自己的电脑而改*/

cleardevice();

}

3) 画界面函数DrawK( ) 

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

void DrawK()//开始画面,左上角坐标为(5040),右下角坐标为(610460)的围墙

{

    setbkcolor(GREEN);

    setcolor(LIGHTRED);

    setlinestyle(0,0,5);//设置线型

    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()//玩游戏的具体过程

{

    rand();//随机数发生器

    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;//新的一节先放在看不见得位置,下次循环就取前一节的位置

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

              food.yes=1;

              score+=10;

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

           }

           setcolor(WHITE);//画出蛇

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

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

           Sleep(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);

       }

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

           break;

       key=getchar();//接受案件

       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()//游戏结束

{

    cleardevice();

    PrScore();

    setcolor(RED);

    outtextxy(100,100,"我会回来的!!!!!");

    getch();

}

void PrScore()//输出成绩

{

    char str[10];

    setfillstyle(SOLID_FILL,YELLOW);

    bar(50,15,220,35);

    setcolor(6);

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

    outtextxy(55,20,str);

}

void Close()//图形结束

{

    getch();

    closegraph();

}

五、调试及解决方法

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

六、测试结果

 

 

 

 

 

 

七、设计心得体会

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

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

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

加了程序的可读性。

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

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

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

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

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

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

5)学会了有关头文件的使用方法,及系统调配问题的解决方法等。

   6)了解到了注释的重要性。

八、附录

1、参考文献:

谭浩强,《C++程序设计》            清华大学出版社

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

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

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

2、源代码


#define M 200

#include"graphics.h"

#include<stdlib.h>

#include<stdio.h>

#include<string.h>

#include<iostream.h>

#include<dos.h>

#include<conio.h>

#include <windows.h>

#define LEFT 97//A

#define RIGHT 100//D

#define DOWN 115//S

#define UP 119//W

#define Esc 0x011b

int i,key;

int score=0;

int gamespeed=250;//游戏速度可根据实际情况自行调整

struct Food

{

    int x;//食物的横坐标

    int y;//食物的纵坐标

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

}food;//食物的结构体

struct Snake

{

    int x[M];

    int y[M];

    int node;//蛇的节数

    int direction;//蛇的移动方向

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

}snake;

void Init();//图形驱动

void Close();//图形结束

void DrawK();//开始画面

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

void GameOver();//游戏结束

void PrScore();//输出成绩

void main()//主函数

{

    Init();//图形驱动

    DrawK();//开始画面

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

    Close();//图形结束

}

void Init()//图形驱动

{

    int gd=DETECT,gm;

    initgraph(&gd,&gm," ");/*此处为turboc的路径,读者可以根据自己的电脑而改*/

    cleardevice();

}

void DrawK()//开始画面,左上角坐标为(5040),右下角坐标为(610460)的围墙

{

    setbkcolor(GREEN);

    setcolor(LIGHTRED);

    setlinestyle(0,0,5);//设置线型

    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()//玩游戏的具体过程

{

    rand();//随机数发生器

    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;//新的一节先放在看不见得位置,下次循环就取前一节的位置

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

                food.yes=1;

                score+=10;

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

            }

            setcolor(WHITE);//画出蛇

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

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

            Sleep(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);

        }

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

            break;

        key=getchar();//接受案件

        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()//游戏结束

{

    cleardevice();

    PrScore();

    setcolor(RED);

    outtextxy(100,100,"我会回来的!!!!!");

    getch();

}

void PrScore()//输出成绩

{

    char str[10];

    setfillstyle(SOLID_FILL,YELLOW);

    bar(50,15,220,35);

    setcolor(6);

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

    outtextxy(55,20,str);

}

void Close()//图形结束

{

    getch();

    closegraph();

}

 

 

 

 

 

 

  • 13
    点赞
  • 4
    评论
  • 88
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值