贪吃蛇

来源:互联网 发布:连锁店收银软件 编辑:程序博客网 时间:2024/04/30 11:33

这次用控制台实现简单的贪吃蛇游戏(面向过程设计)。
首先,明确游戏规则。游戏初始状态是有一睹围墙和一条由几个点组成的“蛇”,还有一个食物,其实就是打印地图和创建一个链表。代码分别如下:

  1. 游戏初始化
void Pos(short x,short y)//设置光标位置函数,上一节讲过。{    COORD pos;    pos.X=x;    pos.Y=y;    HANDLE hOutput=GetStdHandle(STD_OUTPUT_HANDLE);    SetConsoleCursorPosition(hOutput,pos);}void CreateMap()//打印地图{    //打印上下边框,这里每次自增2是因为控制台的一行和一列    //的宽度不同,且恰好有两倍关系。    for(int i=0;i<57;i+=2)    {        Pos(i,0);        printf("■");        Pos(i,24);        printf("■");    }    for(int i=1;i<24;i++)//打印左右边框    {        Pos(0,i);        printf("■");                    Pos(56,i);        printf("■");        }    return;}void PrintSnake()//打印蛇{    struct Body *p=body001;    while(p!=NULL)//判断是否指向蛇尾    {        Pos(p->x,p->y);        printf("■");        p=p->next;    }//从蛇头打印到蛇尾    return ;}int Food=0; //1表明有食物,0表明没食物short food_x,food_y;//食物坐标void CreateFood()//创建新食物{    if(Food==0)    {               srand((int)time(0));        food_x=2+rand()%53;//x的取值范围[2,54]        if(food_x%2==1)            food_x--;        food_y=1+rand()%23;//y的取值范围[1,23]        Food=1;    }}//接下来定义结构体从而创建链表。struct Body//定义蛇身结构体{    short x,y;//蛇身结点的坐标    Body *next;//指向下一个结点的指针};Body *body001;//蛇头指针,判断方向,宜做全局变量void Init()//游戏初始化{    Body *body002,*body003,*body004;    body001=new Body;//创建4个蛇身结构体    body002=new Body;    body003=new Body;    body004=new Body;    body001->next=body002;//把蛇身连接起来,形成链表    body002->next=body003;    body003->next=body004;    body004->next=NULL;    Pos(body001->x=12,body001->y=8);printf("■");//设定并打印蛇身的初始位置    Pos(body002->x=10,body002->y=8);printf("■");    Pos(body003->x=8,body003->y=8);printf("■");    Pos(body004->x=6,body004->y=8);printf("■");    CreateFood();//创建食物}

步骤1总结,有4个函数块和1个结构体和4个全局变量,
声明如下:
void Pos(short x,short y);//设置光标位置函数,上一节讲过。
void CreateMap();//打印地图
void PrintSnake();//打印蛇
void CreateFood();//创建食物坐标
void Init();//游戏初始化
struct Body;//定义蛇身结构体
Body *body001;//蛇头指针
int Food=0; //1表明有食物,0表明没食物
short food_x,food_y;//食物坐标
好了,现在进行一个关键步骤,就是蛇的移动问题。我想的是,蛇的移动分为两种情况,就是蛇的下一步有没有食物。若没有食物,则在下一步位置创建蛇身结构体,作为蛇头,然后把蛇尾删除。
若是有食物,则在食物位置创建结构体,作为蛇头,不删除蛇尾。
这一步代码包含蛇的一步移动问题。

void SnakeMove()//蛇身移动、刷新蛇身和食物及其坐标{    Body *p_food;//下一格有食物    Body *p_forward;//下一格没食物    Body *q;//蛇身移动一格时的临时指针    p_forward=new Body;       if(1==dir)//向上移动    {        if(body001->x==food_x && body001->y-1==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Pos(62,3);printf("分数:%d",score);            Food=0;            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x;//横坐标不变            p_forward->y=body001->y-1;//纵坐标-1            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }//else    }    if(2==dir)//向下移动    {        if(body001->x==food_x && body001->y+1==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Pos(62,3);printf("分数:%d",score);            Food=0;            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x;//横坐标不变            p_forward->y=body001->y+1;//纵坐标+1            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }//else    }    if(3==dir)//向左移动    {        if(body001->x-2==food_x && body001->y==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Pos(62,3);printf("分数:%d",score);            Food=0;            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x-2;//横坐标-2            p_forward->y=body001->y;//纵坐标不变            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }    }    if(4==dir)//向右移动    {        if(body001->x+2==food_x && body001->y==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Food=0;            Pos(62,3);printf("分数:%d",score);            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x+2;//横坐标=2            p_forward->y=body001->y;//纵坐标不变            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }    }    Pos(food_x,food_y);printf("■");//打印食物    PrintSnake();//打印蛇} 

其实这一步是整个游戏的核心,每走一步就重新打印蛇,意味着这个函数需要放在一个循环里面。
接下来实现游戏规则:不能碰墙和自己。
代码如下:

//游戏规则检测int TouchSelf()//判断是否咬到自己{    struct Body *p_tself;    p_tself=body001;    while(!p_tself->next==NULL)    {        p_tself=p_tself->next;        if(p_tself->x==body001->x && p_tself->y==body001->y)            return 1;    }    return 0;} int TouchWall()//不可穿墙{    if(body001->x==0 || body001->x==56 || body001->y==0 || body001->y==24)        return 1;    else         return 0;}

OK,有了一步移动,有了规则检测,有了食物随机产生,有了墙面,可以进行游戏的循环,每一步循环,我要得到玩家的按键方向,没有则是继续上一步的方向或是初始方向。然后有了方向就移动一步,顺便检测是否撞墙和撞到自己,没有就进行下一个循坏。
两个循坏的时间间隔则是蛇运动的快慢了。

void GameCircle()//游戏循环{    while(1)    {        if (1== TouchWall())//不可穿墙             break;//撞墙Game Over        if(1== TouchSelf() )//判断蛇是否咬到自己            break;//咬到自己Game Over        //判断用户的按键输入        if(GetAsyncKeyState(VK_UP) && dir!=2)            dir=1;        else if(GetAsyncKeyState(VK_DOWN) && dir!=1)            dir=2;        else if(GetAsyncKeyState(VK_LEFT) && dir!=4)            dir=3;        else if(GetAsyncKeyState(VK_RIGHT) && dir!=3)            dir=4;        SnakeMove();//蛇移动一格         Sleep(sleeptime);//设定两次移动之间的时间间隔    } } void EndImage() //游戏结束画面{    system("cls");    Pos(30,9);printf("游戏结束,欢迎再来!");    Pos(30,11);printf("你的得分:%d",score);    Pos(28,13);    system("pause");}

整个游戏具备的条件都有了,在主函数里面实现。如下:

int main(){    CreateMap();    Init();    GameCircle();    EndImage();    return 0;}

嗯,这样结束了。
整段代码如下。

#include<windows.h>#include<conio.h>#include<cstdlib>#include<time.h>#include<iostream>using namespace std;void Pos(short x,short y)//设置光标位置函数,上一节讲过。{    COORD pos;    pos.X=x;    pos.Y=y;    HANDLE hOutput=GetStdHandle(STD_OUTPUT_HANDLE);    SetConsoleCursorPosition(hOutput,pos);}void CreateMap()//打印地图{    for(int i=0;i<57;i+=2)//打印上下边框,这里每次自增2是因为控制台的一行和一列的宽度不同,且恰好有两倍关系。    {        Pos(i,0);        printf("■");        Pos(i,24);        printf("■");    }    for(int i=1;i<24;i++)//打印左右边框    {        Pos(0,i);        printf("■");                    Pos(56,i);        printf("■");        }    return;}//接下来定义结构体从而创建链表。struct Body//定义蛇身结构体{    short x,y;//蛇身结点的坐标    Body *next;//指向下一个结点的指针};int Food=0; //1表明有食物,0表明没食物short food_x,food_y;//食物坐标void CreateFood()//创建新食物{    if(Food==0)    {               srand((int)time(0));        food_x=2+rand()%53;//x的取值范围[2,54]        if(food_x%2==1)            food_x--;        food_y=1+rand()%23;//y的取值范围[1,23]        Food=1;    }}Body *body001;//蛇头指针void Init()//游戏初始化{    struct Body *body002,*body003,*body004;//定义四个指向蛇身的指针    body001=new Body;//创建4个蛇身结构体    body002=new Body;    body003=new Body;    body004=new Body;    body001->next=body002;//把蛇身连接起来,形成链表    body002->next=body003;    body003->next=body004;    body004->next=NULL;    Pos(body001->x=12,body001->y=8);printf("■");//设定并打印蛇身的初始位置    Pos(body002->x=10,body002->y=8);printf("■");    Pos(body003->x=8,body003->y=8);printf("■");    Pos(body004->x=6,body004->y=8);printf("■");    CreateFood();//打印食物}void PrintSnake()//打印蛇{    struct Body *p=body001;    while(p!=NULL)//判断是否指向蛇尾    {        Pos(p->x,p->y);        printf("■");        p=p->next;    }//从蛇头打印到蛇尾    return ;}int dir=4;//蛇头方向1-up,2-down,3-left,4-rightint sleeptime=220;//每次移动之后的停顿时间int score;//玩家得分void SnakeMove()//蛇身移动、刷新蛇身和食物及其坐标{    Body *p_food;//下一格有食物    Body *p_forward;//下一格没食物    Body *q;//蛇身移动一格时的临时指针    p_forward=new Body;       if(1==dir)//向上移动    {        if(body001->x==food_x && body001->y-1==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Pos(62,3);printf("分数:%d",score);            Food=0;            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x;//横坐标不变            p_forward->y=body001->y-1;//纵坐标-1            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }//else    }    if(2==dir)//向下移动    {        if(body001->x==food_x && body001->y+1==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Pos(62,3);printf("分数:%d",score);            Food=0;            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x;//横坐标不变            p_forward->y=body001->y+1;//纵坐标+1            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }//else    }    if(3==dir)//向左移动    {        if(body001->x-2==food_x && body001->y==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Pos(62,3);printf("分数:%d",score);            Food=0;            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x-2;//横坐标-2            p_forward->y=body001->y;//纵坐标不变            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }    }    if(4==dir)//向右移动    {        if(body001->x+2==food_x && body001->y==food_y)//下一格有食物        {            p_food=new Body;            p_food->x=food_x;            p_food->y=food_y;            p_food->next=body001;            body001=p_food;            score+=5;            Food=0;            Pos(62,3);printf("分数:%d",score);            CreateFood();        }        else//下一格没有食物        {            p_forward->x=body001->x+2;//横坐标=2            p_forward->y=body001->y;//纵坐标不变            p_forward->next=body001;            body001=p_forward;            q=body001;            while((q->next)->next!=NULL)//使q指向倒数第二个结点                q=q->next;            Pos((q->next)->x,(q->next)->y);//移动光标到蛇尾            printf(" ");//删除蛇尾            free(q->next); //释放蛇尾            q->next=NULL;//使倒数第二个结点成为新的蛇尾        }    }    Pos(food_x,food_y);printf("■");//打印食物    PrintSnake();//打印蛇} int TouchSelf()//判断是否咬到自己{    struct Body *p_tself;    p_tself=body001;    while(!p_tself->next==NULL)    {        p_tself=p_tself->next;        if(p_tself->x==body001->x && p_tself->y==body001->y)            return 1;    }    return 0;} int TouchWall()//不可穿墙{    if(body001->x==0 || body001->x==56 || body001->y==0 || body001->y==24)        return 1;    else         return 0;}void GameCircle()//游戏循环{    while(1)    {        if (1== TouchWall())//不可穿墙             break;        if(1== TouchSelf() )//判断蛇是否咬到自己            break;//咬到自己Game Over        //判断用户的按键输入        if(GetAsyncKeyState(VK_UP) && dir!=2)            dir=1;        else if(GetAsyncKeyState(VK_DOWN) && dir!=1)            dir=2;        else if(GetAsyncKeyState(VK_LEFT) && dir!=4)            dir=3;        else if(GetAsyncKeyState(VK_RIGHT) && dir!=3)            dir=4;        SnakeMove();//蛇移动一格         Sleep(sleeptime);//设定两次移动之间的时间间隔    } } void EndImage(){    system("cls");    Pos(30,9);printf("游戏结束,欢迎再来!");    Pos(30,11);printf("你的得分:%d",score);    Pos(28,13);    Sleep(5000);}int main(){    CreateMap();    Init();    GameCircle();    EndImage();    return 0;}
0 0
原创粉丝点击