贪吃蛇()C++实现

/********************************************************************************
* @File name: main.c
* @Description: 用于详细说明此程序文件完成的主要功能
* @ Function List: void drawMap(); //绘制游戏边框
                   void createFood(); //随机生成食物
                   void keyDown();  //按键操作
                   bool snakeStatus();  //判断蛇的状态
                   void getxy(int x, int y);  //从控制台移动光标
* @Author: 王成军
* @Version: 1.1
* @Date: 2019-12-05
* @History: 修改历史记录列表,应包括修改日期、修改者及修改内容简述(可有可无)。
********************************************************************************/

#include<stdio.h>
#include<stdlib.h>
/*stdlib.h里面定义了五种类型,一些宏和通用工具函数类型例如为size_t,wchar_t的,div_t,ldiv_t和lldiv_t;宏例如EXIT_FAILURE,EXIT_SUCCESS RAND_MAX和MB_CUR_MAX等等;
常用的函数如malloc(),calloc(),realloc(),free(),system(),atoi(),atol(),rand(),srand(),exit()等。可以打开编译器的包括目录里面的stdlib.h头文件查看。
*/
#include<Windows.h>
#include <graphics.h>
#include<time.h>
#include<conio.h>  //控制台输入输出头文件


#define snakesize 100    //蛇的最大身体长度 
#define mapheigt 26     //地图的高度
#define mapwidth  75    //地图的宽度

int key = 72;          //表示蛇移动的方向,72为按下“↑”所代表的数字 
int changeFlag = 0;    //用来判断蛇是否吃掉了食物,
int sorce = 0;         //记录玩家的得


void drawMap();        //绘制游戏边框
void createFood();    //随机生成食物
void keyDown();       //按键操作
bool snakeStatus();    //蛇的状态
void getxy(int x, int y);  //从控制台移动光标
void gameEnd();
void creatInterface();   //功能菜单


struct    //定义食物结构体
{
int x;
int y;
int c;
}food;

struct     //定义蛇结构体
{
  int speed;
  int len;
  int x[snakesize];
  int y[snakesize];
}snake;


/*******************************************************
*
* Function name :set_color(int x) 
* Description   : 修改颜色
* Parameter     :      
*        @STD_OUTPUT_HANDLE     标准输出的句柄     
* Return        :无
SetConsoleTextAttribute是一个可以在API(应用程序编程接口)中设置控制台窗口字体颜色和背景色的计算机函数
该函数被广泛应用于电脑编程与软件开发中。
**********************************************************/
void set_color(int x)
{
    HANDLE winHandle;
    winHandle = GetStdHandle((STD_OUTPUT_HANDLE)) ;//用来修改命令行窗口的颜色
    SetConsoleTextAttribute(winHandle,x) ;
}

/*******************************************************
*
* Function name : getxy()
* Description   : 函数功能描述
* Parameter         :int x,int y
*        @x         表示光标的x坐标值
*        @y         表示光标的y坐标值 
*       
* Return          :无
*COORD是Windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标。
其定义为:
typedef struct _COORD {
SHORT X; // horizontal coordinate
SHORT Y; // vertical coordinate
} COORD;
**********************************************************/
void getxy(int x,int y)
{
    COORD get;
    get.X=x;
    get.Y=y;
    GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), get);
    /*句柄: 在windows程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为他们分配内存,
并返回标示这些资源的标示号。*/
}
/*******************************************************
*
* Function name : drawMap()  
* Description   ://绘制游戏边框,定义蛇的移动
* Parameter         :int i  局部变量  用于循环
*        @i           用于循环时打印墙体,和蛇
*        @参数名2           参数说明
*        @参数名3           参数说明
* Return          :函数返回值的说明
**********************************************************/
void drawMap()                //绘制地图
{
    int i;
    for(i=0;i<=mapwidth;i+=2)
    {
        getxy(i,0);
        printf("■");
        set_color(3);
        getxy(i,mapheigt);
        printf("■");           //将光标移动依次到(i,mapheight)处打印下边框
        set_color(2);
    }


for ( i = 0; i < mapheigt; i++)
    {
    getxy(0, i);      //将光标移动依次到(0,i)处打印左边框
    printf("■");
    set_color(14);
    }

for ( i = 0; i < mapheigt; i++)
{    getxy(mapwidth-1, i);//将光标移动依次到(mapwidth i)处打印左边框
    printf("■");
    set_color(14);
}

while(1)
{
srand((unsigned int)time(NULL));       //srand函数是随机数发生器的初始化函数。原型:void srand(unsigned int seed);srand和rand()配合使用产生伪随机数序列。
food.x = rand() % (mapwidth - 4) + 2;
food.y = rand() % (mapheigt - 2) + 1;
if (food.x % 2 == 0)
break;
}
getxy(food.x,food.y);  将光标移到食物的坐标处打印食物
set_color(3);
printf("★");

snake.len = 3;   //    初始化蛇的属性
snake.speed = 200;  
snake.x[0] = mapwidth / 2 + 1;//x坐标为偶数
snake.y[0] = mapheigt / 2;                                  
getxy(snake.x[0], snake.y[0]);
set_color(4);
printf("■"); //打印蛇头

for ( i = 1; i < snake.len; i++)
{
        snake.x[i] = snake.x[i - 1] + 2;  //蛇身的打印,纵坐标不变,横坐标为上一节蛇身的坐标值+2
        snake.y[i] = snake.y[i - 1];
        getxy(snake.x[i], snake.y[i]);
        set_color(14);
        printf("■");
}
getxy(mapwidth - 2, 0);
return;
}

/*******************************************************
*
* Function name :void keyDown()
* Description   : 判断键盘是否有键按下
* Parameter         : pre_key
*        @ pre_key          获取按下的键盘值 
*        @参数名2           参数说明
*        @参数名3           参数说明
* Return          :无
*kbhit()是一个C和C++函数,用于非阻塞地响应键盘输入事件。其中文可译为“键盘敲击”(keyboard hit)。
getch()是编程中所用的函数,这个函数是一个不回显函数,当用户按下某个字符时,函数自动读取,无需按回车,有的C语言命令行程序会用到此函数做游戏,但是这个函数并非标准函数,要注意移植性!
getch()读取方向键的时候,会返回两次,第一次调用返回0或者224,第二次调用返回的才是实际值
**********************************************************/
void keyDown()
{
int pre_key=key;
    if (kbhit())//判断按下了键盘中的某个键
    {
        fflush(stdin);//清空缓冲区的字符
        key = getch();
        key = getch();
    }

if (changeFlag == 0)
    {
        getxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
        printf("  ");      //在蛇尾处输出空格即擦去蛇尾
    }
 
    for (int i = snake.len - 1; i > 0; i--)    //将蛇的每一节依次向前移动一节(蛇头除外)
    {
        snake.x[i] = snake.x[i - 1];
        snake.y[i] = snake.y[i - 1];
    }
 
    if (pre_key == 72 && key == 80)//蛇当前移动的方向不能和前一次的方向相反,比如蛇往左走的时候不能直接按右键往右走
        key = 72;
    if (pre_key == 80 && key == 72)  
        key = 80;
    if (pre_key == 75 && key == 77)    //如果当前移动方向和前一次方向相反的话,把当前移动的方向改为前一次的方向
        key = 75;
    if (pre_key == 77 && key == 75)
        key = 77;
/**
    *控制台按键所代表的数字
    *“↑”:72
    *“↓”:80
    *“←”:75
    *“→”:77
    */

    switch (key)  //判断蛇头应该往哪个方向移动
    {
    case 75:
        snake.x[0] -= 2;//往左
        break;
    case 77:
        snake.x[0] += 2;//往右
        break;
    case 72:
        snake.y[0]--;//往上
        break;
    case 80:
        snake.y[0]++;//往下
        break;
    }

getxy(snake.x[0], snake.y[0]);
    printf("■");
    set_color(9);
getxy(mapwidth- 2, 0);
    changeFlag = 0;  //由于目前没有吃到食物,changFlag值为0
    return;
}

/*******************************************************
*
* Function name :createFood() 
* Description   : 随机创造食物
* Parameter     :
*        @flag       判断蛇是否吃到食物
*        @         
* Return        :无
**********************************************************/
void createFood()
{
    if (snake.x[0] == food.x && snake.y[0] == food.y)//蛇头碰到食物
    {
    
        while (1)                 //蛇头碰到食物即为要吃掉这个食物了,因此需要再次生成一个食物
        {
            int flag = 1;
            srand((unsigned int)time(NULL));
            food.x = rand() % (mapwidth - 4) + 2;
            food.y = rand() % (mapheigt - 2) + 1;
            food.c=rand()%15;
 
            
            for (int i = 0; i < snake.len; i++)  //随机生成的食物不能在蛇的身体上
            {
                if (snake.x[i] == food.x && snake.y[i] == food.y)
                {
                    flag = 0;
                    break;
                }
            }
        
            if (flag && food.x % 2 == 0)      //随机生成的食物不能横坐标为奇数,也不能在蛇身,否则重新生成
                break;
        }
 
    
        getxy(food.x, food.y);      //绘制食物
        printf("★");
        set_color(food.c);
        snake.len++;//吃到食物,蛇身长度加1
        sorce += 10;//每个食物得10分
        snake.speed -= 5;//随着吃的食物越来越多,速度会越来越快
        changeFlag = 1;//很重要,因为吃到了食物,就不用再擦除蛇尾的那一节,以此来造成蛇身体增长的效果
    }
    return;

}

/*******************************************************
*
* Function name :snakeStatus() 
* Description   : 判断蛇致死的情况
* Parameter     :
*        @ false       bool蛇进行了违规操作 
*        @ true        bool蛇进行了违规操作
* Return        :无
**********************************************************/

bool snakeStatus()
{
    if (snake.y[0] == 0 || snake.y[0] == mapheigt) //蛇头碰到上下边界,游戏结束
        return false;
    
    if (snake.x[0] == 0 || snake.x[0] == mapwidth)//蛇头碰到左右边界,游戏结束
        return false;

    for (int i = 1; i < snake.len; i++) //蛇头碰到左右边界,游戏结束
    {
        if (snake.x[i] == snake.x[0] && snake.y[i] == snake.y[0])
            return false;
    }
    return true;
}

bool snakel()         //改写后的程序会出现蛇能闯过右边墙体不死的情况此函数进行纠正
{
if(snake.x[0]>=74)
return false;
}


/*******************************************************
*
* Function name :welcomePage( ) 
* Description   : 游戏的进入菜单
* Parameter     :
*        @ 无 
*        @ 无
* Return        :无
**********************************************************/
void welcomePage( )
{
   getxy(35,2);
    printf("欢迎来到贪吃蛇");
    set_color(1);
    getxy(15, 5);
    printf("游戏规则");
    set_color(2);
    getxy(15, 7);
    printf("1. 用↑,↓,←,→,来控制方向");
    set_color(3);
    getxy(15, 9);
    printf("2. 撞到自己蛇会死 ");
    set_color(11);
    getxy(15, 11);
    printf("3.撞到墙蛇会死 ");
    set_color(4);
    getxy(15, 13);
    printf("4.吃到食物增加积分");
    set_color(4);
    getxy(15, 15);
    printf("祝你游戏愉快");
    set_color(10);
    getxy(28, 23);
    printf("Press any key to continue...");
    getxy(0, 28);
    getchar();
    system("cls");   //system("CLS") 是在C语言程序中,调用系统命令cls完成清屏操作。
}


/*******************************************************
*
* Function name :gameEnd() 
* Description   : 游戏的结束菜单
* Parameter     :在游戏结束后用一页显示玩家的分数
*        @ 无 
*        @ 无
* Return        :无
**********************************************************/
void gameEnd()
{
    system("cls");
   getxy(32, 14);
    printf("Your final score is   %d", sorce);
    getchar();
    getxy(0, 25);
    exit(0);
}

/*******************************************************
*
* Function name :creatInterface()
* Description   : 绘制游戏旁菜单
* Parameter     :
*        @ str_title        游戏标题 
*        @ title_pos        光标起始位置
* Return        :无
**********************************************************/
void creatInterface( )
{
  
    getxy(78, 2);
    printf("Score:");
    set_color(1);
    getxy(78, 4);
    printf("Score Per Food:");
    set_color(3);
    getxy(82, 6);
    printf("介 绍");
    set_color(3);
    getxy(78,8);
    printf("↑.向上移动.");
    set_color(4);
    getxy(78,10);
    printf("↓.向下移动.");
    set_color(12);
    getxy(78,12);
    printf("←.向左移动.");
    getxy(78,14);
    printf("→.向右移动.");
    set_color(15);
    getxy(78,16);
   printf("Space\tGame pause.");
       set_color(3);
    getxy(78, 18);
    printf("ESC\tQuit the game.");
    set_color(11);
    getxy(78, 20);
    printf("@.王成军");
    set_color(15);
    
}


/*******************************************************
*
* Function name :main()
* Description   : 驱动整个程序
* Parameter     :
*        @ 无         
*        @无        
* Return        :0
Sleep函数可以使计算机程序(进程,任务或线程)进入休眠,使其在一段时间内处于非活动状态。
当函数设定的计时器到期,或者接收到信号、程序发生中断都会导致程序继续执行。

**********************************************************/
int main()
{   welcomePage();
    drawMap();
    creatInterface();
    while (1)
    {   
        keyDown();
        if (!snakeStatus())           //判死操作
            break;
        if(!snakel())                 //判死操作
            break;
        createFood();
        Sleep(snake.speed);  

        getxy(86, 2);
        printf("%d", sorce);
        getxy(94, 4);
        printf("%d ",sorce/10);
    }
  gameEnd();
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_43921974

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值